security_selinux.c 54.7 KB
Newer Older
1
/*
2
 * Copyright (C) 2008-2012 Red Hat, Inc.
3 4 5 6 7 8
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
O
Osier Yang 已提交
9 10 11 12 13 14 15 16 17
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library;  If not, see
 * <http://www.gnu.org/licenses/>.
 *
18 19
 * Authors:
 *     James Morris <jmorris@namei.org>
20
 *     Dan Walsh <dwalsh@redhat.com>
21 22 23 24 25 26 27 28 29
 *
 * SELinux security driver.
 */
#include <config.h>
#include <selinux/selinux.h>
#include <selinux/context.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
E
Eric Blake 已提交
30 31 32
#if HAVE_SELINUX_LABEL_H
# include <selinux/label.h>
#endif
33

34
#include "security_driver.h"
35 36 37 38
#include "security_selinux.h"
#include "virterror_internal.h"
#include "util.h"
#include "memory.h"
39
#include "logging.h"
40 41
#include "pci.h"
#include "hostusb.h"
42
#include "storage_file.h"
E
Eric Blake 已提交
43
#include "virfile.h"
44
#include "virhash.h"
45
#include "virrandom.h"
46 47
#include "util.h"
#include "conf.h"
D
Daniel P. Berrange 已提交
48 49 50

#define VIR_FROM_THIS VIR_FROM_SECURITY

51 52 53 54 55 56 57 58 59 60 61 62
#define MAX_CONTEXT 1024

typedef struct _virSecuritySELinuxData virSecuritySELinuxData;
typedef virSecuritySELinuxData *virSecuritySELinuxDataPtr;

typedef struct _virSecuritySELinuxCallbackData virSecuritySELinuxCallbackData;
typedef virSecuritySELinuxCallbackData *virSecuritySELinuxCallbackDataPtr;

struct _virSecuritySELinuxData {
    char *domain_context;
    char *file_context;
    char *content_context;
63
    virHashTablePtr mcs;
64 65 66 67 68 69 70
};

struct _virSecuritySELinuxCallbackData {
    virSecurityManagerPtr manager;
    virSecurityLabelDefPtr secdef;
};

71 72 73
#define SECURITY_SELINUX_VOID_DOI       "0"
#define SECURITY_SELINUX_NAME "selinux"

74 75 76
/*
 * Returns 0 on success, 1 if already reserved, or -1 on fatal error
 */
77
static int
78 79
virSecuritySELinuxMCSAdd(virSecurityManagerPtr mgr,
                         const char *mcs)
80
{
81
    virSecuritySELinuxDataPtr data = virSecurityManagerGetPrivateData(mgr);
82

83 84 85 86
    if (virHashLookup(data->mcs, mcs))
        return 1;

    if (virHashAddEntry(data->mcs, mcs, (void*)0x1) < 0)
87
        return -1;
88

89 90 91
    return 0;
}

92 93 94
static void
virSecuritySELinuxMCSRemove(virSecurityManagerPtr mgr,
                            const char *mcs)
95
{
96 97 98
    virSecuritySELinuxDataPtr data = virSecurityManagerGetPrivateData(mgr);

    virHashRemoveEntry(data->mcs, mcs);
99 100
}

101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142

static char *
virSecuritySELinuxMCSFind(virSecurityManagerPtr mgr)
{
    virSecuritySELinuxDataPtr data = virSecurityManagerGetPrivateData(mgr);
    int c1 = 0;
    int c2 = 0;
    char *mcs = NULL;

    for (;;) {
        c1 = virRandomBits(10);
        c2 = virRandomBits(10);

        if (c1 == c2) {
            if (virAsprintf(&mcs, "s0:c%d", c1) < 0) {
                virReportOOMError();
                return NULL;
            }
        } else {
            if (c1 > c2) {
                int t = c1;
                c1 = c2;
                c2 = t;
            }
            if (virAsprintf(&mcs, "s0:c%d,c%d", c1, c2) < 0) {
                virReportOOMError();
                return NULL;
            }
        }

        if (virHashLookup(data->mcs, mcs) == NULL)
            goto cleanup;

        VIR_FREE(mcs);
    }

cleanup:
    VIR_DEBUG("Found context '%s'", NULLSTR(mcs));
    return mcs;
}


143
static char *
144 145 146
virSecuritySELinuxGenNewContext(const char *basecontext,
                                const char *mcs,
                                bool isObjectContext)
147
{
148
    context_t context = NULL;
149 150
    char *ret = NULL;
    char *str;
151 152 153 154 155 156 157 158 159 160 161 162 163 164
    security_context_t ourSecContext = NULL;
    context_t ourContext = NULL;

    if (getcon(&ourSecContext) < 0) {
        virReportSystemError(errno, "%s",
                             _("Unable to get current process SELinux context"));
        goto cleanup;
    }
    if (!(ourContext = context_new(ourSecContext))) {
        virReportSystemError(errno,
                             _("Unable to parse current SELinux context '%s'"),
                             ourSecContext);
        goto cleanup;
    }
165 166 167 168 169 170 171 172

    if (!(context = context_new(basecontext))) {
        virReportSystemError(errno,
                             _("Unable to parse base SELinux context '%s'"),
                             basecontext);
        goto cleanup;
    }

173 174 175 176 177 178 179 180
    if (context_user_set(context,
                         context_user_get(ourContext)) != 0) {
        virReportSystemError(errno,
                             _("Unable to set SELinux context user '%s'"),
                             context_user_get(ourContext));
        goto cleanup;
    }

181 182
    if (!isObjectContext &&
        context_role_set(context,
183 184
                         context_role_get(ourContext)) != 0) {
        virReportSystemError(errno,
185
                             _("Unable to set SELinux context role '%s'"),
186 187 188 189
                             context_role_get(ourContext));
        goto cleanup;
    }

190 191 192 193 194 195 196 197 198 199 200 201 202 203 204
    if (context_range_set(context, mcs) != 0) {
        virReportSystemError(errno,
                             _("Unable to set SELinux context MCS '%s'"),
                             mcs);
        goto cleanup;
    }
    if (!(str = context_str(context))) {
        virReportSystemError(errno, "%s",
                             _("Unable to format SELinux context"));
        goto cleanup;
    }
    if (!(ret = strdup(str))) {
        virReportOOMError();
        goto cleanup;
    }
205 206
    VIR_DEBUG("Generated context '%s' from '%s' and '%s'",
              ret, basecontext, ourSecContext);
207
cleanup:
208 209
    freecon(ourSecContext);
    context_free(ourContext);
210 211
    context_free(context);
    return ret;
212 213
}

214

