security_selinux.c 21.9 KB
Newer Older
1
/*
2
 * Copyright (C) 2008,2009 Red Hat, Inc.
3 4 5 6 7 8 9 10
 *
 * 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.
 *
 * Authors:
 *     James Morris <jmorris@namei.org>
11
 *     Dan Walsh <dwalsh@redhat.com>
12 13 14 15 16 17 18 19 20 21
 *
 * 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>

22
#include "security_driver.h"
23 24 25 26
#include "security_selinux.h"
#include "virterror_internal.h"
#include "util.h"
#include "memory.h"
27
#include "logging.h"
28 29
#include "pci.h"
#include "hostusb.h"
30
#include "storage_file.h"
D
Daniel P. Berrange 已提交
31 32 33

#define VIR_FROM_THIS VIR_FROM_SECURITY

34
static char default_domain_context[1024];
35
static char default_content_context[1024];
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
static char default_image_context[1024];
#define SECURITY_SELINUX_VOID_DOI       "0"
#define SECURITY_SELINUX_NAME "selinux"

/* TODO
   The data struct of used mcs should be replaced with a better data structure in the future
*/

struct MCS {
    char *mcs;
    struct MCS *next;
};
static struct MCS *mcsList = NULL;

static int
mcsAdd(const char *mcs)
{
    struct MCS *ptr;

    for (ptr = mcsList; ptr; ptr = ptr->next) {
D
Daniel P. Berrange 已提交
56
        if (STREQ(ptr->mcs, mcs))
57 58
            return -1;
    }
D
Daniel P. Berrange 已提交
59 60
    if (VIR_ALLOC(ptr) < 0)
        return -1;
61 62 63 64 65 66 67 68 69 70 71 72 73
    ptr->mcs = strdup(mcs);
    ptr->next = mcsList;
    mcsList = ptr;
    return 0;
}

static int
mcsRemove(const char *mcs)
{
    struct MCS *prevptr = NULL;
    struct MCS *ptr = NULL;

    for (ptr = mcsList; ptr; ptr = ptr->next) {
D
Daniel P. Berrange 已提交
74
        if (STREQ(ptr->mcs, mcs)) {
75 76 77 78 79
            if (prevptr)
                prevptr->next = ptr->next;
            else {
                mcsList = ptr->next;
            }
80 81
            VIR_FREE(ptr->mcs);
            VIR_FREE(ptr);
82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105
            return 0;
        }
        prevptr = ptr;
    }
    return -1;
}

static char *
SELinuxGenNewContext(const char *oldcontext, const char *mcs)
{
    char *newcontext = NULL;
    char *scontext = strdup(oldcontext);
    if (!scontext) goto err;
    context_t con = context_new(scontext);
    if (!con) goto err;
    context_range_set(con, mcs);
    newcontext = strdup(context_str(con));
    context_free(con);
err:
    freecon(scontext);
    return (newcontext);
}

static int
106
SELinuxInitialize(void)
107 108 109 110 111 112
{
    char *ptr = NULL;
    int fd = 0;

    fd = open(selinux_virtual_domain_context_path(), O_RDONLY);
    if (fd < 0) {
113
        virReportSystemError(errno,
114 115
                             _("cannot open SELinux virtual domain context file '%s'"),
                             selinux_virtual_domain_context_path());
116 117 118 119
        return -1;
    }

    if (saferead(fd, default_domain_context, sizeof(default_domain_context)) < 0) {
120
        virReportSystemError(errno,
121 122
                             _("cannot read SELinux virtual domain context file %s"),
                             selinux_virtual_domain_context_path());
123 124 125 126 127 128 129 130 131
        close(fd);
        return -1;
    }
    close(fd);

    ptr = strchrnul(default_domain_context, '\n');
    *ptr = '\0';

    if ((fd = open(selinux_virtual_image_context_path(), O_RDONLY)) < 0) {
132
        virReportSystemError(errno,
133 134
                             _("cannot open SELinux virtual image context file %s"),
                             selinux_virtual_image_context_path());
135 136 137 138
        return -1;
    }

    if (saferead(fd, default_image_context, sizeof(default_image_context)) < 0) {
139
        virReportSystemError(errno,
140 141
                             _("cannot read SELinux virtual image context file %s"),
                             selinux_virtual_image_context_path());
142 143 144 145 146 147
        close(fd);
        return -1;
    }
    close(fd);

    ptr = strchrnul(default_image_context, '\n');
148 149 150 151 152 153 154
    if (*ptr == '\n') {
        *ptr = '\0';
        strcpy(default_content_context, ptr+1);
        ptr = strchrnul(default_content_context, '\n');
        if (*ptr == '\n')
            *ptr = '\0';
    }
155 156 157 158
    return 0;
}