215
#ifdef HAVE_SELINUX_LXC_CONTEXTS_PATH
216
static int
217
virSecuritySELinuxLXCInitialize(virSecurityManagerPtr mgr)
218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267
{
    virConfValuePtr scon = NULL;
    virConfValuePtr tcon = NULL;
    virConfValuePtr dcon = NULL;
    virConfPtr selinux_conf;
    virSecuritySELinuxDataPtr data = virSecurityManagerGetPrivateData(mgr);

    selinux_conf = virConfReadFile(selinux_lxc_contexts_path(), 0);
    if (!selinux_conf) {
        virReportSystemError(errno,
                             _("cannot open SELinux lxc contexts file '%s'"),
                             selinux_lxc_contexts_path());
        return -1;
    }

    scon = virConfGetValue(selinux_conf, "process");
    if (! scon || scon->type != VIR_CONF_STRING || (! scon->str)) {
        virReportSystemError(errno,
                             _("cannot read 'process' value from selinux lxc contexts file '%s'"),
                             selinux_lxc_contexts_path());
        goto error;
    }

    tcon = virConfGetValue(selinux_conf, "file");
    if (! tcon || tcon->type != VIR_CONF_STRING || (! tcon->str)) {
        virReportSystemError(errno,
                             _("cannot read 'file' value from selinux lxc contexts file '%s'"),
                             selinux_lxc_contexts_path());
        goto error;
    }

    dcon = virConfGetValue(selinux_conf, "content");
    if (! dcon || dcon->type != VIR_CONF_STRING || (! dcon->str)) {
        virReportSystemError(errno,
                             _("cannot read 'file' value from selinux lxc contexts file '%s'"),
                             selinux_lxc_contexts_path());
        goto error;
    }

    data->domain_context = strdup(scon->str);
    data->file_context = strdup(tcon->str);
    data->content_context = strdup(dcon->str);
    if (!data->domain_context ||
        !data->file_context ||
        !data->content_context) {
        virReportSystemError(errno,
                             _("cannot allocate memory for LXC SELinux contexts '%s'"),
                             selinux_lxc_contexts_path());
        goto error;
    }
268 269 270 271

    if (!(data->mcs = virHashCreate(10, NULL)))
        goto error;

272 273 274 275 276 277 278 279
    virConfFree(selinux_conf);
    return 0;

error:
    virConfFree(selinux_conf);
    VIR_FREE(data->domain_context);
    VIR_FREE(data->file_context);
    VIR_FREE(data->content_context);
280
    virHashFree(data->mcs);
281 282
    return -1;
}
283 284
#else
static int
285
virSecuritySELinuxLXCInitialize(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED)
286 287 288 289 290 291
{
    virReportSystemError(ENOSYS, "%s",
                         _("libselinux does not support LXC contexts path"));
    return -1;
}
#endif
292 293 294


static int
295
virSecuritySELinuxQEMUInitialize(virSecurityManagerPtr mgr)
296
{
297 298
    char *ptr;
    virSecuritySELinuxDataPtr data = virSecurityManagerGetPrivateData(mgr);
299

300
    if (virFileReadAll(selinux_virtual_domain_context_path(), MAX_CONTEXT, &(data->domain_context)) < 0) {
301
        virReportSystemError(errno,
302
                             _("cannot read SELinux virtual domain context file '%s'"),
303
                             selinux_virtual_domain_context_path());
304
        goto error;
305 306
    }

307 308 309
    ptr = strchrnul(data->domain_context, '\n');
    if (ptr)
        *ptr = '\0';
310

311
    if (virFileReadAll(selinux_virtual_image_context_path(), 2*MAX_CONTEXT, &(data->file_context)) < 0) {
312
        virReportSystemError(errno,
313 314
                             _("cannot read SELinux virtual image context file %s"),
                             selinux_virtual_image_context_path());
315
        goto error;
316 317
    }

318 319
    ptr = strchrnul(data->file_context, '\n');
    if (ptr && *ptr == '\n') {
320
        *ptr = '\0';
321 322 323 324 325 326 327
        data->content_context = strdup(ptr+1);
        if (!data->content_context) {
            virReportOOMError();
            goto error;
        }
        ptr = strchrnul(data->content_context, '\n');
        if (ptr && *ptr == '\n')
328 329
            *ptr = '\0';
    }
330

331 332 333
    if (!(data->mcs = virHashCreate(10, NULL)))
        goto error;

334
    return 0;
335 336 337 338 339

error:
    VIR_FREE(data->domain_context);
    VIR_FREE(data->file_context);
    VIR_FREE(data->content_context);
340
    virHashFree(data->mcs);
341
    return -1;
342 343
}

344 345

static int
346
virSecuritySELinuxInitialize(virSecurityManagerPtr mgr)
347 348 349
{
    VIR_DEBUG("SELinuxInitialize %s", virSecurityManagerGetDriver(mgr));
    if (STREQ(virSecurityManagerGetDriver(mgr),  "LXC")) {
350
        return virSecuritySELinuxLXCInitialize(mgr);
351
    } else {
352
        return virSecuritySELinuxQEMUInitialize(mgr);
353 354 355 356
    }
}


357
static int
358 359
virSecuritySELinuxGenSecurityLabel(virSecurityManagerPtr mgr,
                                   virDomainDefPtr def)
360 361
{
    int rc = -1;
362
    char *mcs = NULL;
363
    char *scontext = NULL;
364
    context_t ctx = NULL;
365
    const char *range;
366 367
    virSecurityLabelDefPtr seclabel;
    virSecuritySELinuxDataPtr data;
368

369
    if (mgr == NULL) {
370
        virReportError(VIR_ERR_INTERNAL_ERROR,
371
                       "%s", _("invalid security driver"));
372 373 374
        return rc;
    }

375 376 377 378 379 380 381 382 383 384
    seclabel = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
    if (seclabel == NULL) {
        return rc;
    }

    data = virSecurityManagerGetPrivateData(mgr);

    VIR_DEBUG("label=%s", virSecurityManagerGetDriver(mgr));
    if (seclabel->type == VIR_DOMAIN_SECLABEL_DYNAMIC &&
        seclabel->label) {
385 386
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("security label already defined for VM"));
387
        return rc;
D
Daniel P. Berrange 已提交
388
    }
389

390
    if (seclabel->imagelabel) {
391 392
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("security image label already defined for VM"));
393 394 395
        return rc;
    }

396 397
    if (seclabel->model &&
        STRNEQ(seclabel->model, SECURITY_SELINUX_NAME)) {
398 399
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("security label model %s is not supported with selinux"),
400
                       seclabel->model);
401 402 403
        return rc;
    }

404
    VIR_DEBUG("type=%d", seclabel->type);
405

406
    switch (seclabel->type) {
407
    case VIR_DOMAIN_SECLABEL_STATIC:
408
        if (!(ctx = context_new(seclabel->label)) ) {
409 410
            virReportSystemError(errno,
                                 _("unable to allocate socket security context '%s'"),
411
                                 seclabel->label);
412
            return rc;
413 414
        }

415
        range = context_range_get(ctx);
416 417 418 419 420
        if (!range ||
            !(mcs = strdup(range))) {
            virReportOOMError();
            goto cleanup;
        }
421 422 423
        break;

    case VIR_DOMAIN_SECLABEL_DYNAMIC:
424 425 426 427 428
        if (!(mcs = virSecuritySELinuxMCSFind(mgr)))
            goto cleanup;

        if (virSecuritySELinuxMCSAdd(mgr, mcs) < 0)
            goto cleanup;
429

430 431 432 433 434
        seclabel->label =
            virSecuritySELinuxGenNewContext(seclabel->baselabel ?
                                 seclabel->baselabel :
                                 data->domain_context, mcs, false);
        if (!seclabel->label)  {
435 436
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("cannot generate selinux context for %s"), mcs);
437
            goto cleanup;
438
        }
439 440 441 442 443 444 445
        break;

    case VIR_DOMAIN_SECLABEL_NONE:
        /* no op */
        break;

    default:
446 447
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected security label type '%s'"),
448
                       virDomainSeclabelTypeToString(seclabel->type));
449
        goto cleanup;
D
Daniel P. Berrange 已提交
450
    }
451

452 453 454 455 456
    if (!seclabel->norelabel) {
        seclabel->imagelabel = virSecuritySELinuxGenNewContext(data->domain_context,
                                                               mcs,
                                                               true);
        if (!seclabel->imagelabel)  {
457 458
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("cannot generate selinux context for %s"), mcs);
459
            goto cleanup;
460
        }
461 462
    }

463 464
    if (!seclabel->model &&
        !(seclabel->model = strdup(SECURITY_SELINUX_NAME))) {
465
        virReportOOMError();
466
        goto cleanup;
D
Daniel P. Berrange 已提交
467 468
    }

469
    rc = 0;
470 471 472

cleanup:
    if (rc != 0) {
473 474 475 476 477 478
        if (seclabel->type == VIR_DOMAIN_SECLABEL_DYNAMIC)
            VIR_FREE(seclabel->label);
        VIR_FREE(seclabel->imagelabel);
        if (seclabel->type == VIR_DOMAIN_SECLABEL_DYNAMIC &&
            !seclabel->baselabel)
            VIR_FREE(seclabel->model);
479 480 481 482
    }

    if (ctx)
        context_free(ctx);
D
Daniel P. Berrange 已提交
483
    VIR_FREE(scontext);
484 485 486
    VIR_FREE(mcs);

    VIR_DEBUG("model=%s label=%s imagelabel=%s baselabel=%s",
487 488 489 490
              NULLSTR(seclabel->model),
              NULLSTR(seclabel->label),
              NULLSTR(seclabel->imagelabel),
              NULLSTR(seclabel->baselabel));
491

492 493 494
    return rc;
}

495
static int
496
virSecuritySELinuxReserveSecurityLabel(virSecurityManagerPtr mgr,
497 498
                                       virDomainDefPtr def,
                                       pid_t pid)
499 500 501 502
{
    security_context_t pctx;
    context_t ctx = NULL;
    const char *mcs;
503
    int rv;
504
    virSecurityLabelDefPtr seclabel;
505

506 507 508 509 510 511
    seclabel = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
    if (seclabel == NULL) {
        return -1;
    }

    if (seclabel->type == VIR_DOMAIN_SECLABEL_STATIC)
512 513
        return 0;

514
    if (getpidcon(pid, &pctx) == -1) {
515
        virReportSystemError(errno,
516
                             _("unable to get PID %d security context"), pid);
517 518 519 520
        return -1;
    }

    ctx = context_new(pctx);
521
    freecon(pctx);
522
    if (!ctx)
523
        goto error;
524 525 526

    mcs = context_range_get(ctx);
    if (!mcs)
527 528
        goto error;

529
    if ((rv = virSecuritySELinuxMCSAdd(mgr, mcs)) < 0)
530
        goto error;
531

532 533 534 535 536 537
    if (rv == 1) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("MCS level for existing domain label %s already reserved"),
                       (char*)pctx);
        goto error;
    }
538 539 540 541 542

    context_free(ctx);

    return 0;

543
error:
544 545 546 547 548
    context_free(ctx);
    return -1;
}


549
static int
550
virSecuritySELinuxSecurityDriverProbe(const char *virtDriver)
551
{
552 553 554
    if (!is_selinux_enabled())
        return SECURITY_DRIVER_DISABLE;

555 556 557 558 559 560
    if (virtDriver && STREQ(virtDriver, "LXC")) {
#if HAVE_SELINUX_LXC_CONTEXTS_PATH
        if (!virFileExists(selinux_lxc_contexts_path()))
#endif
            return SECURITY_DRIVER_DISABLE;
    }
561 562

    return SECURITY_DRIVER_ENABLE;
563 564
}

565

566
static int
567
virSecuritySELinuxSecurityDriverOpen(virSecurityManagerPtr mgr)
568
{
569
    return virSecuritySELinuxInitialize(mgr);
570 571
}

572

573
static int
574
virSecuritySELinuxSecurityDriverClose(virSecurityManagerPtr mgr)
575
{
576 577 578 579 580
    virSecuritySELinuxDataPtr data = virSecurityManagerGetPrivateData(mgr);

    if (!data)
        return 0;

581 582
    virHashFree(data->mcs);

583 584 585 586
    VIR_FREE(data->domain_context);
    VIR_FREE(data->file_context);
    VIR_FREE(data->content_context);

587 588 589 590
    return 0;
}


591 592
static const char *
virSecuritySELinuxSecurityGetModel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED)
593 594 595 596
{
    return SECURITY_SELINUX_NAME;
}

597 598
static const char *
virSecuritySELinuxSecurityGetDOI(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED)
599 600 601 602 603
{
    /*
     * Where will the DOI come from?  SELinux configuration, or qemu
     * configuration? For the moment, we'll just set it to "0".
     */
604
    return SECURITY_SELINUX_VOID_DOI;
605 606 607
}

static int
608 609 610 611
virSecuritySELinuxGetSecurityProcessLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
                                          virDomainDefPtr def ATTRIBUTE_UNUSED,
                                          pid_t pid,
                                          virSecurityLabelPtr sec)
612 613 614
{
    security_context_t ctx;

615
    if (getpidcon(pid, &ctx) == -1) {
616
        virReportSystemError(errno,
617
                             _("unable to get PID %d security context"),
618
                             pid);
619 620 621 622
        return -1;
    }

    if (strlen((char *) ctx) >= VIR_SECURITY_LABEL_BUFLEN) {
623 624 625 626
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("security label exceeds "
                         "maximum length: %d"),
                       VIR_SECURITY_LABEL_BUFLEN - 1);
627
        freecon(ctx);
628 629 630 631
        return -1;
    }

    strcpy(sec->label, (char *) ctx);
632
    freecon(ctx);
633

634
    VIR_DEBUG("label=%s", sec->label);
635 636
    sec->enforcing = security_getenforce();
    if (sec->enforcing == -1) {
637
        virReportSystemError(errno, "%s",
638
                             _("error calling security_getenforce()"));
639 640 641 642 643 644
        return -1;
    }

    return 0;
}

645 646 647
/* Attempt to change the label of PATH to TCON.  If OPTIONAL is true,
 * return 1 if labelling was not possible.  Otherwise, require a label
 * change, and return 0 for success, -1 for failure.  */
648
static int
649
virSecuritySELinuxSetFileconHelper(const char *path, char *tcon, bool optional)
650
{
651
    security_context_t econ;
652

653 654
    VIR_INFO("Setting SELinux context on '%s' to '%s'", path, tcon);

655
    if (setfilecon(path, tcon) < 0) {
656 657
        int setfilecon_errno = errno;

658 659 660 661
        if (getfilecon(path, &econ) >= 0) {
            if (STREQ(tcon, econ)) {
                freecon(econ);
                /* It's alright, there's nothing to change anyway. */
662
                return optional ? 1 : 0;
663 664 665
            }
            freecon(econ);
        }
666 667

        /* if the error complaint is related to an image hosted on
668 669
         * an nfs mount, or a usbfs/sysfs filesystem not supporting
         * labelling, then just ignore it & hope for the best.
670
         * The user hopefully set one of the necessary SELinux
671
         * virt_use_{nfs,usb,pci}  boolean tunables to allow it...
672
         */
673
        if (setfilecon_errno != EOPNOTSUPP && setfilecon_errno != ENOTSUP) {
674
            virReportSystemError(setfilecon_errno,
675
                                 _("unable to set security context '%s' on '%s'"),
676
                                 tcon, path);
677 678
            if (security_getenforce() == 1)
                return -1;
679
        } else {
680 681 682 683 684 685 686 687 688 689 690 691 692 693
            const char *msg;
            if ((virStorageFileIsSharedFSType(path,
                                              VIR_STORAGE_FILE_SHFS_NFS) == 1) &&
                security_get_boolean_active("virt_use_nfs") != 1) {
                msg = _("Setting security context '%s' on '%s' not supported. "
                        "Consider setting virt_use_nfs");
               if (security_getenforce() == 1)
                   VIR_WARN(msg, tcon, path);
               else
                   VIR_INFO(msg, tcon, path);
            } else {
                VIR_INFO("Setting security context '%s' on '%s' not supported",
                         tcon, path);
            }
694 695
            if (optional)
                return 1;
696
        }
697 698 699 700
    }
    return 0;
}

701
static int
702
virSecuritySELinuxSetFileconOptional(const char *path, char *tcon)
703
{
704
    return virSecuritySELinuxSetFileconHelper(path, tcon, true);
705 706 707
}

static int
708
virSecuritySELinuxSetFilecon(const char *path, char *tcon)
709
{
710
    return virSecuritySELinuxSetFileconHelper(path, tcon, false);
711 712
}