static int
159
SELinuxGenSecurityLabel(virDomainObjPtr vm)
160 161 162 163 164 165
{
    int rc = -1;
    char mcs[1024];
    char *scontext = NULL;
    int c1 = 0;
    int c2 = 0;
166

167 168 169
    if (vm->def->seclabel.type == VIR_DOMAIN_SECLABEL_STATIC)
        return 0;

170 171 172
    if (vm->def->seclabel.label ||
        vm->def->seclabel.model ||
        vm->def->seclabel.imagelabel) {
173
        virSecurityReportError(VIR_ERR_INTERNAL_ERROR,
174
                               "%s", _("security label already defined for VM"));
175
        return rc;
D
Daniel P. Berrange 已提交
176
    }
177 178 179 180 181 182 183 184

    do {
        c1 = virRandom(1024);
        c2 = virRandom(1024);

        if ( c1 == c2 ) {
            sprintf(mcs, "s0:c%d", c1);
        } else {
D
Daniel P. Berrange 已提交
185
            if ( c1 < c2 )
186 187 188 189 190 191 192
                sprintf(mcs, "s0:c%d,c%d", c1, c2);
            else
                sprintf(mcs, "s0:c%d,c%d", c2, c1);
        }
    } while(mcsAdd(mcs) == -1);

    vm->def->seclabel.label = SELinuxGenNewContext(default_domain_context, mcs);
D
Daniel P. Berrange 已提交
193
    if (! vm->def->seclabel.label)  {
194
        virSecurityReportError(VIR_ERR_INTERNAL_ERROR,
D
Daniel P. Berrange 已提交
195 196 197
                               _("cannot generate selinux context for %s"), mcs);
        goto err;
    }
198
    vm->def->seclabel.imagelabel = SELinuxGenNewContext(default_image_context, mcs);
D
Daniel P. Berrange 已提交
199
    if (! vm->def->seclabel.imagelabel)  {
200
        virSecurityReportError(VIR_ERR_INTERNAL_ERROR,
D
Daniel P. Berrange 已提交
201 202 203
                               _("cannot generate selinux context for %s"), mcs);
        goto err;
    }
204
    vm->def->seclabel.model = strdup(SECURITY_SELINUX_NAME);
205
    if (!vm->def->seclabel.model) {
206
        virReportOOMError();
D
Daniel P. Berrange 已提交
207 208 209
        goto err;
    }

210 211 212 213

    rc = 0;
    goto done;
err:
D
Daniel P. Berrange 已提交
214 215 216
    VIR_FREE(vm->def->seclabel.label);
    VIR_FREE(vm->def->seclabel.imagelabel);
    VIR_FREE(vm->def->seclabel.model);
217
done:
D
Daniel P. Berrange 已提交
218
    VIR_FREE(scontext);
219 220 221
    return rc;
}