713
static int
714
virSecuritySELinuxFSetFilecon(int fd, char *tcon)
715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751
{
    security_context_t econ;

    VIR_INFO("Setting SELinux context on fd %d to '%s'", fd, tcon);

    if (fsetfilecon(fd, tcon) < 0) {
        int fsetfilecon_errno = errno;

        if (fgetfilecon(fd, &econ) >= 0) {
            if (STREQ(tcon, econ)) {
                freecon(econ);
                /* It's alright, there's nothing to change anyway. */
                return 0;
            }
            freecon(econ);
        }

        /* if the error complaint is related to an image hosted on
         * an nfs mount, or a usbfs/sysfs filesystem not supporting
         * labelling, then just ignore it & hope for the best.
         * The user hopefully set one of the necessary SELinux
         * virt_use_{nfs,usb,pci}  boolean tunables to allow it...
         */
        if (fsetfilecon_errno != EOPNOTSUPP) {
            virReportSystemError(fsetfilecon_errno,
                                 _("unable to set security context '%s' on fd %d"),
                                 tcon, fd);
            if (security_getenforce() == 1)
                return -1;
        } else {
            VIR_INFO("Setting security context '%s' on fd %d not supported",
                     tcon, fd);
        }
    }
    return 0;
}

E
Eric Blake 已提交
752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770
/* Set fcon to the appropriate label for path and mode, or return -1.  */
static int
getContext(const char *newpath, mode_t mode, security_context_t *fcon)
{
#if HAVE_SELINUX_LABEL_H
    struct selabel_handle *handle = selabel_open(SELABEL_CTX_FILE, NULL, 0);
    int ret;

    if (handle == NULL)
        return -1;

    ret = selabel_lookup(handle, fcon, newpath, mode);
    selabel_close(handle);
    return ret;
#else
    return matchpathcon(newpath, mode, fcon);
#endif
}

771 772 773

/* This method shouldn't raise errors, since they'll overwrite
 * errors that the caller(s) are already dealing with */
774
static int
775
virSecuritySELinuxRestoreSecurityFileLabel(const char *path)
776
{
777 778 779 780
    struct stat buf;
    security_context_t fcon = NULL;
    int rc = -1;
    char *newpath = NULL;
781
    char ebuf[1024];
782

783 784
    VIR_INFO("Restoring SELinux context on '%s'", path);

785
    if (virFileResolveLink(path, &newpath) < 0) {
786 787
        VIR_WARN("cannot resolve symlink %s: %s", path,
                 virStrerror(errno, ebuf, sizeof(ebuf)));
D
Daniel P. Berrange 已提交
788
        goto err;
789
    }
790

791
    if (stat(newpath, &buf) != 0) {
792 793
        VIR_WARN("cannot stat %s: %s", newpath,
                 virStrerror(errno, ebuf, sizeof(ebuf)));
D
Daniel P. Berrange 已提交
794
        goto err;
795
    }
D
Daniel P. Berrange 已提交
796

E
Eric Blake 已提交
797
    if (getContext(newpath, buf.st_mode, &fcon) < 0) {
798
        VIR_WARN("cannot lookup default selinux label for %s", newpath);
799
    } else {
800
        rc = virSecuritySELinuxSetFilecon(newpath, fcon);
801
    }
802

803
err:
804
    freecon(fcon);
805 806
    VIR_FREE(newpath);
    return rc;
807 808
}

809
static int
810 811 812 813
virSecuritySELinuxRestoreSecurityImageLabelInt(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
                                               virDomainDefPtr def,
                                               virDomainDiskDefPtr disk,
                                               int migrated)
814
{
815 816 817 818 819 820
    virSecurityLabelDefPtr seclabel;
    virSecurityDeviceLabelDefPtr disk_seclabel;

    seclabel = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
    if (seclabel == NULL)
        return -1;
821

822 823 824
    disk_seclabel = virDomainDiskDefGetSecurityLabelDef(disk,
                                                        SECURITY_SELINUX_NAME);
    if (seclabel->norelabel || (disk_seclabel && disk_seclabel->norelabel))
825 826
        return 0;

827 828 829 830 831 832 833 834 835 836 837
    /* Don't restore labels on readoly/shared disks, because
     * other VMs may still be accessing these
     * Alternatively we could iterate over all running
     * domains and try to figure out if it is in use, but
     * this would not work for clustered filesystems, since
     * we can't see running VMs using the file on other nodes
     * Safest bet is thus to skip the restore step.
     */
    if (disk->readonly || disk->shared)
        return 0;

838
    if (!disk->src || disk->type == VIR_DOMAIN_DISK_TYPE_NETWORK)
839 840
        return 0;

841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856
    /* If we have a shared FS & doing migrated, we must not
     * change ownership, because that kills access on the
     * destination host which is sub-optimal for the guest
     * VM's I/O attempts :-)
     */
    if (migrated) {
        int rc = virStorageFileIsSharedFS(disk->src);
        if (rc < 0)
            return -1;
        if (rc == 1) {
            VIR_DEBUG("Skipping image label restore on %s because FS is shared",
                      disk->src);
            return 0;
        }
    }

857
    return virSecuritySELinuxRestoreSecurityFileLabel(disk->src);
858 859
}

860 861

static int
862 863 864
virSecuritySELinuxRestoreSecurityImageLabel(virSecurityManagerPtr mgr,
                                            virDomainDefPtr def,
                                            virDomainDiskDefPtr disk)
865
{
866
    return virSecuritySELinuxRestoreSecurityImageLabelInt(mgr, def, disk, 0);
867 868 869
}


870
static int
871 872 873 874
virSecuritySELinuxSetSecurityFileLabel(virDomainDiskDefPtr disk,
                                       const char *path,
                                       size_t depth,
                                       void *opaque)
875
{
876 877
    int ret;
    virSecurityDeviceLabelDefPtr disk_seclabel;
878 879 880
    virSecuritySELinuxCallbackDataPtr cbdata = opaque;
    const virSecurityLabelDefPtr secdef = cbdata->secdef;
    virSecuritySELinuxDataPtr data = virSecurityManagerGetPrivateData(cbdata->manager);
881

882 883 884 885
    disk_seclabel = virDomainDiskDefGetSecurityLabelDef(disk,
                                                        SECURITY_SELINUX_NAME);

    if (disk_seclabel && disk_seclabel->norelabel)
886 887
        return 0;

888 889 890
    if (disk_seclabel && !disk_seclabel->norelabel &&
        disk_seclabel->label) {
        ret = virSecuritySELinuxSetFilecon(path, disk_seclabel->label);
891
    } else if (depth == 0) {
892

893
        if (disk->shared) {
894
            ret = virSecuritySELinuxSetFileconOptional(path, data->file_context);
895
        } else if (disk->readonly) {
896
            ret = virSecuritySELinuxSetFileconOptional(path, data->content_context);
897
        } else if (secdef->imagelabel) {
898
            ret = virSecuritySELinuxSetFileconOptional(path, secdef->imagelabel);
899
        } else {
900
            ret = 0;
901 902
        }
    } else {
903
        ret = virSecuritySELinuxSetFileconOptional(path, data->content_context);
904
    }
905
    if (ret == 1 && !disk_seclabel) {
906 907
        /* If we failed to set a label, but virt_use_nfs let us
         * proceed anyway, then we don't need to relabel later.  */
908
        if (VIR_ALLOC(disk_seclabel) < 0) {
909 910 911
            virReportOOMError();
            return -1;
        }
912
        disk_seclabel->norelabel = true;
913
        ret = 0;
914
    }
915
    return ret;
916 917
}

918
static int
919 920 921
virSecuritySELinuxSetSecurityImageLabel(virSecurityManagerPtr mgr,
                                        virDomainDefPtr def,
                                        virDomainDiskDefPtr disk)
922 923