222
static int
223
SELinuxReserveSecurityLabel(virDomainObjPtr vm)
224 225 226 227 228
{
    security_context_t pctx;
    context_t ctx = NULL;
    const char *mcs;

229 230 231
    if (vm->def->seclabel.type == VIR_DOMAIN_SECLABEL_STATIC)
        return 0;

232
    if (getpidcon(vm->pid, &pctx) == -1) {
233
        virReportSystemError(errno,
234
                             _("unable to get PID %d security context"), vm->pid);
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
        return -1;
    }

    ctx = context_new(pctx);
    VIR_FREE(pctx);
    if (!ctx)
        goto err;

    mcs = context_range_get(ctx);
    if (!mcs)
        goto err;

    mcsAdd(mcs);

    context_free(ctx);

    return 0;

err:
    context_free(ctx);
    return -1;
}



260 261 262 263 264 265 266
static int
SELinuxSecurityDriverProbe(void)
{
    return is_selinux_enabled() ? SECURITY_DRIVER_ENABLE : SECURITY_DRIVER_DISABLE;
}

static int
267
SELinuxSecurityDriverOpen(virSecurityDriverPtr drv)
268 269 270 271 272
{
    /*
     * Where will the DOI come from?  SELinux configuration, or qemu
     * configuration? For the moment, we'll just set it to "0".
     */
273
    virSecurityDriverSetDOI(drv, SECURITY_SELINUX_VOID_DOI);
274
    return SELinuxInitialize();
275 276 277
}

static int
278
SELinuxGetSecurityProcessLabel(virDomainObjPtr vm,
279
                               virSecurityLabelPtr sec)
280 281 282 283
{
    security_context_t ctx;

    if (getpidcon(vm->pid, &ctx) == -1) {
284
        virReportSystemError(errno,
285 286
                             _("unable to get PID %d security context"),
                             vm->pid);
287 288 289 290
        return -1;
    }

    if (strlen((char *) ctx) >= VIR_SECURITY_LABEL_BUFLEN) {
291
        virSecurityReportError(VIR_ERR_INTERNAL_ERROR,
292
                               _("security label exceeds "
C
Cole Robinson 已提交
293
                                 "maximum length: %d"),
294 295 296 297 298
                               VIR_SECURITY_LABEL_BUFLEN - 1);
        return -1;
    }

    strcpy(sec->label, (char *) ctx);
299
    VIR_FREE(ctx);
300 301 302

    sec->enforcing = security_getenforce();
    if (sec->enforcing == -1) {
303
        virReportSystemError(errno, "%s",
304
                             _("error calling security_getenforce()"));
305 306 307 308 309 310 311
        return -1;
    }

    return 0;
}

static int
312
SELinuxSetFilecon(const char *path, char *tcon)
313
{
314
    security_context_t econ;
315

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

318
    if (setfilecon(path, tcon) < 0) {
319 320
        int setfilecon_errno = errno;

321 322 323 324 325 326 327 328
        if (getfilecon(path, &econ) >= 0) {
            if (STREQ(tcon, econ)) {
                freecon(econ);
                /* It's alright, there's nothing to change anyway. */
                return 0;
            }
            freecon(econ);
        }
329 330

        /* if the error complaint is related to an image hosted on
331 332
         * an nfs mount, or a usbfs/sysfs filesystem not supporting
         * labelling, then just ignore it & hope for the best.
333
         * The user hopefully set one of the necessary SELinux
334
         * virt_use_{nfs,usb,pci}  boolean tunables to allow it...
335 336
         */
        if (setfilecon_errno != EOPNOTSUPP) {
337
            virReportSystemError(setfilecon_errno,
338 339
                                 _("unable to set security context '%s' on '%s'"),
                                 tcon, path);
340 341
            if (security_getenforce() == 1)
                return -1;
342 343 344
        } else {
            VIR_INFO("Setting security context '%s' on '%s' not supported",
                     tcon, path);
345
        }
346 347 348 349 350
    }
    return 0;
}