{
924
    bool allowDiskFormatProbing;
925 926
    virSecuritySELinuxCallbackData cbdata;
    cbdata.manager = mgr;
927
    cbdata.secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
928

929 930 931 932
    allowDiskFormatProbing = virSecurityManagerGetAllowDiskFormatProbing(mgr);

    if (cbdata.secdef == NULL)
        return -1;
933

934
    if (cbdata.secdef->norelabel)
935 936
        return 0;

937 938 939
    if (disk->type == VIR_DOMAIN_DISK_TYPE_NETWORK)
        return 0;

940 941 942 943 944 945
    /* XXX On one hand, it would be nice to have the driver's uid:gid
     * here so we could retry opens with it. On the other hand, it
     * probably doesn't matter because in practice that's only useful
     * for files on root-squashed NFS shares, and NFS doesn't properly
     * support selinux anyway.
     */
946
    return virDomainDiskDefForeachPath(disk,
947
                                       allowDiskFormatProbing,
948
                                       true,
949
                                       -1, -1, /* current process uid:gid */
950
                                       virSecuritySELinuxSetSecurityFileLabel,
951
                                       &cbdata);
952 953
}

954 955

static int
956 957
virSecuritySELinuxSetSecurityPCILabel(pciDevice *dev ATTRIBUTE_UNUSED,
                                      const char *file, void *opaque)
958
{
959
    virSecurityLabelDefPtr secdef;
960
    virDomainDefPtr def = opaque;
961

962 963 964
    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
    if (secdef == NULL)
        return -1;
965
    return virSecuritySELinuxSetFilecon(file, secdef->imagelabel);
966 967 968
}

static int
969 970
virSecuritySELinuxSetSecurityUSBLabel(usbDevice *dev ATTRIBUTE_UNUSED,
                                      const char *file, void *opaque)
971
{
972
    virSecurityLabelDefPtr secdef;
973
    virDomainDefPtr def = opaque;
974 975 976 977

    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
    if (secdef == NULL)
        return -1;
978

979
    return virSecuritySELinuxSetFilecon(file, secdef->imagelabel);
980 981 982
}

static int
983 984 985
virSecuritySELinuxSetSecurityHostdevLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
                                          virDomainDefPtr def,
                                          virDomainHostdevDefPtr dev)
986 987

{
988
    virSecurityLabelDefPtr secdef;
989 990
    int ret = -1;

991 992 993 994
    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
    if (secdef == NULL)
        return -1;

995
    if (secdef->norelabel)
996 997
        return 0;

998 999 1000 1001 1002
    if (dev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
        return 0;

    switch (dev->source.subsys.type) {
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB: {
1003
        usbDevice *usb = usbGetDevice(dev->source.subsys.u.usb.bus,
1004
                                      dev->source.subsys.u.usb.device);
1005

1006 1007
        if (!usb)
            goto done;
1008

1009
        ret = usbDeviceFileIterate(usb, virSecuritySELinuxSetSecurityUSBLabel, def);
1010
        usbFreeDevice(usb);
M
Mark McLoughlin 已提交
1011
        break;
1012 1013 1014
    }

    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI: {
1015
        pciDevice *pci = pciGetDevice(dev->source.subsys.u.pci.domain,
1016 1017 1018 1019 1020 1021 1022
                                      dev->source.subsys.u.pci.bus,
                                      dev->source.subsys.u.pci.slot,
                                      dev->source.subsys.u.pci.function);

        if (!pci)
            goto done;

1023
        ret = pciDeviceFileIterate(pci, virSecuritySELinuxSetSecurityPCILabel, def);
1024
        pciFreeDevice(pci);
1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037

        break;
    }

    default:
        ret = 0;
        break;
    }

done:
    return ret;
}

1038

1039
static int
1040 1041 1042
virSecuritySELinuxRestoreSecurityPCILabel(pciDevice *dev ATTRIBUTE_UNUSED,
                                          const char *file,
                                          void *opaque ATTRIBUTE_UNUSED)
1043
{
1044
    return virSecuritySELinuxRestoreSecurityFileLabel(file);
1045 1046 1047
}

static int
1048 1049 1050
virSecuritySELinuxRestoreSecurityUSBLabel(usbDevice *dev ATTRIBUTE_UNUSED,
                                          const char *file,
                                          void *opaque ATTRIBUTE_UNUSED)
1051
{
1052
    return virSecuritySELinuxRestoreSecurityFileLabel(file);
1053 1054 1055
}

static int
1056 1057 1058
virSecuritySELinuxRestoreSecurityHostdevLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
                                              virDomainDefPtr def,
                                              virDomainHostdevDefPtr dev)
1059 1060

{
1061
    virSecurityLabelDefPtr secdef;
1062 1063
    int ret = -1;

1064 1065 1066 1067
    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
    if (secdef == NULL)
        return -1;

1068
    if (secdef->norelabel)
1069 1070
        return 0;

1071 1072 1073 1074 1075
    if (dev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
        return 0;

    switch (dev->source.subsys.type) {
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB: {
1076
        usbDevice *usb = usbGetDevice(dev->source.subsys.u.usb.bus,
1077
                                      dev->source.subsys.u.usb.device);
1078 1079 1080 1081

        if (!usb)
            goto done;

1082
        ret = usbDeviceFileIterate(usb, virSecuritySELinuxRestoreSecurityUSBLabel, NULL);
1083
        usbFreeDevice(usb);
1084 1085 1086 1087 1088

        break;
    }

    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI: {
1089
        pciDevice *pci = pciGetDevice(dev->source.subsys.u.pci.domain,
1090 1091 1092 1093 1094 1095 1096
                                      dev->source.subsys.u.pci.bus,
                                      dev->source.subsys.u.pci.slot,
                                      dev->source.subsys.u.pci.function);

        if (!pci)
            goto done;

1097
        ret = pciDeviceFileIterate(pci, virSecuritySELinuxRestoreSecurityPCILabel, NULL);
1098
        pciFreeDevice(pci);
1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111

        break;
    }

    default:
        ret = 0;
        break;
    }

done:
    return ret;
}

1112 1113

static int
1114 1115
virSecuritySELinuxSetSecurityChardevLabel(virDomainDefPtr def,
                                          virDomainChrSourceDefPtr dev)
1116 1117

{
1118
    virSecurityLabelDefPtr secdef;
1119 1120 1121
    char *in = NULL, *out = NULL;
    int ret = -1;

1122 1123 1124 1125
    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
    if (secdef == NULL)
        return -1;

1126
    if (secdef->norelabel)
1127 1128 1129 1130 1131
        return 0;

    switch (dev->type) {
    case VIR_DOMAIN_CHR_TYPE_DEV:
    case VIR_DOMAIN_CHR_TYPE_FILE:
1132
        ret = virSecuritySELinuxSetFilecon(dev->data.file.path, secdef->imagelabel);
1133 1134 1135
        break;

    case VIR_DOMAIN_CHR_TYPE_PIPE:
1136 1137 1138 1139 1140 1141
        if ((virAsprintf(&in, "%s.in", dev->data.file.path) < 0) ||
            (virAsprintf(&out, "%s.out", dev->data.file.path) < 0)) {
            virReportOOMError();
            goto done;
        }
        if (virFileExists(in) && virFileExists(out)) {
1142 1143
            if ((virSecuritySELinuxSetFilecon(in, secdef->imagelabel) < 0) ||
                (virSecuritySELinuxSetFilecon(out, secdef->imagelabel) < 0)) {
1144
                goto done;
1145
            }
1146
        } else if (virSecuritySELinuxSetFilecon(dev->data.file.path, secdef->imagelabel) < 0) {
1147
            goto done;
1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163
        }
        ret = 0;
        break;

    default:
        ret = 0;
        break;
    }

done:
    VIR_FREE(in);
    VIR_FREE(out);
    return ret;
}

static int
1164 1165
virSecuritySELinuxRestoreSecurityChardevLabel(virDomainDefPtr def,
                                              virDomainChrSourceDefPtr dev)
1166 1167

{
1168
    virSecurityLabelDefPtr secdef;
1169 1170 1171
    char *in = NULL, *out = NULL;
    int ret = -1;

1172 1173 1174 1175
    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
    if (secdef == NULL)
        return -1;

1176
    if (secdef->norelabel)
1177 1178 1179 1180 1181
        return 0;

    switch (dev->type) {
    case VIR_DOMAIN_CHR_TYPE_DEV:
    case VIR_DOMAIN_CHR_TYPE_FILE:
1182
        if (virSecuritySELinuxRestoreSecurityFileLabel(dev->data.file.path) < 0)
1183 1184
            goto done;
        ret = 0;
1185 1186 1187 1188 1189 1190 1191
        break;
    case VIR_DOMAIN_CHR_TYPE_PIPE:
        if ((virAsprintf(&out, "%s.out", dev->data.file.path) < 0) ||
            (virAsprintf(&in, "%s.in", dev->data.file.path) < 0)) {
            virReportOOMError();
            goto done;
        }
1192
        if (virFileExists(in) && virFileExists(out)) {
1193 1194
            if ((virSecuritySELinuxRestoreSecurityFileLabel(out) < 0) ||
                (virSecuritySELinuxRestoreSecurityFileLabel(in) < 0)) {
1195 1196
                goto done;
            }
1197
        } else if (virSecuritySELinuxRestoreSecurityFileLabel(dev->data.file.path) < 0) {
1198
            goto done;
1199
        }
1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215
        ret = 0;
        break;

    default:
        ret = 0;
        break;
    }

done:
    VIR_FREE(in);
    VIR_FREE(out);
    return ret;
}


static int
1216 1217 1218
virSecuritySELinuxRestoreSecurityChardevCallback(virDomainDefPtr def,
                                                 virDomainChrDefPtr dev,
                                                 void *opaque ATTRIBUTE_UNUSED)
1219
{
1220 1221 1222 1223 1224
    /* This is taken care of by processing of def->serials */
    if (dev->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE &&
        dev->targetType == VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_SERIAL)
        return 0;

1225
    return virSecuritySELinuxRestoreSecurityChardevLabel(def, &dev->source);
1226 1227 1228
}


E
Eric Blake 已提交
1229
static int
1230 1231 1232
virSecuritySELinuxRestoreSecuritySmartcardCallback(virDomainDefPtr def,
                                                   virDomainSmartcardDefPtr dev,
                                                   void *opaque ATTRIBUTE_UNUSED)
E
Eric Blake 已提交
1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243
{
    const char *database;

    switch (dev->type) {
    case VIR_DOMAIN_SMARTCARD_TYPE_HOST:
        break;

    case VIR_DOMAIN_SMARTCARD_TYPE_HOST_CERTIFICATES:
        database = dev->data.cert.database;
        if (!database)
            database = VIR_DOMAIN_SMARTCARD_DEFAULT_DATABASE;
1244
        return virSecuritySELinuxRestoreSecurityFileLabel(database);
E
Eric Blake 已提交
1245 1246

    case VIR_DOMAIN_SMARTCARD_TYPE_PASSTHROUGH:
1247
        return virSecuritySELinuxRestoreSecurityChardevLabel(def, &dev->data.passthru);
E
Eric Blake 已提交
1248 1249

    default:
1250 1251 1252
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unknown smartcard type %d"),
                       dev->type);
E
Eric Blake 已提交
1253 1254 1255 1256 1257 1258 1259
        return -1;
    }

    return 0;
}


1260
static int
1261 1262 1263
virSecuritySELinuxRestoreSecurityAllLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
                                          virDomainDefPtr def,
                                          int migrated ATTRIBUTE_UNUSED)
1264
{
1265
    virSecurityLabelDefPtr secdef;
1266 1267
    int i;
    int rc = 0;
1268

1269
    VIR_DEBUG("Restoring security label on %s", def->name);
1270

1271 1272 1273 1274
    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
    if (secdef == NULL)
        return -1;

1275
    if (secdef->norelabel)
1276 1277
        return 0;

1278
    for (i = 0 ; i < def->nhostdevs ; i++) {
1279 1280 1281
        if (virSecuritySELinuxRestoreSecurityHostdevLabel(mgr,
                                                          def,
                                                          def->hostdevs[i]) < 0)
1282
            rc = -1;
1283
    }
1284
    for (i = 0 ; i < def->ndisks ; i++) {
1285 1286 1287 1288
        if (virSecuritySELinuxRestoreSecurityImageLabelInt(mgr,
                                                           def,
                                                           def->disks[i],
                                                           migrated) < 0)
1289 1290
            rc = -1;
    }
1291

1292
    if (virDomainChrDefForeach(def,
1293
                               false,
1294
                               virSecuritySELinuxRestoreSecurityChardevCallback,
1295
                               NULL) < 0)
1296 1297
        rc = -1;

1298
    if (virDomainSmartcardDefForeach(def,
E
Eric Blake 已提交
1299
                                     false,
1300
                                     virSecuritySELinuxRestoreSecuritySmartcardCallback,
1301
                                     NULL) < 0)
E
Eric Blake 已提交
1302 1303
        rc = -1;

1304
    if (def->os.kernel &&
1305
        virSecuritySELinuxRestoreSecurityFileLabel(def->os.kernel) < 0)
1306 1307
        rc = -1;

1308
    if (def->os.initrd &&
1309
        virSecuritySELinuxRestoreSecurityFileLabel(def->os.initrd) < 0)
1310 1311
        rc = -1;

1312 1313 1314 1315
    return rc;
}

static int
1316
virSecuritySELinuxReleaseSecurityLabel(virSecurityManagerPtr mgr,
1317
                                       virDomainDefPtr def)
1318
{
1319 1320 1321 1322 1323
    virSecurityLabelDefPtr secdef;

    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
    if (secdef == NULL)
        return -1;
1324

1325 1326 1327 1328
    if (secdef->type == VIR_DOMAIN_SECLABEL_DYNAMIC) {
        if (secdef->label != NULL) {
            context_t con = context_new(secdef->label);
            if (con) {
1329
                virSecuritySELinuxMCSRemove(mgr, context_range_get(con));
1330 1331 1332 1333 1334 1335
                context_free(con);
            }
        }
        VIR_FREE(secdef->label);
        if (!secdef->baselabel)
            VIR_FREE(secdef->model);
1336 1337 1338
    }
    VIR_FREE(secdef->imagelabel);

1339
    return 0;
1340 1341
}

1342 1343

static int
1344 1345 1346
virSecuritySELinuxSetSavedStateLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
                                     virDomainDefPtr def,
                                     const char *savefile)
1347
{
1348 1349 1350 1351 1352
    virSecurityLabelDefPtr secdef;

    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
    if (secdef == NULL)
        return -1;
1353

1354
    if (secdef->norelabel)
1355 1356
        return 0;

1357
    return virSecuritySELinuxSetFilecon(savefile, secdef->imagelabel);
1358 1359 1360 1361
}


static int
1362 1363 1364
virSecuritySELinuxRestoreSavedStateLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
                                         virDomainDefPtr def,
                                         const char *savefile)
1365
{
1366 1367 1368 1369 1370
    virSecurityLabelDefPtr secdef;

    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
    if (secdef == NULL)
        return -1;
1371

1372
    if (secdef->norelabel)
1373 1374
        return 0;

1375
    return virSecuritySELinuxRestoreSecurityFileLabel(savefile);
1376 1377 1378
}


1379
static int
1380 1381
virSecuritySELinuxSecurityVerify(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
                                 virDomainDefPtr def)
1382
{
1383 1384 1385 1386 1387 1388
    virSecurityLabelDefPtr secdef;

    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
    if (secdef == NULL)
        return -1;

1389
    if (!STREQ(virSecurityManagerGetModel(mgr), secdef->model)) {
1390 1391 1392 1393 1394
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("security label driver mismatch: "
                         "'%s' model configured for domain, but "
                         "hypervisor driver is '%s'."),
                       secdef->model, virSecurityManagerGetModel(mgr));
1395 1396 1397
        return -1;
    }

1398 1399
    if (secdef->type == VIR_DOMAIN_SECLABEL_STATIC) {
        if (security_check_context(secdef->label) != 0) {
1400 1401
            virReportError(VIR_ERR_XML_ERROR,
                           _("Invalid security label %s"), secdef->label);
1402 1403 1404 1405 1406 1407
            return -1;
        }
    }
    return 0;
}