static int
351
SELinuxRestoreSecurityFileLabel(const char *path)
352
{
353 354 355
    struct stat buf;
    security_context_t fcon = NULL;
    int rc = -1;
D
Daniel P. Berrange 已提交
356
    int err;
357
    char *newpath = NULL;
358

359 360
    VIR_INFO("Restoring SELinux context on '%s'", path);

D
Daniel P. Berrange 已提交
361
    if ((err = virFileResolveLink(path, &newpath)) < 0) {
362
        virReportSystemError(err,
D
Daniel P. Berrange 已提交
363 364
                             _("cannot resolve symlink %s"), path);
        goto err;
365
    }
366

367 368 369
    if (stat(newpath, &buf) != 0) {
        virReportSystemError(errno,
                             _("cannot stat %s"), newpath);
D
Daniel P. Berrange 已提交
370
        goto err;
371
    }
D
Daniel P. Berrange 已提交
372 373

    if (matchpathcon(newpath, buf.st_mode, &fcon) == 0)  {
374
        rc = SELinuxSetFilecon(newpath, fcon);
375 376 377 378
    } else {
        virSecurityReportError(VIR_ERR_INTERNAL_ERROR,
                               _("cannot restore selinux file label for %s"),
                               newpath);
379
    }
380

381 382 383 384
err:
    VIR_FREE(fcon);
    VIR_FREE(newpath);
    return rc;
385 386
}

387
static int
388 389 390
SELinuxRestoreSecurityImageLabelInt(virDomainObjPtr vm,
                                    virDomainDiskDefPtr disk,
                                    int migrated)