1408
static int
1409 1410
virSecuritySELinuxSetSecurityProcessLabel(virSecurityManagerPtr mgr,
                                          virDomainDefPtr def)
1411 1412
{
    /* TODO: verify DOI */
1413 1414 1415 1416 1417
    virSecurityLabelDefPtr secdef;

    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
    if (secdef == NULL)
        return -1;
1418

1419
    if (secdef->label == NULL)
1420 1421
        return 0;

1422
    VIR_DEBUG("label=%s", secdef->label);
1423
    if (!STREQ(virSecurityManagerGetModel(mgr), secdef->model)) {
1424 1425 1426 1427 1428
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("security label driver mismatch: "
                         "'%s' model configured for domain, but "
                         "hypervisor driver is '%s'."),
                       secdef->model, virSecurityManagerGetModel(mgr));
1429
        if (security_getenforce() == 1)
1430
            return -1;
1431 1432 1433
    }

    if (setexeccon(secdef->label) == -1) {
1434
        virReportSystemError(errno,
1435 1436
                             _("unable to set security context '%s'"),
                             secdef->label);
1437
        if (security_getenforce() == 1)
1438
            return -1;
1439 1440
    }

1441 1442 1443
    return 0;
}

1444
static int
1445 1446
virSecuritySELinuxSetSecurityDaemonSocketLabel(virSecurityManagerPtr mgr,
                                               virDomainDefPtr def)
1447 1448
{
    /* TODO: verify DOI */
1449
    virSecurityLabelDefPtr secdef;
1450 1451 1452 1453 1454
    context_t execcon = NULL;
    context_t proccon = NULL;
    security_context_t scon = NULL;
    int rc = -1;

1455 1456 1457 1458 1459
    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
    if (secdef == NULL)
        return -1;

    if (secdef->label == NULL)
1460 1461
        return 0;

1462
    if (!STREQ(virSecurityManagerGetModel(mgr), secdef->model)) {
1463 1464 1465 1466 1467
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("security label driver mismatch: "
                         "'%s' model configured for domain, but "
                         "hypervisor driver is '%s'."),
                       secdef->model, virSecurityManagerGetModel(mgr));
1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499
        goto done;
    }

    if ( !(execcon = context_new(secdef->label)) ) {
        virReportSystemError(errno,
                             _("unable to allocate socket security context '%s'"),
                             secdef->label);
        goto done;
    }

    if (getcon(&scon) == -1) {
        virReportSystemError(errno,
                             _("unable to get current process context '%s'"),
                             secdef->label);
        goto done;
    }

    if ( !(proccon = context_new(scon)) ) {
        virReportSystemError(errno,
                             _("unable to set socket security context '%s'"),
                             secdef->label);
        goto done;
    }

    if (context_range_set(proccon, context_range_get(execcon)) == -1) {
        virReportSystemError(errno,
                             _("unable to set socket security context range '%s'"),
                             secdef->label);
        goto done;
    }

    VIR_DEBUG("Setting VM %s socket context %s",
1500
              def->name, context_str(proccon));
1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518
    if (setsockcreatecon(context_str(proccon)) == -1) {
        virReportSystemError(errno,
                             _("unable to set socket security context '%s'"),
                             context_str(proccon));
        goto done;
    }

    rc = 0;
done:

    if (security_getenforce() != 1)
        rc = 0;
    if (execcon) context_free(execcon);
    if (proccon) context_free(proccon);
    freecon(scon);
    return rc;
}

1519
static int
1520 1521
virSecuritySELinuxSetSecuritySocketLabel(virSecurityManagerPtr mgr,
                                         virDomainDefPtr vm)
1522
{
1523
    virSecurityLabelDefPtr secdef;
1524 1525
    int rc = -1;

1526 1527 1528 1529
    secdef = virDomainDefGetSecurityLabelDef(vm, SECURITY_SELINUX_NAME);
    if (secdef == NULL)
        return -1;

1530 1531 1532 1533
    if (secdef->label == NULL)
        return 0;

    if (!STREQ(virSecurityManagerGetModel(mgr), secdef->model)) {
1534 1535 1536 1537 1538
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("security label driver mismatch: "
                         "'%s' model configured for domain, but "
                         "hypervisor driver is '%s'."),
                       secdef->model, virSecurityManagerGetModel(mgr));
1539 1540 1541 1542
        goto done;
    }

    VIR_DEBUG("Setting VM %s socket context %s",
1543
              vm->name, secdef->label);
1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559
    if (setsockcreatecon(secdef->label) == -1) {
        virReportSystemError(errno,
                             _("unable to set socket security context '%s'"),
                             secdef->label);
        goto done;
    }

    rc = 0;

done:
    if (security_getenforce() != 1)
        rc = 0;

    return rc;
}

1560
static int
1561 1562
virSecuritySELinuxClearSecuritySocketLabel(virSecurityManagerPtr mgr,
                                           virDomainDefPtr def)
1563 1564
{
    /* TODO: verify DOI */
1565 1566 1567 1568 1569
    virSecurityLabelDefPtr secdef;

    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
    if (secdef == NULL)
        return -1;
1570

1571
    if (secdef->label == NULL)
1572 1573
        return 0;

1574
    if (!STREQ(virSecurityManagerGetModel(mgr), secdef->model)) {
1575 1576 1577 1578 1579
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("security label driver mismatch: "
                         "'%s' model configured for domain, but "
                         "hypervisor driver is '%s'."),
                       secdef->model, virSecurityManagerGetModel(mgr));
1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593
        if (security_getenforce() == 1)
            return -1;
    }

    if (setsockcreatecon(NULL) == -1) {
        virReportSystemError(errno,
                             _("unable to clear socket security context '%s'"),
                             secdef->label);
        if (security_getenforce() == 1)
            return -1;
    }
    return 0;
}

1594 1595

static int
1596 1597 1598
virSecuritySELinuxSetSecurityChardevCallback(virDomainDefPtr def,
                                             virDomainChrDefPtr dev,
                                             void *opaque ATTRIBUTE_UNUSED)
1599
{
1600 1601 1602 1603 1604
    /* This is taken care of by processing of def->serials */
    if (dev->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE &&
        dev->targetType == VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_SERIAL)
        return 0;

1605
    return virSecuritySELinuxSetSecurityChardevLabel(def, &dev->source);
1606 1607 1608
}


E
Eric Blake 已提交
1609
static int
1610 1611 1612
virSecuritySELinuxSetSecuritySmartcardCallback(virDomainDefPtr def,
                                               virDomainSmartcardDefPtr dev,
                                               void *opaque)
E
Eric Blake 已提交
1613 1614
{
    const char *database;
1615 1616
    virSecurityManagerPtr mgr = opaque;
    virSecuritySELinuxDataPtr data = virSecurityManagerGetPrivateData(mgr);
E
Eric Blake 已提交
1617 1618 1619 1620 1621 1622 1623 1624 1625

    switch (dev->type) {
    case VIR_DOMAIN_SMARTCARD_TYPE_HOST:
        break;

    case VIR_DOMAIN_SMARTCARD_TYPE_HOST_CERTIFICATES:
        database = dev->data.cert.database;
        if (!database)
            database = VIR_DOMAIN_SMARTCARD_DEFAULT_DATABASE;
1626
        return virSecuritySELinuxSetFilecon(database, data->content_context);
E
Eric Blake 已提交
1627 1628

    case VIR_DOMAIN_SMARTCARD_TYPE_PASSTHROUGH:
1629
        return virSecuritySELinuxSetSecurityChardevLabel(def, &dev->data.passthru);
E
Eric Blake 已提交
1630 1631

    default:
1632 1633 1634
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unknown smartcard type %d"),
                       dev->type);
E
Eric Blake 已提交
1635 1636 1637 1638 1639 1640 1641
        return -1;
    }

    return 0;
}