391
{
392 393 394 395 396
    const virSecurityLabelDefPtr secdef = &vm->def->seclabel;

    if (secdef->type == VIR_DOMAIN_SECLABEL_STATIC)
        return 0;

397 398 399 400 401 402 403 404 405 406 407 408 409 410
    /* 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;

    if (!disk->src)
        return 0;

411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426
    /* 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;
        }
    }

427
    return SELinuxRestoreSecurityFileLabel(disk->src);
428 429
}

430 431 432 433 434 435 436 437 438

static int
SELinuxRestoreSecurityImageLabel(virDomainObjPtr vm,
                                 virDomainDiskDefPtr disk)
{
    return SELinuxRestoreSecurityImageLabelInt(vm, disk, 0);
}


439
static int
440
SELinuxSetSecurityImageLabel(virDomainObjPtr vm,
441
                             virDomainDiskDefPtr disk)
442 443 444

{
    const virSecurityLabelDefPtr secdef = &vm->def->seclabel;
445
    const char *path;
446

447 448 449
    if (secdef->type == VIR_DOMAIN_SECLABEL_STATIC)
        return 0;

450 451 452
    if (!disk->src)
        return 0;

453 454 455 456 457 458 459
    path = disk->src;
    do {
        virStorageFileMetadata meta;
        int ret;

        memset(&meta, 0, sizeof(meta));

460
        ret = virStorageFileGetMetadata(path, &meta);
461 462 463 464 465 466

        if (path != disk->src)
            VIR_FREE(path);
        path = NULL;

        if (ret < 0)
467
           break;
468 469

        if (meta.backingStore != NULL &&
470
            SELinuxSetFilecon(meta.backingStore,
471 472 473 474 475 476 477 478
                              default_content_context) < 0) {
            VIR_FREE(meta.backingStore);
            return -1;
        }

        path = meta.backingStore;
    } while (path != NULL);

479
    if (disk->shared) {
480
        return SELinuxSetFilecon(disk->src, default_image_context);
481
    } else if (disk->readonly) {
482
        return SELinuxSetFilecon(disk->src, default_content_context);
483
    } else if (secdef->imagelabel) {
484
        return SELinuxSetFilecon(disk->src, secdef->imagelabel);
485
    }
486

487 488 489
    return 0;
}

490 491

static int
492
SELinuxSetSecurityPCILabel(pciDevice *dev ATTRIBUTE_UNUSED,
493 494 495 496 497
                           const char *file, void *opaque)
{
    virDomainObjPtr vm = opaque;
    const virSecurityLabelDefPtr secdef = &vm->def->seclabel;

498
    return SELinuxSetFilecon(file, secdef->imagelabel);
499 500 501
}

static int
502
SELinuxSetSecurityUSBLabel(usbDevice *dev ATTRIBUTE_UNUSED,
503 504 505 506 507
                           const char *file, void *opaque)
{
    virDomainObjPtr vm = opaque;
    const virSecurityLabelDefPtr secdef = &vm->def->seclabel;

508
    return SELinuxSetFilecon(file, secdef->imagelabel);
509 510 511
}

static int
512
SELinuxSetSecurityHostdevLabel(virDomainObjPtr vm,
513 514 515
                               virDomainHostdevDefPtr dev)

{
516
    const virSecurityLabelDefPtr secdef = &vm->def->seclabel;
517 518
    int ret = -1;

519 520 521
    if (secdef->type == VIR_DOMAIN_SECLABEL_STATIC)
        return 0;

522 523 524 525 526
    if (dev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
        return 0;

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

530 531
        if (!usb)
            goto done;
532

533
        ret = usbDeviceFileIterate(usb, SELinuxSetSecurityUSBLabel, vm);
534
        usbFreeDevice(usb);
M
Mark McLoughlin 已提交
535
        break;
536 537 538
    }

    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI: {
539
        pciDevice *pci = pciGetDevice(dev->source.subsys.u.pci.domain,
540 541 542 543 544 545 546
                                      dev->source.subsys.u.pci.bus,
                                      dev->source.subsys.u.pci.slot,
                                      dev->source.subsys.u.pci.function);

        if (!pci)
            goto done;

547
        ret = pciDeviceFileIterate(pci, SELinuxSetSecurityPCILabel, vm);
548
        pciFreeDevice(pci);
549 550 551 552 553 554 555 556 557 558 559 560 561

        break;
    }

    default:
        ret = 0;
        break;
    }

done:
    return ret;
}

562

563
static int
564
SELinuxRestoreSecurityPCILabel(pciDevice *dev ATTRIBUTE_UNUSED,
565 566 567
                               const char *file,
                               void *opaque ATTRIBUTE_UNUSED)
{
568
    return SELinuxRestoreSecurityFileLabel(file);
569 570 571
}

static int
572
SELinuxRestoreSecurityUSBLabel(usbDevice *dev ATTRIBUTE_UNUSED,
573 574 575
                               const char *file,
                               void *opaque ATTRIBUTE_UNUSED)
{
576
    return SELinuxRestoreSecurityFileLabel(file);
577 578 579
}

static int
580
SELinuxRestoreSecurityHostdevLabel(virDomainObjPtr vm,
581 582 583
                                   virDomainHostdevDefPtr dev)

{
584
    const virSecurityLabelDefPtr secdef = &vm->def->seclabel;
585 586
    int ret = -1;

587 588 589
    if (secdef->type == VIR_DOMAIN_SECLABEL_STATIC)
        return 0;

590 591 592 593 594
    if (dev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
        return 0;

    switch (dev->source.subsys.type) {
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB: {
595
        usbDevice *usb = usbGetDevice(dev->source.subsys.u.usb.bus,
596
                                      dev->source.subsys.u.usb.device);
597 598 599 600

        if (!usb)
            goto done;

601
        ret = usbDeviceFileIterate(usb, SELinuxRestoreSecurityUSBLabel, NULL);
602
        usbFreeDevice(usb);
603 604 605 606 607

        break;
    }

    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI: {
608
        pciDevice *pci = pciGetDevice(dev->source.subsys.u.pci.domain,
609 610 611 612 613 614 615
                                      dev->source.subsys.u.pci.bus,
                                      dev->source.subsys.u.pci.slot,
                                      dev->source.subsys.u.pci.function);

        if (!pci)
            goto done;

616
        ret = pciDeviceFileIterate(pci, SELinuxRestoreSecurityPCILabel, NULL);
617
        pciFreeDevice(pci);
618 619 620 621 622 623 624 625 626 627 628 629 630

        break;
    }

    default:
        ret = 0;
        break;
    }

done:
    return ret;
}

631
static int
632 633
SELinuxRestoreSecurityAllLabel(virDomainObjPtr vm,
                               int migrated ATTRIBUTE_UNUSED)
634 635 636 637
{
    const virSecurityLabelDefPtr secdef = &vm->def->seclabel;
    int i;
    int rc = 0;
638 639 640

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

641 642 643 644
    if (secdef->type == VIR_DOMAIN_SECLABEL_STATIC)
        return 0;

    for (i = 0 ; i < vm->def->nhostdevs ; i++) {
645
        if (SELinuxRestoreSecurityHostdevLabel(vm, vm->def->hostdevs[i]) < 0)
646
            rc = -1;
647
    }
648
    for (i = 0 ; i < vm->def->ndisks ; i++) {
649 650 651
        if (SELinuxRestoreSecurityImageLabelInt(vm,
                                                vm->def->disks[i],
                                                migrated) < 0)
652 653
            rc = -1;
    }
654

655 656 657 658 659 660 661 662
    if (vm->def->os.kernel &&
        SELinuxRestoreSecurityFileLabel(vm->def->os.kernel) < 0)
        rc = -1;

    if (vm->def->os.initrd &&
        SELinuxRestoreSecurityFileLabel(vm->def->os.initrd) < 0)
        rc = -1;

663 664 665 666
    return rc;
}

static int
667
SELinuxReleaseSecurityLabel(virDomainObjPtr vm)
668 669 670
{
    const virSecurityLabelDefPtr secdef = &vm->def->seclabel;

671 672
    if (secdef->type == VIR_DOMAIN_SECLABEL_STATIC ||
        secdef->label == NULL)
673 674
        return 0;

675 676 677 678 679 680 681 682 683 684
    context_t con = context_new(secdef->label);
    if (con) {
        mcsRemove(context_range_get(con));
        context_free(con);
    }

    VIR_FREE(secdef->model);
    VIR_FREE(secdef->label);
    VIR_FREE(secdef->imagelabel);

685
    return 0;
686 687
}

688 689

static int
690
SELinuxSetSavedStateLabel(virDomainObjPtr vm,
691 692 693 694
                          const char *savefile)
{
    const virSecurityLabelDefPtr secdef = &vm->def->seclabel;

695 696 697
    if (secdef->type == VIR_DOMAIN_SECLABEL_STATIC)
        return 0;

698
    return SELinuxSetFilecon(savefile, secdef->imagelabel);
699 700 701 702
}


static int
703
SELinuxRestoreSavedStateLabel(virDomainObjPtr vm,
704 705
                              const char *savefile)
{
706 707 708 709 710
    const virSecurityLabelDefPtr secdef = &vm->def->seclabel;

    if (secdef->type == VIR_DOMAIN_SECLABEL_STATIC)
        return 0;

711
    return SELinuxRestoreSecurityFileLabel(savefile);
712 713 714
}


715
static int
716
SELinuxSecurityVerify(virDomainDefPtr def)
717 718 719 720
{
    const virSecurityLabelDefPtr secdef = &def->seclabel;
    if (secdef->type == VIR_DOMAIN_SECLABEL_STATIC) {
        if (security_check_context(secdef->label) != 0) {
721
            virSecurityReportError(VIR_ERR_XML_ERROR,
722 723 724 725 726 727 728
                                   _("Invalid security label %s"), secdef->label);
            return -1;
        }
    }
    return 0;
}

729
static int
730
SELinuxSetSecurityProcessLabel(virSecurityDriverPtr drv,
731
                               virDomainObjPtr vm)
732 733 734 735
{
    /* TODO: verify DOI */
    const virSecurityLabelDefPtr secdef = &vm->def->seclabel;

736 737 738
    if (vm->def->seclabel.label == NULL)
        return 0;

739
    if (!STREQ(drv->name, secdef->model)) {
740
        virSecurityReportError(VIR_ERR_INTERNAL_ERROR,
741 742 743 744
                               _("security label driver mismatch: "
                                 "'%s' model configured for domain, but "
                                 "hypervisor driver is '%s'."),
                               secdef->model, drv->name);
745
        if (security_getenforce() == 1)
746
            return -1;
747 748 749
    }

    if (setexeccon(secdef->label) == -1) {
750
        virReportSystemError(errno,
751 752
                             _("unable to set security context '%s'"),
                             secdef->label);
753
        if (security_getenforce() == 1)
754
            return -1;
755 756
    }

757 758 759 760
    return 0;
}

static int
761
SELinuxSetSecurityAllLabel(virDomainObjPtr vm)
762 763 764 765 766 767 768 769 770 771 772 773 774
{
    const virSecurityLabelDefPtr secdef = &vm->def->seclabel;
    int i;

    if (secdef->type == VIR_DOMAIN_SECLABEL_STATIC)
        return 0;

    for (i = 0 ; i < vm->def->ndisks ; i++) {
        /* XXX fixme - we need to recursively label the entire tree :-( */
        if (vm->def->disks[i]->type == VIR_DOMAIN_DISK_TYPE_DIR) {
            VIR_WARN("Unable to relabel directory tree %s for disk %s",
                     vm->def->disks[i]->src, vm->def->disks[i]->dst);
            continue;
775
        }
776
        if (SELinuxSetSecurityImageLabel(vm, vm->def->disks[i]) < 0)
777 778 779
            return -1;
    }
    for (i = 0 ; i < vm->def->nhostdevs ; i++) {
780
        if (SELinuxSetSecurityHostdevLabel(vm, vm->def->hostdevs[i]) < 0)
781
            return -1;
782 783
    }

784 785 786 787 788 789 790 791
    if (vm->def->os.kernel &&
        SELinuxSetFilecon(vm->def->os.kernel, default_content_context) < 0)
        return -1;

    if (vm->def->os.initrd &&
        SELinuxSetFilecon(vm->def->os.initrd, default_content_context) < 0)
        return -1;

792 793 794 795 796 797 798
    return 0;
}