1642
static int
1643 1644 1645
virSecuritySELinuxSetSecurityAllLabel(virSecurityManagerPtr mgr,
                                      virDomainDefPtr def,
                                      const char *stdin_path)
1646 1647
{
    int i;
1648 1649 1650 1651 1652 1653
    virSecuritySELinuxDataPtr data = virSecurityManagerGetPrivateData(mgr);
    virSecurityLabelDefPtr secdef;

    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
    if (secdef == NULL)
        return -1;
1654

1655
    if (secdef->norelabel)
1656 1657
        return 0;

1658
    for (i = 0 ; i < def->ndisks ; i++) {
1659
        /* XXX fixme - we need to recursively label the entire tree :-( */
1660
        if (def->disks[i]->type == VIR_DOMAIN_DISK_TYPE_DIR) {
1661
            VIR_WARN("Unable to relabel directory tree %s for disk %s",
1662
                     def->disks[i]->src, def->disks[i]->dst);
1663
            continue;
1664
        }
1665
        if (virSecuritySELinuxSetSecurityImageLabel(mgr,
1666
                                         def, def->disks[i]) < 0)
1667 1668
            return -1;
    }
1669
    /* XXX fixme process  def->fss if relabel == true */
1670

1671
    for (i = 0 ; i < def->nhostdevs ; i++) {
1672
        if (virSecuritySELinuxSetSecurityHostdevLabel(mgr,
1673 1674
                                           def,
                                           def->hostdevs[i]) < 0)
1675
            return -1;
1676 1677
    }

1678
    if (virDomainChrDefForeach(def,
1679
                               true,
1680
                               virSecuritySELinuxSetSecurityChardevCallback,
1681
                               NULL) < 0)
1682 1683
        return -1;

1684
    if (virDomainSmartcardDefForeach(def,
E
Eric Blake 已提交
1685
                                     true,
1686
                                     virSecuritySELinuxSetSecuritySmartcardCallback,
1687
                                     mgr) < 0)
E
Eric Blake 已提交
1688 1689
        return -1;

1690
    if (def->os.kernel &&
1691
        virSecuritySELinuxSetFilecon(def->os.kernel, data->content_context) < 0)
1692 1693
        return -1;

1694
    if (def->os.initrd &&
1695
        virSecuritySELinuxSetFilecon(def->os.initrd, data->content_context) < 0)
1696 1697
        return -1;

1698
    if (stdin_path) {
1699
        if (virSecuritySELinuxSetFilecon(stdin_path, data->content_context) < 0 &&
1700 1701 1702 1703
            virStorageFileIsSharedFSType(stdin_path,
                                         VIR_STORAGE_FILE_SHFS_NFS) != 1)
            return -1;
    }
1704

1705 1706 1707
    return 0;
}

1708
static int
1709 1710 1711
virSecuritySELinuxSetImageFDLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
                                  virDomainDefPtr def,
                                  int fd)
1712
{
1713 1714 1715 1716 1717
    virSecurityLabelDefPtr secdef;

    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
    if (secdef == NULL)
        return -1;
1718 1719 1720 1721

    if (secdef->imagelabel == NULL)
        return 0;

1722
    return virSecuritySELinuxFSetFilecon(fd, secdef->imagelabel);
1723 1724
}

1725 1726 1727 1728
static char *
virSecuritySELinuxGenImageLabel(virSecurityManagerPtr mgr,
                                virDomainDefPtr def)
{
1729
    virSecurityLabelDefPtr secdef;
1730 1731 1732 1733 1734 1735
    virSecuritySELinuxDataPtr data = virSecurityManagerGetPrivateData(mgr);
    const char *range;
    context_t ctx = NULL;
    char *label = NULL;
    const char *mcs = NULL;

1736 1737 1738 1739
    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
    if (secdef == NULL)
        goto cleanup;

1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752
    if (secdef->label) {
        ctx = context_new(secdef->label);
        if (!ctx) {
            virReportOOMError();
            goto cleanup;
        }
        range = context_range_get(ctx);
        if (range) {
            mcs = strdup(range);
            if (!mcs) {
                virReportOOMError();
                goto cleanup;
            }
1753 1754
            if (!(label = virSecuritySELinuxGenNewContext(data->file_context,
                                                          mcs, true)))
1755 1756 1757 1758 1759 1760 1761 1762 1763 1764
                goto cleanup;
        }
    }

cleanup:
        context_free(ctx);
        VIR_FREE(mcs);
        return label;
}

1765 1766 1767 1768
static char *
virSecuritySELinuxGetSecurityMountOptions(virSecurityManagerPtr mgr,
                                          virDomainDefPtr def)
{
1769
    char *opts = NULL;
1770 1771 1772 1773 1774
    virSecurityLabelDefPtr secdef;

    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
    if (secdef == NULL)
        return NULL;
1775 1776

    if (! secdef->imagelabel)
1777
        secdef->imagelabel = virSecuritySELinuxGenImageLabel(mgr,def);
1778 1779 1780 1781 1782 1783 1784

    if (secdef->imagelabel) {
        virAsprintf(&opts,
                    ",context=\"%s\"",
                    (const char*) secdef->imagelabel);
    }

1785
    VIR_DEBUG("imageLabel=%s", secdef->imagelabel);
1786 1787 1788
    return opts;
}

1789
virSecurityDriver virSecurityDriverSELinux = {
1790 1791
    .privateDataLen                     = sizeof(virSecuritySELinuxData),
    .name                               = SECURITY_SELINUX_NAME,
1792 1793 1794
    .probe                              = virSecuritySELinuxSecurityDriverProbe,
    .open                               = virSecuritySELinuxSecurityDriverOpen,
    .close                              = virSecuritySELinuxSecurityDriverClose,
1795

1796 1797
    .getModel                           = virSecuritySELinuxSecurityGetModel,
    .getDOI                             = virSecuritySELinuxSecurityGetDOI,
1798

1799
    .domainSecurityVerify               = virSecuritySELinuxSecurityVerify,
1800

1801 1802
    .domainSetSecurityImageLabel        = virSecuritySELinuxSetSecurityImageLabel,
    .domainRestoreSecurityImageLabel    = virSecuritySELinuxRestoreSecurityImageLabel,
1803

1804 1805 1806
    .domainSetSecurityDaemonSocketLabel = virSecuritySELinuxSetSecurityDaemonSocketLabel,
    .domainSetSecuritySocketLabel       = virSecuritySELinuxSetSecuritySocketLabel,
    .domainClearSecuritySocketLabel     = virSecuritySELinuxClearSecuritySocketLabel,
1807

1808 1809 1810
    .domainGenSecurityLabel             = virSecuritySELinuxGenSecurityLabel,
    .domainReserveSecurityLabel         = virSecuritySELinuxReserveSecurityLabel,
    .domainReleaseSecurityLabel         = virSecuritySELinuxReleaseSecurityLabel,
1811

1812 1813
    .domainGetSecurityProcessLabel      = virSecuritySELinuxGetSecurityProcessLabel,
    .domainSetSecurityProcessLabel      = virSecuritySELinuxSetSecurityProcessLabel,
1814

1815 1816
    .domainSetSecurityAllLabel          = virSecuritySELinuxSetSecurityAllLabel,
    .domainRestoreSecurityAllLabel      = virSecuritySELinuxRestoreSecurityAllLabel,
1817

1818 1819
    .domainSetSecurityHostdevLabel      = virSecuritySELinuxSetSecurityHostdevLabel,
    .domainRestoreSecurityHostdevLabel  = virSecuritySELinuxRestoreSecurityHostdevLabel,
1820

1821 1822
    .domainSetSavedStateLabel           = virSecuritySELinuxSetSavedStateLabel,
    .domainRestoreSavedStateLabel       = virSecuritySELinuxRestoreSavedStateLabel,
1823

1824
    .domainSetSecurityImageFDLabel      = virSecuritySELinuxSetImageFDLabel,
1825

1826
    .domainGetSecurityMountOptions      = virSecuritySELinuxGetSecurityMountOptions,
1827
};