virSecurityDriver virSELinuxSecurityDriver = {
    .name                       = SECURITY_SELINUX_NAME,
    .probe                      = SELinuxSecurityDriverProbe,
    .open                       = SELinuxSecurityDriverOpen,
799
    .domainSecurityVerify       = SELinuxSecurityVerify,
800 801 802
    .domainSetSecurityImageLabel = SELinuxSetSecurityImageLabel,
    .domainRestoreSecurityImageLabel = SELinuxRestoreSecurityImageLabel,
    .domainGenSecurityLabel     = SELinuxGenSecurityLabel,
803
    .domainReserveSecurityLabel     = SELinuxReserveSecurityLabel,
804 805 806 807 808
    .domainReleaseSecurityLabel     = SELinuxReleaseSecurityLabel,
    .domainGetSecurityProcessLabel     = SELinuxGetSecurityProcessLabel,
    .domainSetSecurityProcessLabel     = SELinuxSetSecurityProcessLabel,
    .domainRestoreSecurityAllLabel = SELinuxRestoreSecurityAllLabel,
    .domainSetSecurityAllLabel     = SELinuxSetSecurityAllLabel,
809 810
    .domainSetSecurityHostdevLabel = SELinuxSetSecurityHostdevLabel,
    .domainRestoreSecurityHostdevLabel = SELinuxRestoreSecurityHostdevLabel,
811 812
    .domainSetSavedStateLabel = SELinuxSetSavedStateLabel,
    .domainRestoreSavedStateLabel = SELinuxRestoreSavedStateLabel,
813
};