security_selinux.c 91.5 KB
Newer Older
1
/*
2
 * Copyright (C) 2008-2014 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
 * 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
15
 * License along with this library.  If not, see
O
Osier Yang 已提交
16 17
 * <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
#include "security_selinux.h"
36
#include "virerror.h"
37
#include "viralloc.h"
38
#include "virlog.h"
39
#include "virpci.h"
40
#include "virusb.h"
41
#include "virscsi.h"
42
#include "virscsivhost.h"
43
#include "virstoragefile.h"
E
Eric Blake 已提交
44
#include "virfile.h"
45
#include "virhash.h"
46
#include "virrandom.h"
47
#include "virconf.h"
48
#include "virtpm.h"
49
#include "virstring.h"
D
Daniel P. Berrange 已提交
50 51 52

#define VIR_FROM_THIS VIR_FROM_SECURITY

53 54
VIR_LOG_INIT("security.security_selinux");

55 56 57 58 59 60 61
#define MAX_CONTEXT 1024

typedef struct _virSecuritySELinuxData virSecuritySELinuxData;
typedef virSecuritySELinuxData *virSecuritySELinuxDataPtr;

struct _virSecuritySELinuxData {
    char *domain_context;
62
    char *alt_domain_context;
63 64
    char *file_context;
    char *content_context;
65
    virHashTablePtr mcs;
66
    bool skipAllLabel;
67 68 69
#if HAVE_SELINUX_LABEL_H
    struct selabel_handle *label_handle;
#endif
70 71
};

72 73 74
/* Data structure to pass to various callbacks so we have everything we need */
typedef struct _virSecuritySELinuxCallbackData virSecuritySELinuxCallbackData;
typedef virSecuritySELinuxCallbackData *virSecuritySELinuxCallbackDataPtr;
75

76
struct _virSecuritySELinuxCallbackData {
77 78 79 80
    virSecurityManagerPtr mgr;
    virDomainDefPtr def;
};

81 82 83
typedef struct _virSecuritySELinuxContextItem virSecuritySELinuxContextItem;
typedef virSecuritySELinuxContextItem *virSecuritySELinuxContextItemPtr;
struct _virSecuritySELinuxContextItem {
84 85
    char *path;
    char *tcon;
86 87 88 89 90 91 92 93 94 95 96
    bool optional;
};

typedef struct _virSecuritySELinuxContextList virSecuritySELinuxContextList;
typedef virSecuritySELinuxContextList *virSecuritySELinuxContextListPtr;
struct _virSecuritySELinuxContextList {
    bool privileged;
    virSecuritySELinuxContextItemPtr *items;
    size_t nItems;
};

97 98 99
#define SECURITY_SELINUX_VOID_DOI       "0"
#define SECURITY_SELINUX_NAME "selinux"

100
static int
101 102 103
virSecuritySELinuxRestoreTPMFileLabelInt(virSecurityManagerPtr mgr,
                                         virDomainDefPtr def,
                                         virDomainTPMDefPtr tpm);
104 105


106 107
virThreadLocal contextList;

108 109 110 111 112 113 114 115 116 117 118 119

static void
virSecuritySELinuxContextItemFree(virSecuritySELinuxContextItemPtr item)
{
    if (!item)
        return;

    VIR_FREE(item->path);
    VIR_FREE(item->tcon);
    VIR_FREE(item);
}

120 121 122 123 124 125
static int
virSecuritySELinuxContextListAppend(virSecuritySELinuxContextListPtr list,
                                    const char *path,
                                    const char *tcon,
                                    bool optional)
{
126 127
    int ret = -1;
    virSecuritySELinuxContextItemPtr item = NULL;
128 129 130 131

    if (VIR_ALLOC(item) < 0)
        return -1;

132 133 134
    if (VIR_STRDUP(item->path, path) < 0 || VIR_STRDUP(item->tcon, tcon) < 0)
        goto cleanup;

135 136
    item->optional = optional;

137 138
    if (VIR_APPEND_ELEMENT(list->items, list->nItems, item) < 0)
        goto cleanup;
139

140 141 142 143
    ret = 0;
 cleanup:
    virSecuritySELinuxContextItemFree(item);
    return ret;
144 145 146 147 148 149 150 151 152 153 154 155
}

static void
virSecuritySELinuxContextListFree(void *opaque)
{
    virSecuritySELinuxContextListPtr list = opaque;
    size_t i;

    if (!list)
        return;

    for (i = 0; i < list->nItems; i++)
156 157
        virSecuritySELinuxContextItemFree(list->items[i]);

158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230
    VIR_FREE(list);
}


/**
 * virSecuritySELinuxTransactionAppend:
 * @path: Path to chown
 * @tcon: target context
 * @optional: true if setting @tcon is optional
 *
 * Appends an entry onto transaction list.
 *
 * Returns: 1 in case of successful append
 *          0 if there is no transaction enabled
 *         -1 otherwise.
 */
static int
virSecuritySELinuxTransactionAppend(const char *path,
                                    const char *tcon,
                                    bool optional)
{
    virSecuritySELinuxContextListPtr list;

    list = virThreadLocalGet(&contextList);
    if (!list)
        return 0;

    if (virSecuritySELinuxContextListAppend(list, path, tcon, optional) < 0)
        return -1;

    return 1;
}


static int virSecuritySELinuxSetFileconHelper(const char *path,
                                              const char *tcon,
                                              bool optional,
                                              bool privileged);

/**
 * virSecuritySELinuxTransactionRun:
 * @pid: process pid
 * @opaque: opaque data
 *
 * This is the callback that runs in the same namespace as the domain we are
 * relabelling. For given transaction (@opaque) it relabels all the paths on
 * the list.
 *
 * Returns: 0 on success
 *         -1 otherwise.
 */
static int
virSecuritySELinuxTransactionRun(pid_t pid ATTRIBUTE_UNUSED,
                                 void *opaque)
{
    virSecuritySELinuxContextListPtr list = opaque;
    size_t i;

    for (i = 0; i < list->nItems; i++) {
        virSecuritySELinuxContextItemPtr item = list->items[i];

        /* TODO Implement rollback */
        if (virSecuritySELinuxSetFileconHelper(item->path,
                                               item->tcon,
                                               item->optional,
                                               list->privileged) < 0)
            return -1;
    }

    return 0;
}


231 232 233
/*
 * Returns 0 on success, 1 if already reserved, or -1 on fatal error
 */
234
static int
235 236
virSecuritySELinuxMCSAdd(virSecurityManagerPtr mgr,
                         const char *mcs)
237
{
238
    virSecuritySELinuxDataPtr data = virSecurityManagerGetPrivateData(mgr);
239

240 241 242 243
    if (virHashLookup(data->mcs, mcs))
        return 1;

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

246 247 248
    return 0;
}

249 250 251
static void
virSecuritySELinuxMCSRemove(virSecurityManagerPtr mgr,
                            const char *mcs)
252
{
253 254 255
    virSecuritySELinuxDataPtr data = virSecurityManagerGetPrivateData(mgr);

    virHashRemoveEntry(data->mcs, mcs);
256 257
}

258 259

static char *
260 261 262 263
virSecuritySELinuxMCSFind(virSecurityManagerPtr mgr,
                          const char *sens,
                          int catMin,
                          int catMax)
264 265
{
    virSecuritySELinuxDataPtr data = virSecurityManagerGetPrivateData(mgr);
266
    int catRange;
267
    char *mcs = NULL;
268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288

    /* +1 since virRandomInt range is exclusive of the upper bound */
    catRange = (catMax - catMin) + 1;

    if (catRange < 8) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Category range c%d-c%d too small"),
                       catMin, catMax);
        return NULL;
    }

    VIR_DEBUG("Using sensitivity level '%s' cat min %d max %d range %d",
              sens, catMin, catMax, catRange);

    for (;;) {
        int c1 = virRandomInt(catRange);
        int c2 = virRandomInt(catRange);

        VIR_DEBUG("Try cat %s:c%d,c%d", sens, c1 + catMin, c2 + catMin);

        if (c1 == c2) {
289
            if (virAsprintf(&mcs, "%s:c%d", sens, catMin + c1) < 0)
290 291 292 293 294 295 296
                return NULL;
        } else {
            if (c1 > c2) {
                int t = c1;
                c1 = c2;
                c2 = t;
            }
297
            if (virAsprintf(&mcs, "%s:c%d,c%d", sens, catMin + c1, catMin + c2) < 0)
298 299 300 301 302 303 304 305 306 307 308 309
                return NULL;
        }

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

        VIR_FREE(mcs);
    }

    return mcs;
}

310 311 312 313

/*
 * This needs to cope with several styles of range
 *
314
 * system_u:system_r:virtd_t
315 316 317 318
 * system_u:system_r:virtd_t:s0
 * system_u:system_r:virtd_t:s0-s0
 * system_u:system_r:virtd_t:s0-s0:c0.c1023
 *
319 320
 * In the first case we'll assume s0:c0.c1023 and
 * in the next two cases, we'll assume c0.c1023 for
321 322 323
 * the category part, since that's what we're really
 * interested in. This won't work in Enforcing mode,
 * but will prevent libvirtd breaking in Permissive
N
Nehal J Wani 已提交
324
 * mode when run with a weird process label.
325
 */
326 327 328 329 330
static int
virSecuritySELinuxMCSGetProcessRange(char **sens,
                                     int *catMin,
                                     int *catMax)
{
331 332
    security_context_t ourSecContext = NULL;
    context_t ourContext = NULL;
333 334
    char *cat = NULL;
    char *tmp;
335
    const char *contextRange;
336
    int ret = -1;
337

M
Martin Kletzander 已提交
338
    if (getcon_raw(&ourSecContext) < 0) {
339 340 341 342 343 344 345 346 347 348
        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;
    }
349 350
    if (!(contextRange = context_range_get(ourContext)))
        contextRange = "s0";
351

352
    if (VIR_STRDUP(*sens, contextRange) < 0)
353 354
        goto cleanup;

355 356 357 358 359
    /* Find and blank out the category part (if any) */
    tmp = strchr(*sens, ':');
    if (tmp) {
        *tmp = '\0';
        cat = tmp + 1;
360 361
    }
    /* Find and blank out the sensitivity upper bound */
362
    if ((tmp = strchr(*sens, '-')))
363 364 365
        *tmp = '\0';
    /* sens now just contains the sensitivity lower bound */

366
    /* If there was no category part, just assume c0.c1023 */
367 368
    if (!cat) {
        *catMin = 0;
369
        *catMax = 1023;
370 371 372 373
        ret = 0;
        goto cleanup;
    }

374 375 376 377 378 379 380 381 382
    /* Find & extract category min */
    tmp = cat;
    if (tmp[0] != 'c') {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Cannot parse category in %s"),
                       cat);
        goto cleanup;
    }
    tmp++;
383
    if (virStrToLong_i(tmp, &tmp, 10, catMin) < 0) {
384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Cannot parse category in %s"),
                       cat);
        goto cleanup;
    }

    /* We *must* have a pair of categories otherwise
     * there's no range to allocate VM categories from */
    if (!tmp[0]) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("No category range available"));
        goto cleanup;
    }

    /* Find & extract category max (if any) */
    if (tmp[0] != '.') {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Cannot parse category in %s"),
                       cat);
        goto cleanup;
    }
    tmp++;
    if (tmp[0] != 'c') {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Cannot parse category in %s"),
                       cat);
        goto cleanup;
    }
    tmp++;
413
    if (virStrToLong_i(tmp, &tmp, 10, catMax) < 0) {
414 415 416 417 418 419
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Cannot parse category in %s"),
                       cat);
        goto cleanup;
    }

420
    ret = 0;
421

422
 cleanup:
423 424
    if (ret < 0)
        VIR_FREE(*sens);
425 426
    freecon(ourSecContext);
    context_free(ourContext);
427
    return ret;
428 429
}

430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459
static char *
virSecuritySELinuxContextAddRange(security_context_t src,
                                  security_context_t dst)
{
    char *str = NULL;
    char *ret = NULL;
    context_t srccon = NULL;
    context_t dstcon = NULL;

    if (!src || !dst)
        return ret;

    if (!(srccon = context_new(src)) || !(dstcon = context_new(dst))) {
        virReportSystemError(errno, "%s",
                             _("unable to allocate security context"));
        goto cleanup;
    }

    if (context_range_set(dstcon, context_range_get(srccon)) == -1) {
        virReportSystemError(errno,
                             _("unable to set security context range '%s'"), dst);
        goto cleanup;
    }

    if (!(str = context_str(dstcon))) {
        virReportSystemError(errno, "%s",
                             _("Unable to format SELinux context"));
        goto cleanup;
    }

460
    ignore_value(VIR_STRDUP(ret, str));
461

462
 cleanup:
463 464 465 466
    if (srccon) context_free(srccon);
    if (dstcon) context_free(dstcon);
    return ret;
}
467

468
static char *
469 470 471
virSecuritySELinuxGenNewContext(const char *basecontext,
                                const char *mcs,
                                bool isObjectContext)
472
{
473
    context_t context = NULL;
474 475
    char *ret = NULL;
    char *str;
476 477 478
    security_context_t ourSecContext = NULL;
    context_t ourContext = NULL;

479 480 481
    VIR_DEBUG("basecontext=%s mcs=%s isObjectContext=%d",
              basecontext, mcs, isObjectContext);

M
Martin Kletzander 已提交
482
    if (getcon_raw(&ourSecContext) < 0) {
483 484 485 486 487 488 489 490 491 492
        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;
    }
493
    VIR_DEBUG("process=%s", ourSecContext);
494 495 496 497 498 499 500 501

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

502 503 504 505 506 507 508 509
    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;
    }

510 511
    if (!isObjectContext &&
        context_role_set(context,
512 513
                         context_role_get(ourContext)) != 0) {
        virReportSystemError(errno,
514
                             _("Unable to set SELinux context role '%s'"),
515 516 517 518
                             context_role_get(ourContext));
        goto cleanup;
    }

519 520 521 522 523 524 525 526 527 528 529
    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;
    }
530
    if (VIR_STRDUP(ret, str) < 0)
531
        goto cleanup;
532
    VIR_DEBUG("Generated context '%s'",  ret);
533
 cleanup:
534 535
    freecon(ourSecContext);
    context_free(ourContext);
536 537
    context_free(context);
    return ret;
538 539
}

540

541
#ifdef HAVE_SELINUX_LXC_CONTEXTS_PATH
542
static int
543
virSecuritySELinuxLXCInitialize(virSecurityManagerPtr mgr)
544 545 546 547
{
    virConfPtr selinux_conf;
    virSecuritySELinuxDataPtr data = virSecurityManagerGetPrivateData(mgr);

548 549
    data->skipAllLabel = true;

550
# if HAVE_SELINUX_LABEL_H
551 552 553 554 555 556
    data->label_handle = selabel_open(SELABEL_CTX_FILE, NULL, 0);
    if (!data->label_handle) {
        virReportSystemError(errno, "%s",
                             _("cannot open SELinux label_handle"));
        return -1;
    }
557
# endif
558

559
    if (!(selinux_conf = virConfReadFile(selinux_lxc_contexts_path(), 0)))
560
        goto error;
561

562
    if (virConfGetValueString(selinux_conf, "process", &data->domain_context) < 0)
563 564
        goto error;

565 566 567 568
    if (!data->domain_context) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("missing 'process' value in selinux lxc contexts file '%s'"),
                       selinux_lxc_contexts_path());
569 570 571
        goto error;
    }

572 573 574 575 576 577 578
    if (virConfGetValueString(selinux_conf, "file", &data->file_context) < 0)
        goto error;

    if (!data->file_context) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("missing 'file' value in selinux lxc contexts file '%s'"),
                       selinux_lxc_contexts_path());
579 580 581
        goto error;
    }

582 583 584 585 586 587 588
    if (virConfGetValueString(selinux_conf, "content", &data->content_context) < 0)
        goto error;

    if (!data->content_context) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("missing 'content' value in selinux lxc contexts file '%s'"),
                       selinux_lxc_contexts_path());
589
        goto error;
590
    }
591 592 593 594

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

595 596 597
    virConfFree(selinux_conf);
    return 0;

598
 error:
599
# if HAVE_SELINUX_LABEL_H
600
    selabel_close(data->label_handle);
601
    data->label_handle = NULL;
602
# endif
603 604 605 606
    virConfFree(selinux_conf);
    VIR_FREE(data->domain_context);
    VIR_FREE(data->file_context);
    VIR_FREE(data->content_context);
607
    virHashFree(data->mcs);
608 609
    return -1;
}
610 611
#else
static int
612
virSecuritySELinuxLXCInitialize(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED)
613 614 615 616 617 618
{
    virReportSystemError(ENOSYS, "%s",
                         _("libselinux does not support LXC contexts path"));
    return -1;
}
#endif
619 620 621


static int
622
virSecuritySELinuxQEMUInitialize(virSecurityManagerPtr mgr)
623
{
624 625
    char *ptr;
    virSecuritySELinuxDataPtr data = virSecurityManagerGetPrivateData(mgr);
626

627 628
    data->skipAllLabel = false;

629 630 631 632 633 634 635 636 637
#if HAVE_SELINUX_LABEL_H
    data->label_handle = selabel_open(SELABEL_CTX_FILE, NULL, 0);
    if (!data->label_handle) {
        virReportSystemError(errno, "%s",
                             _("cannot open SELinux label_handle"));
        return -1;
    }
#endif

638
    if (virFileReadAll(selinux_virtual_domain_context_path(), MAX_CONTEXT, &(data->domain_context)) < 0) {
639
        virReportSystemError(errno,
640
                             _("cannot read SELinux virtual domain context file '%s'"),
641
                             selinux_virtual_domain_context_path());
642
        goto error;
643 644
    }

645
    ptr = strchrnul(data->domain_context, '\n');
646
    if (ptr && *ptr == '\n') {
647
        *ptr = '\0';
648 649
        ptr++;
        if (*ptr != '\0') {
650
            if (VIR_STRDUP(data->alt_domain_context, ptr) < 0)
651 652 653 654 655 656 657 658 659
                goto error;
            ptr = strchrnul(data->alt_domain_context, '\n');
            if (ptr && *ptr == '\n')
                *ptr = '\0';
        }
    }
    VIR_DEBUG("Loaded domain context '%s', alt domain context '%s'",
              data->domain_context, NULLSTR(data->alt_domain_context));

660

661
    if (virFileReadAll(selinux_virtual_image_context_path(), 2*MAX_CONTEXT, &(data->file_context)) < 0) {
662
        virReportSystemError(errno,
663 664
                             _("cannot read SELinux virtual image context file %s"),
                             selinux_virtual_image_context_path());
665
        goto error;
666 667
    }

668 669
    ptr = strchrnul(data->file_context, '\n');
    if (ptr && *ptr == '\n') {
670
        *ptr = '\0';
671
        if (VIR_STRDUP(data->content_context, ptr + 1) < 0)
672 673 674
            goto error;
        ptr = strchrnul(data->content_context, '\n');
        if (ptr && *ptr == '\n')
675 676
            *ptr = '\0';
    }
677

678 679 680
    VIR_DEBUG("Loaded file context '%s', content context '%s'",
              data->file_context, data->content_context);

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

684
    return 0;
685

686
 error:
687 688
#if HAVE_SELINUX_LABEL_H
    selabel_close(data->label_handle);
689
    data->label_handle = NULL;
690
#endif
691
    VIR_FREE(data->domain_context);
692
    VIR_FREE(data->alt_domain_context);
693 694
    VIR_FREE(data->file_context);
    VIR_FREE(data->content_context);
695
    virHashFree(data->mcs);
696
    return -1;
697 698
}

699 700

static int
701
virSecuritySELinuxInitialize(virSecurityManagerPtr mgr)
702 703
{
    VIR_DEBUG("SELinuxInitialize %s", virSecurityManagerGetDriver(mgr));
704 705 706 707 708 709 710 711

    if (virThreadLocalInit(&contextList,
                           virSecuritySELinuxContextListFree) < 0) {
        virReportSystemError(errno, "%s",
                             _("Unable to initialize thread local variable"));
        return -1;
    }

712
    if (STREQ(virSecurityManagerGetDriver(mgr),  "LXC")) {
713
        return virSecuritySELinuxLXCInitialize(mgr);
714
    } else {
715
        return virSecuritySELinuxQEMUInitialize(mgr);
716 717 718 719
    }
}


720
static int
721 722
virSecuritySELinuxGenLabel(virSecurityManagerPtr mgr,
                           virDomainDefPtr def)
723 724
{
    int rc = -1;
725
    char *mcs = NULL;
726
    char *scontext = NULL;
727
    context_t ctx = NULL;
728
    const char *range;
729 730
    virSecurityLabelDefPtr seclabel;
    virSecuritySELinuxDataPtr data;
731
    const char *baselabel;
732 733
    char *sens = NULL;
    int catMin, catMax;
734

735
    seclabel = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
P
Peter Krempa 已提交
736
    if (seclabel == NULL)
737
        return 0;
738 739 740 741 742 743

    data = virSecurityManagerGetPrivateData(mgr);

    VIR_DEBUG("label=%s", virSecurityManagerGetDriver(mgr));
    if (seclabel->type == VIR_DOMAIN_SECLABEL_DYNAMIC &&
        seclabel->label) {
P
Peter Krempa 已提交
744 745
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("security label already defined for VM"));
746
        return rc;
D
Daniel P. Berrange 已提交
747
    }
748

749
    if (seclabel->imagelabel) {
P
Peter Krempa 已提交
750 751
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("security image label already defined for VM"));
752 753 754
        return rc;
    }

755 756
    if (seclabel->model &&
        STRNEQ(seclabel->model, SECURITY_SELINUX_NAME)) {
757 758
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("security label model %s is not supported with selinux"),
759
                       seclabel->model);
760 761 762
        return rc;
    }

763
    VIR_DEBUG("type=%d", seclabel->type);
764

765
    switch (seclabel->type) {
766
    case VIR_DOMAIN_SECLABEL_STATIC:
767
        if (!(ctx = context_new(seclabel->label))) {
768 769
            virReportSystemError(errno,
                                 _("unable to allocate socket security context '%s'"),
770
                                 seclabel->label);
771
            return rc;
772 773
        }

P
Peter Krempa 已提交
774
        if (!(range = context_range_get(ctx))) {
775
            virReportSystemError(errno, "%s", _("unable to get selinux context range"));
776 777
            goto cleanup;
        }
778 779
        if (VIR_STRDUP(mcs, range) < 0)
            goto cleanup;
780 781 782
        break;

    case VIR_DOMAIN_SECLABEL_DYNAMIC:
783 784 785 786 787 788 789 790 791
        if (virSecuritySELinuxMCSGetProcessRange(&sens,
                                                 &catMin,
                                                 &catMax) < 0)
            goto cleanup;

        if (!(mcs = virSecuritySELinuxMCSFind(mgr,
                                              sens,
                                              catMin,
                                              catMax)))
792 793 794 795
            goto cleanup;

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

797 798 799 800
        baselabel = seclabel->baselabel;
        if (!baselabel) {
            if (def->virtType == VIR_DOMAIN_VIRT_QEMU) {
                if (data->alt_domain_context == NULL) {
801
                    static bool warned;
802 803 804 805 806 807 808 809 810 811 812 813 814 815 816
                    if (!warned) {
                        VIR_WARN("SELinux policy does not define a domain type for QEMU TCG. "
                                 "Guest startup may be denied due to missing 'execmem' privilege "
                                 "unless the 'virt_use_execmem' policy boolean is enabled");
                        warned = true;
                    }
                    baselabel = data->domain_context;
                } else {
                    baselabel = data->alt_domain_context;
                }
            } else {
                baselabel = data->domain_context;
            }
        }

817 818
        seclabel->label = virSecuritySELinuxGenNewContext(baselabel, mcs, false);
        if (!seclabel->label)
819
            goto cleanup;
820

821 822 823
        break;

    case VIR_DOMAIN_SECLABEL_NONE:
824 825 826 827 828 829 830 831
        if (virSecuritySELinuxMCSGetProcessRange(&sens,
                                                 &catMin,
                                                 &catMax) < 0)
            goto cleanup;

        if (VIR_STRDUP(mcs, sens) < 0)
            goto cleanup;

832 833 834
        break;

    default:
835 836
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected security label type '%s'"),
837
                       virDomainSeclabelTypeToString(seclabel->type));
838
        goto cleanup;
D
Daniel P. Berrange 已提交
839
    }
840

841 842 843 844 845 846
    /* always generate a image label, needed to label new objects */
    seclabel->imagelabel = virSecuritySELinuxGenNewContext(data->file_context,
                                                           mcs,
                                                           true);
    if (!seclabel->imagelabel)
        goto cleanup;
847

848
    if (!seclabel->model &&
849
        VIR_STRDUP(seclabel->model, SECURITY_SELINUX_NAME) < 0)
850
        goto cleanup;
D
Daniel P. Berrange 已提交
851

852
    rc = 0;
853

854
 cleanup:
855
    if (rc != 0) {
856 857 858 859 860 861
        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);
862 863 864 865
    }

    if (ctx)
        context_free(ctx);
D
Daniel P. Berrange 已提交
866
    VIR_FREE(scontext);
867
    VIR_FREE(mcs);
868
    VIR_FREE(sens);
869 870

    VIR_DEBUG("model=%s label=%s imagelabel=%s baselabel=%s",
871 872 873 874
              NULLSTR(seclabel->model),
              NULLSTR(seclabel->label),
              NULLSTR(seclabel->imagelabel),
              NULLSTR(seclabel->baselabel));
875

876 877 878
    return rc;
}

879
static int
880 881 882
virSecuritySELinuxReserveLabel(virSecurityManagerPtr mgr,
                               virDomainDefPtr def,
                               pid_t pid)
883 884 885 886
{
    security_context_t pctx;
    context_t ctx = NULL;
    const char *mcs;
887
    int rv;
888
    virSecurityLabelDefPtr seclabel;
889

890
    seclabel = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
891 892 893
    if (!seclabel ||
        seclabel->type == VIR_DOMAIN_SECLABEL_NONE ||
        seclabel->type == VIR_DOMAIN_SECLABEL_STATIC)
894 895
        return 0;

M
Martin Kletzander 已提交
896
    if (getpidcon_raw(pid, &pctx) == -1) {
897
        virReportSystemError(errno,
898
                             _("unable to get PID %d security context"), pid);
899 900 901 902
        return -1;
    }

    ctx = context_new(pctx);
903
    freecon(pctx);
904
    if (!ctx)
905
        goto error;
906 907 908

    mcs = context_range_get(ctx);
    if (!mcs)
909 910
        goto error;

911
    if ((rv = virSecuritySELinuxMCSAdd(mgr, mcs)) < 0)
912
        goto error;
913

914 915 916 917 918 919
    if (rv == 1) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("MCS level for existing domain label %s already reserved"),
                       (char*)pctx);
        goto error;
    }
920 921 922 923 924

    context_free(ctx);

    return 0;

925
 error:
926 927 928 929 930
    context_free(ctx);
    return -1;
}


931
static int
932
virSecuritySELinuxDriverProbe(const char *virtDriver)
933
{
934
    if (is_selinux_enabled() <= 0)
935 936
        return SECURITY_DRIVER_DISABLE;

937 938 939 940 941 942
    if (virtDriver && STREQ(virtDriver, "LXC")) {
#if HAVE_SELINUX_LXC_CONTEXTS_PATH
        if (!virFileExists(selinux_lxc_contexts_path()))
#endif
            return SECURITY_DRIVER_DISABLE;
    }
943 944

    return SECURITY_DRIVER_ENABLE;
945 946
}

947

948
static int
949
virSecuritySELinuxDriverOpen(virSecurityManagerPtr mgr)
950
{
951
    return virSecuritySELinuxInitialize(mgr);
952 953
}

954

955
static int
956
virSecuritySELinuxDriverClose(virSecurityManagerPtr mgr)
957
{
958 959 960 961 962
    virSecuritySELinuxDataPtr data = virSecurityManagerGetPrivateData(mgr);

    if (!data)
        return 0;

963
#if HAVE_SELINUX_LABEL_H
964 965
    if (data->label_handle)
        selabel_close(data->label_handle);
966 967
#endif

968 969
    virHashFree(data->mcs);

970
    VIR_FREE(data->domain_context);
971
    VIR_FREE(data->alt_domain_context);
972 973 974
    VIR_FREE(data->file_context);
    VIR_FREE(data->content_context);

975 976 977 978
    return 0;
}


979
static const char *
980
virSecuritySELinuxGetModel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED)
981 982 983 984
{
    return SECURITY_SELINUX_NAME;
}

985
static const char *
986
virSecuritySELinuxGetDOI(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED)
987 988 989 990 991
{
    /*
     * Where will the DOI come from?  SELinux configuration, or qemu
     * configuration? For the moment, we'll just set it to "0".
     */
992
    return SECURITY_SELINUX_VOID_DOI;
993 994
}

995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098
/**
 * virSecuritySELinuxTransactionStart:
 * @mgr: security manager
 *
 * Starts a new transaction. In transaction nothing is changed context
 * until TransactionCommit() is called. This is implemented as a list
 * that is appended to whenever setfilecon() would be called. Since
 * secdriver APIs can be called from multiple threads (to work over
 * different domains) the pointer to the list is stored in thread local
 * variable.
 *
 * Returns 0 on success,
 *        -1 otherwise.
 */
static int
virSecuritySELinuxTransactionStart(virSecurityManagerPtr mgr)
{
    bool privileged = virSecurityManagerGetPrivileged(mgr);
    virSecuritySELinuxContextListPtr list;

    list = virThreadLocalGet(&contextList);
    if (list) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Another relabel transaction is already started"));
        return -1;
    }

    if (VIR_ALLOC(list) < 0)
        return -1;

    list->privileged = privileged;

    if (virThreadLocalSet(&contextList, list) < 0) {
        virReportSystemError(errno, "%s",
                             _("Unable to set thread local variable"));
        VIR_FREE(list);
        return -1;
    }

    return 0;
}

/**
 * virSecuritySELinuxTransactionCommit:
 * @mgr: security manager
 * @pid: domain's PID
 *
 * Enters the @pid namespace (usually @pid refers to a domain) and
 * performs all the sefilecon()-s on the list. Note that the
 * transaction is also freed, therefore new one has to be started after
 * successful return from this function. Also it is considered as error
 * if there's no transaction set and this function is called.
 *
 * Returns: 0 on success,
 *         -1 otherwise.
 */
static int
virSecuritySELinuxTransactionCommit(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
                                    pid_t pid)
{
    virSecuritySELinuxContextListPtr list;
    int ret = 0;

    list = virThreadLocalGet(&contextList);
    if (!list)
        return 0;

    if (virThreadLocalSet(&contextList, NULL) < 0) {
        virReportSystemError(errno, "%s",
                             _("Unable to clear thread local variable"));
        goto cleanup;
    }

    if (virProcessRunInMountNamespace(pid,
                                      virSecuritySELinuxTransactionRun,
                                      list) < 0)
        goto cleanup;

    ret = 0;
 cleanup:
    virSecuritySELinuxContextListFree(list);
    return ret;
}

/**
 * virSecuritySELinuxTransactionAbort:
 * @mgr: security manager
 *
 * Cancels and frees any out standing transaction.
 */
static void
virSecuritySELinuxTransactionAbort(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED)
{
    virSecuritySELinuxContextListPtr list;

    list = virThreadLocalGet(&contextList);
    if (!list)
        return;

    if (virThreadLocalSet(&contextList, NULL) < 0)
        VIR_DEBUG("Unable to clear thread local variable");
    virSecuritySELinuxContextListFree(list);
}

1099
static int
1100 1101 1102 1103
virSecuritySELinuxGetProcessLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
                                  virDomainDefPtr def ATTRIBUTE_UNUSED,
                                  pid_t pid,
                                  virSecurityLabelPtr sec)
1104 1105 1106
{
    security_context_t ctx;

M
Martin Kletzander 已提交
1107
    if (getpidcon_raw(pid, &ctx) == -1) {
1108
        virReportSystemError(errno,
1109
                             _("unable to get PID %d security context"),
1110
                             pid);
1111 1112 1113 1114
        return -1;
    }

    if (strlen((char *) ctx) >= VIR_SECURITY_LABEL_BUFLEN) {
1115 1116 1117 1118
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("security label exceeds "
                         "maximum length: %d"),
                       VIR_SECURITY_LABEL_BUFLEN - 1);
1119
        freecon(ctx);
1120 1121 1122 1123
        return -1;
    }

    strcpy(sec->label, (char *) ctx);
1124
    freecon(ctx);
1125

1126
    VIR_DEBUG("label=%s", sec->label);
1127 1128
    sec->enforcing = security_getenforce();
    if (sec->enforcing == -1) {
1129
        virReportSystemError(errno, "%s",
1130
                             _("error calling security_getenforce()"));
1131 1132 1133 1134 1135 1136
        return -1;
    }

    return 0;
}

1137 1138 1139
/* 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.  */
1140
static int
1141
virSecuritySELinuxSetFileconHelper(const char *path, const char *tcon,
1142
                                   bool optional, bool privileged)
1143
{
1144
    security_context_t econ;
1145 1146 1147 1148 1149 1150 1151 1152 1153
    int rc;

    /* Be aware that this function might run in a separate process.
     * Therefore, any driver state changes would be thrown away. */

    if ((rc = virSecuritySELinuxTransactionAppend(path, tcon, optional)) < 0)
        return -1;
    else if (rc > 0)
        return 0;
1154

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

1157
    if (setfilecon_raw(path, (VIR_SELINUX_CTX_CONST char *) tcon) < 0) {
1158 1159
        int setfilecon_errno = errno;

M
Martin Kletzander 已提交
1160
        if (getfilecon_raw(path, &econ) >= 0) {
1161 1162 1163
            if (STREQ(tcon, econ)) {
                freecon(econ);
                /* It's alright, there's nothing to change anyway. */
1164
                return optional ? 1 : 0;
1165 1166 1167
            }
            freecon(econ);
        }
1168

1169 1170 1171 1172 1173
        /* If the error complaint is related to an image hosted on a (possibly
         * read-only) NFS mount, or a usbfs/sysfs filesystem not supporting
         * labelling, then just ignore it & hope for the best.  The user
         * hopefully sets one of the necessary SELinux virt_use_{nfs,usb,pci}
         * boolean tunables to allow it ...
1174
         */
1175
        VIR_WARNINGS_NO_WLOGICALOP_EQUAL_EXPR
1176 1177
        if (setfilecon_errno != EOPNOTSUPP && setfilecon_errno != ENOTSUP &&
            setfilecon_errno != EROFS) {
1178
        VIR_WARNINGS_RESET
1179
            virReportSystemError(setfilecon_errno,
1180
                                 _("unable to set security context '%s' on '%s'"),
1181
                                 tcon, path);
1182 1183 1184 1185
            /* However, don't claim error if SELinux is in Enforcing mode and
             * we are running as unprivileged user and we really did see EPERM.
             * Otherwise we want to return error if SELinux is Enforcing. */
            if (security_getenforce() == 1 && (setfilecon_errno != EPERM || privileged))
1186
                return -1;
1187
        } else {
1188
            const char *msg;
1189
            if (virFileIsSharedFSType(path, VIR_FILE_SHFS_NFS) == 1 &&
1190 1191 1192
                security_get_boolean_active("virt_use_nfs") != 1) {
                msg = _("Setting security context '%s' on '%s' not supported. "
                        "Consider setting virt_use_nfs");
1193 1194 1195 1196
                if (security_getenforce() == 1)
                    VIR_WARN(msg, tcon, path);
                else
                    VIR_INFO(msg, tcon, path);
1197 1198 1199 1200
            } else {
                VIR_INFO("Setting security context '%s' on '%s' not supported",
                         tcon, path);
            }
1201 1202
            if (optional)
                return 1;
1203
        }
1204 1205 1206 1207
    }
    return 0;
}

1208
static int
1209
virSecuritySELinuxSetFileconOptional(virSecurityManagerPtr mgr,
1210
                                     const char *path, const char *tcon)
1211
{
1212 1213
    bool privileged = virSecurityManagerGetPrivileged(mgr);
    return virSecuritySELinuxSetFileconHelper(path, tcon, true, privileged);
1214 1215 1216
}

static int
1217
virSecuritySELinuxSetFilecon(virSecurityManagerPtr mgr,
1218
                             const char *path, const char *tcon)
1219
{
1220 1221
    bool privileged = virSecurityManagerGetPrivileged(mgr);
    return virSecuritySELinuxSetFileconHelper(path, tcon, false, privileged);
1222 1223
}

1224
static int
1225
virSecuritySELinuxFSetFilecon(int fd, char *tcon)
1226 1227 1228 1229 1230
{
    security_context_t econ;

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

M
Martin Kletzander 已提交
1231
    if (fsetfilecon_raw(fd, tcon) < 0) {
1232 1233
        int fsetfilecon_errno = errno;

M
Martin Kletzander 已提交
1234
        if (fgetfilecon_raw(fd, &econ) >= 0) {
1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262
            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 已提交
1263 1264
/* Set fcon to the appropriate label for path and mode, or return -1.  */
static int
1265
getContext(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
1266
           const char *newpath, mode_t mode, security_context_t *fcon)
E
Eric Blake 已提交
1267 1268
{
#if HAVE_SELINUX_LABEL_H
1269
    virSecuritySELinuxDataPtr data = virSecurityManagerGetPrivateData(mgr);
E
Eric Blake 已提交
1270

1271
    return selabel_lookup_raw(data->label_handle, fcon, newpath, mode);
E
Eric Blake 已提交
1272 1273 1274 1275 1276
#else
    return matchpathcon(newpath, mode, fcon);
#endif
}

1277 1278 1279

/* This method shouldn't raise errors, since they'll overwrite
 * errors that the caller(s) are already dealing with */
1280
static int
1281 1282
virSecuritySELinuxRestoreFileLabel(virSecurityManagerPtr mgr,
                                   const char *path)
1283
{
1284 1285 1286 1287
    struct stat buf;
    security_context_t fcon = NULL;
    int rc = -1;
    char *newpath = NULL;
1288
    char ebuf[1024];
1289

1290 1291 1292 1293 1294 1295
    /* Some paths are auto-generated, so let's be safe here and do
     * nothing if nothing is needed.
     */
    if (!path)
        return 0;

1296 1297
    VIR_INFO("Restoring SELinux context on '%s'", path);

1298
    if (virFileResolveLink(path, &newpath) < 0) {
1299 1300
        VIR_WARN("cannot resolve symlink %s: %s", path,
                 virStrerror(errno, ebuf, sizeof(ebuf)));
D
Daniel P. Berrange 已提交
1301
        goto err;
1302
    }
1303

1304
    if (stat(newpath, &buf) != 0) {
1305 1306
        VIR_WARN("cannot stat %s: %s", newpath,
                 virStrerror(errno, ebuf, sizeof(ebuf)));
D
Daniel P. Berrange 已提交
1307
        goto err;
1308
    }
D
Daniel P. Berrange 已提交
1309

1310
    if (getContext(mgr, newpath, buf.st_mode, &fcon) < 0) {
1311 1312 1313
        /* Any user created path likely does not have a default label,
         * which makes this an expected non error
         */
1314
        VIR_WARN("cannot lookup default selinux label for %s", newpath);
1315
        rc = 0;
1316
    } else {
1317
        rc = virSecuritySELinuxSetFilecon(mgr, newpath, fcon);
1318
    }
1319

1320
 err:
1321
    freecon(fcon);
1322 1323
    VIR_FREE(newpath);
    return rc;
1324 1325
}

1326

1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369
static int
virSecuritySELinuxSetInputLabel(virSecurityManagerPtr mgr,
                                virDomainDefPtr def,
                                virDomainInputDefPtr input)
{
    virSecurityLabelDefPtr seclabel;

    seclabel = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
    if (seclabel == NULL)
        return 0;

    switch ((virDomainInputType) input->type) {
    case VIR_DOMAIN_INPUT_TYPE_PASSTHROUGH:
        if (virSecuritySELinuxSetFilecon(mgr, input->source.evdev,
                                         seclabel->imagelabel) < 0)
            return -1;
        break;

    case VIR_DOMAIN_INPUT_TYPE_MOUSE:
    case VIR_DOMAIN_INPUT_TYPE_TABLET:
    case VIR_DOMAIN_INPUT_TYPE_KBD:
    case VIR_DOMAIN_INPUT_TYPE_LAST:
        break;
    }

    return 0;
}


static int
virSecuritySELinuxRestoreInputLabel(virSecurityManagerPtr mgr,
                                    virDomainDefPtr def,
                                    virDomainInputDefPtr input)
{
    int rc = 0;
    virSecurityLabelDefPtr seclabel;

    seclabel = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
    if (seclabel == NULL)
        return 0;

    switch ((virDomainInputType) input->type) {
    case VIR_DOMAIN_INPUT_TYPE_PASSTHROUGH:
1370
        rc = virSecuritySELinuxRestoreFileLabel(mgr, input->source.evdev);
1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383
        break;

    case VIR_DOMAIN_INPUT_TYPE_MOUSE:
    case VIR_DOMAIN_INPUT_TYPE_TABLET:
    case VIR_DOMAIN_INPUT_TYPE_KBD:
    case VIR_DOMAIN_INPUT_TYPE_LAST:
        break;
    }

    return rc;
}


1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439
static int
virSecuritySELinuxSetMemoryLabel(virSecurityManagerPtr mgr,
                                 virDomainDefPtr def,
                                 virDomainMemoryDefPtr mem)
{
    virSecurityLabelDefPtr seclabel;

    switch ((virDomainMemoryModel) mem->model) {
    case VIR_DOMAIN_MEMORY_MODEL_NVDIMM:
        seclabel = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
        if (!seclabel || !seclabel->relabel)
            return 0;

        if (virSecuritySELinuxSetFilecon(mgr, mem->nvdimmPath,
                                         seclabel->imagelabel) < 0)
            return -1;
        break;

    case VIR_DOMAIN_MEMORY_MODEL_NONE:
    case VIR_DOMAIN_MEMORY_MODEL_DIMM:
    case VIR_DOMAIN_MEMORY_MODEL_LAST:
        break;
    }

    return 0;
}


static int
virSecuritySELinuxRestoreMemoryLabel(virSecurityManagerPtr mgr,
                                     virDomainDefPtr def,
                                     virDomainMemoryDefPtr mem)
{
    int ret = -1;
    virSecurityLabelDefPtr seclabel;

    switch ((virDomainMemoryModel) mem->model) {
    case VIR_DOMAIN_MEMORY_MODEL_NVDIMM:
        seclabel = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
        if (!seclabel || !seclabel->relabel)
            return 0;

        ret = virSecuritySELinuxRestoreFileLabel(mgr, mem->nvdimmPath);
        break;

    case VIR_DOMAIN_MEMORY_MODEL_DIMM:
    case VIR_DOMAIN_MEMORY_MODEL_NONE:
    case VIR_DOMAIN_MEMORY_MODEL_LAST:
        ret = 0;
        break;
    }

    return ret;
}


1440
static int
1441 1442 1443
virSecuritySELinuxSetTPMFileLabel(virSecurityManagerPtr mgr,
                                  virDomainDefPtr def,
                                  virDomainTPMDefPtr tpm)
1444 1445 1446 1447 1448 1449 1450 1451
{
    int rc;
    virSecurityLabelDefPtr seclabel;
    char *cancel_path;
    const char *tpmdev;

    seclabel = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
    if (seclabel == NULL)
1452
        return 0;
1453 1454 1455 1456

    switch (tpm->type) {
    case VIR_DOMAIN_TPM_TYPE_PASSTHROUGH:
        tpmdev = tpm->data.passthrough.source.data.file.path;
1457
        rc = virSecuritySELinuxSetFilecon(mgr, tpmdev, seclabel->imagelabel);
1458 1459 1460 1461
        if (rc < 0)
            return -1;

        if ((cancel_path = virTPMCreateCancelPath(tpmdev)) != NULL) {
1462 1463
            rc = virSecuritySELinuxSetFilecon(mgr,
                                              cancel_path,
1464 1465 1466
                                              seclabel->imagelabel);
            VIR_FREE(cancel_path);
            if (rc < 0) {
1467
                virSecuritySELinuxRestoreTPMFileLabelInt(mgr, def, tpm);
1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482
                return -1;
            }
        } else {
            return -1;
        }
        break;
    case VIR_DOMAIN_TPM_TYPE_LAST:
        break;
    }

    return 0;
}


static int
1483 1484 1485
virSecuritySELinuxRestoreTPMFileLabelInt(virSecurityManagerPtr mgr,
                                         virDomainDefPtr def,
                                         virDomainTPMDefPtr tpm)
1486 1487 1488 1489 1490 1491 1492 1493
{
    int rc = 0;
    virSecurityLabelDefPtr seclabel;
    char *cancel_path;
    const char *tpmdev;

    seclabel = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
    if (seclabel == NULL)
1494
        return 0;
1495 1496 1497 1498

    switch (tpm->type) {
    case VIR_DOMAIN_TPM_TYPE_PASSTHROUGH:
        tpmdev = tpm->data.passthrough.source.data.file.path;
1499
        rc = virSecuritySELinuxRestoreFileLabel(mgr, tpmdev);
1500 1501

        if ((cancel_path = virTPMCreateCancelPath(tpmdev)) != NULL) {
1502
            if (virSecuritySELinuxRestoreFileLabel(mgr, cancel_path) < 0)
1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514
                rc = -1;
            VIR_FREE(cancel_path);
        }
        break;
    case VIR_DOMAIN_TPM_TYPE_LAST:
        break;
    }

    return rc;
}


1515
static int
1516 1517 1518 1519
virSecuritySELinuxRestoreImageLabelInt(virSecurityManagerPtr mgr,
                                       virDomainDefPtr def,
                                       virStorageSourcePtr src,
                                       bool migrated)
1520
{
1521 1522
    virSecurityLabelDefPtr seclabel;
    virSecurityDeviceLabelDefPtr disk_seclabel;
1523 1524 1525

    if (!src->path || !virStorageSourceIsLocalStorage(src))
        return 0;
1526 1527 1528

    seclabel = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
    if (seclabel == NULL)
1529
        return 0;
1530

1531
    disk_seclabel = virStorageSourceGetSecurityLabelDef(src,
1532
                                                        SECURITY_SELINUX_NAME);
1533
    if (!seclabel->relabel || (disk_seclabel && !disk_seclabel->relabel))
1534 1535
        return 0;

1536 1537 1538
    /* If labelskip is true and there are no backing files, then we
     * know it is safe to skip the restore.  FIXME - backing files should
     * be tracked in domain XML, at which point labelskip should be a
1539
     * per-file attribute instead of a disk attribute. */
1540
    if (disk_seclabel && disk_seclabel->labelskip &&
1541
        !src->backingStore)
1542 1543
        return 0;

1544
    /* Don't restore labels on readonly/shared disks, because other VMs may
1545 1546 1547 1548 1549
     * 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 (src->readonly || src->shared)
1550 1551 1552
        return 0;


1553 1554 1555
    /* If we have a shared FS and are doing migration, 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 :-) */
1556
    if (migrated) {
1557
        int rc = virFileIsSharedFS(src->path);
1558 1559 1560 1561
        if (rc < 0)
            return -1;
        if (rc == 1) {
            VIR_DEBUG("Skipping image label restore on %s because FS is shared",
1562
                      src->path);
1563 1564 1565 1566
            return 0;
        }
    }

1567
    return virSecuritySELinuxRestoreFileLabel(mgr, src->path);
1568 1569
}

1570 1571

static int
1572 1573 1574
virSecuritySELinuxRestoreDiskLabel(virSecurityManagerPtr mgr,
                                   virDomainDefPtr def,
                                   virDomainDiskDefPtr disk)
1575
{
1576 1577
    return virSecuritySELinuxRestoreImageLabelInt(mgr, def, disk->src,
                                                  false);
1578 1579 1580 1581
}


static int
1582 1583 1584
virSecuritySELinuxRestoreImageLabel(virSecurityManagerPtr mgr,
                                    virDomainDefPtr def,
                                    virStorageSourcePtr src)
1585
{
1586
    return virSecuritySELinuxRestoreImageLabelInt(mgr, def, src, false);
1587 1588 1589
}


1590
static int
1591 1592 1593 1594
virSecuritySELinuxSetImageLabelInternal(virSecurityManagerPtr mgr,
                                        virDomainDefPtr def,
                                        virStorageSourcePtr src,
                                        bool first)
1595
{
1596 1597
    virSecuritySELinuxDataPtr data = virSecurityManagerGetPrivateData(mgr);
    virSecurityLabelDefPtr secdef;
1598
    virSecurityDeviceLabelDefPtr disk_seclabel;
1599
    int ret;
1600

1601 1602 1603 1604
    if (!src->path || !virStorageSourceIsLocalStorage(src))
        return 0;

    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
1605
    if (!secdef || !secdef->relabel)
1606 1607 1608
        return 0;

    disk_seclabel = virStorageSourceGetSecurityLabelDef(src,
1609 1610
                                                        SECURITY_SELINUX_NAME);

1611
    if (disk_seclabel && !disk_seclabel->relabel)
1612 1613
        return 0;

1614
    if (disk_seclabel && disk_seclabel->relabel && disk_seclabel->label) {
1615
        ret = virSecuritySELinuxSetFilecon(mgr, src->path, disk_seclabel->label);
1616 1617
    } else if (first) {
        if (src->shared) {
1618 1619
            ret = virSecuritySELinuxSetFileconOptional(mgr,
                                                       src->path,
1620 1621
                                                       data->file_context);
        } else if (src->readonly) {
1622 1623
            ret = virSecuritySELinuxSetFileconOptional(mgr,
                                                       src->path,
1624
                                                       data->content_context);
1625
        } else if (secdef->imagelabel) {
1626 1627
            ret = virSecuritySELinuxSetFileconOptional(mgr,
                                                       src->path,
1628
                                                       secdef->imagelabel);
1629
        } else {
1630
            ret = 0;
1631 1632
        }
    } else {
1633 1634
        ret = virSecuritySELinuxSetFileconOptional(mgr,
                                                   src->path,
1635
                                                   data->content_context);
1636
    }
1637

1638
    if (ret == 1 && !disk_seclabel) {
1639 1640
        /* If we failed to set a label, but virt_use_nfs let us
         * proceed anyway, then we don't need to relabel later.  */
1641
        disk_seclabel = virSecurityDeviceLabelDefNew(SECURITY_SELINUX_NAME);
1642
        if (!disk_seclabel)
1643
            return -1;
1644
        disk_seclabel->labelskip = true;
1645
        if (VIR_APPEND_ELEMENT(src->seclabels, src->nseclabels,
1646
                               disk_seclabel) < 0) {
1647 1648 1649
            virSecurityDeviceLabelDefFree(disk_seclabel);
            return -1;
        }
1650
        ret = 0;
1651
    }
1652

1653
    return ret;
1654 1655
}

1656 1657

static int
1658 1659 1660
virSecuritySELinuxSetImageLabel(virSecurityManagerPtr mgr,
                                virDomainDefPtr def,
                                virStorageSourcePtr src)
1661
{
1662
    return virSecuritySELinuxSetImageLabelInternal(mgr, def, src, true);
1663 1664 1665
}


1666
static int
1667 1668 1669
virSecuritySELinuxSetDiskLabel(virSecurityManagerPtr mgr,
                               virDomainDefPtr def,
                               virDomainDiskDefPtr disk)
1670 1671

{
1672 1673
    bool first = true;
    virStorageSourcePtr next;
1674

1675
    for (next = disk->src; next; next = next->backingStore) {
1676
        if (virSecuritySELinuxSetImageLabelInternal(mgr, def, next, first) < 0)
1677
            return -1;
1678

1679 1680 1681 1682
        first = false;
    }

    return 0;
1683 1684
}

1685
static int
1686
virSecuritySELinuxSetHostdevLabelHelper(const char *file, void *opaque)
1687
{
1688
    virSecurityLabelDefPtr secdef;
1689 1690 1691
    virSecuritySELinuxCallbackDataPtr data = opaque;
    virSecurityManagerPtr mgr = data->mgr;
    virDomainDefPtr def = data->def;
1692

1693 1694
    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
    if (secdef == NULL)
1695
        return 0;
1696
    return virSecuritySELinuxSetFilecon(mgr, file, secdef->imagelabel);
1697 1698 1699
}

static int
1700 1701
virSecuritySELinuxSetPCILabel(virPCIDevicePtr dev ATTRIBUTE_UNUSED,
                              const char *file, void *opaque)
1702
{
1703
    return virSecuritySELinuxSetHostdevLabelHelper(file, opaque);
1704
}
1705

1706
static int
1707 1708
virSecuritySELinuxSetUSBLabel(virUSBDevicePtr dev ATTRIBUTE_UNUSED,
                              const char *file, void *opaque)
1709
{
1710
    return virSecuritySELinuxSetHostdevLabelHelper(file, opaque);
1711 1712
}

1713
static int
1714 1715
virSecuritySELinuxSetSCSILabel(virSCSIDevicePtr dev,
                               const char *file, void *opaque)
1716
{
1717
    virSecurityLabelDefPtr secdef;
1718
    virSecuritySELinuxCallbackDataPtr ptr = opaque;
1719 1720 1721 1722 1723 1724 1725 1726
    virSecurityManagerPtr mgr = ptr->mgr;
    virSecuritySELinuxDataPtr data = virSecurityManagerGetPrivateData(mgr);

    secdef = virDomainDefGetSecurityLabelDef(ptr->def, SECURITY_SELINUX_NAME);
    if (secdef == NULL)
        return 0;

    if (virSCSIDeviceGetShareable(dev))
1727
        return virSecuritySELinuxSetFileconOptional(mgr, file,
1728 1729
                                                    data->file_context);
    else if (virSCSIDeviceGetReadonly(dev))
1730
        return virSecuritySELinuxSetFileconOptional(mgr, file,
1731 1732
                                                    data->content_context);
    else
1733 1734
        return virSecuritySELinuxSetFileconOptional(mgr, file,
                                                    secdef->imagelabel);
1735
}
1736

1737 1738 1739 1740 1741 1742 1743
static int
virSecuritySELinuxSetHostLabel(virSCSIVHostDevicePtr dev ATTRIBUTE_UNUSED,
                               const char *file, void *opaque)
{
    return virSecuritySELinuxSetHostdevLabelHelper(file, opaque);
}

1744
static int
1745 1746 1747 1748
virSecuritySELinuxSetHostdevSubsysLabel(virSecurityManagerPtr mgr,
                                        virDomainDefPtr def,
                                        virDomainHostdevDefPtr dev,
                                        const char *vroot)
1749 1750

{
1751
    virDomainHostdevSubsysUSBPtr usbsrc = &dev->source.subsys.u.usb;
1752
    virDomainHostdevSubsysPCIPtr pcisrc = &dev->source.subsys.u.pci;
1753
    virDomainHostdevSubsysSCSIPtr scsisrc = &dev->source.subsys.u.scsi;
1754
    virDomainHostdevSubsysSCSIVHostPtr hostsrc = &dev->source.subsys.u.scsi_host;
1755 1756
    virSecuritySELinuxCallbackData data = {.mgr = mgr, .def = def};

1757 1758
    int ret = -1;

1759
    /* Like virSecuritySELinuxSetImageLabelInternal() for a networked
1760 1761
     * disk, do nothing for an iSCSI hostdev
     */
1762 1763
    if (dev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI &&
        scsisrc->protocol == VIR_DOMAIN_HOSTDEV_SCSI_PROTOCOL_TYPE_ISCSI)
1764 1765
        return 0;

1766
    switch ((virDomainHostdevSubsysType) dev->source.subsys.type) {
1767
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB: {
1768
        virUSBDevicePtr usb;
1769

1770 1771 1772
        if (dev->missing)
            return 0;

1773 1774
        usb = virUSBDeviceNew(usbsrc->bus,
                              usbsrc->device,
1775
                              vroot);
1776 1777
        if (!usb)
            goto done;
1778

1779
        ret = virUSBDeviceFileIterate(usb, virSecuritySELinuxSetUSBLabel, &data);
1780
        virUSBDeviceFree(usb);
M
Mark McLoughlin 已提交
1781
        break;
1782 1783 1784
    }

    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI: {
1785
        virPCIDevicePtr pci =
1786 1787
            virPCIDeviceNew(pcisrc->addr.domain, pcisrc->addr.bus,
                            pcisrc->addr.slot, pcisrc->addr.function);
1788 1789 1790 1791

        if (!pci)
            goto done;

1792
        if (pcisrc->backend == VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO) {
1793
            char *vfioGroupDev = virPCIDeviceGetIOMMUGroupDev(pci);
1794

1795 1796
            if (!vfioGroupDev) {
                virPCIDeviceFree(pci);
1797
                goto done;
1798
            }
1799
            ret = virSecuritySELinuxSetPCILabel(pci, vfioGroupDev, &data);
1800 1801
            VIR_FREE(vfioGroupDev);
        } else {
1802
            ret = virPCIDeviceFileIterate(pci, virSecuritySELinuxSetPCILabel, &data);
1803
        }
1804
        virPCIDeviceFree(pci);
1805 1806 1807
        break;
    }

1808
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI: {
1809
        virDomainHostdevSubsysSCSIHostPtr scsihostsrc = &scsisrc->u.host;
1810

1811
        virSCSIDevicePtr scsi =
1812
            virSCSIDeviceNew(NULL,
1813 1814
                             scsihostsrc->adapter, scsihostsrc->bus,
                             scsihostsrc->target, scsihostsrc->unit,
1815
                             dev->readonly, dev->shareable);
1816 1817 1818 1819

        if (!scsi)
            goto done;

1820
        ret = virSCSIDeviceFileIterate(scsi,
1821
                                       virSecuritySELinuxSetSCSILabel,
1822
                                       &data);
1823 1824 1825 1826 1827
        virSCSIDeviceFree(scsi);

        break;
    }

1828
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI_HOST: {
1829 1830 1831 1832 1833 1834 1835 1836 1837 1838
        virSCSIVHostDevicePtr host = virSCSIVHostDeviceNew(hostsrc->wwpn);

        if (!host)
            goto done;

        ret = virSCSIVHostDeviceFileIterate(host,
                                            virSecuritySELinuxSetHostLabel,
                                            &data);
        virSCSIVHostDeviceFree(host);
        break;
1839 1840
    }

1841
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_MDEV:
1842
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST:
1843 1844 1845 1846
        ret = 0;
        break;
    }

1847
 done:
1848 1849 1850
    return ret;
}

1851

1852
static int
1853 1854 1855 1856
virSecuritySELinuxSetHostdevCapsLabel(virSecurityManagerPtr mgr,
                                      virDomainDefPtr def,
                                      virDomainHostdevDefPtr dev,
                                      const char *vroot)
1857 1858 1859 1860 1861 1862 1863
{
    int ret = -1;
    virSecurityLabelDefPtr secdef;
    char *path;

    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
    if (secdef == NULL)
1864
        return 0;
1865 1866 1867 1868 1869

    switch (dev->source.caps.type) {
    case VIR_DOMAIN_HOSTDEV_CAPS_TYPE_STORAGE: {
        if (vroot) {
            if (virAsprintf(&path, "%s/%s", vroot,
1870
                            dev->source.caps.u.storage.block) < 0)
1871 1872
                return -1;
        } else {
1873
            if (VIR_STRDUP(path, dev->source.caps.u.storage.block) < 0)
1874 1875
                return -1;
        }
1876
        ret = virSecuritySELinuxSetFilecon(mgr, path, secdef->imagelabel);
1877 1878 1879 1880 1881 1882 1883
        VIR_FREE(path);
        break;
    }

    case VIR_DOMAIN_HOSTDEV_CAPS_TYPE_MISC: {
        if (vroot) {
            if (virAsprintf(&path, "%s/%s", vroot,
1884
                            dev->source.caps.u.misc.chardev) < 0)
1885 1886
                return -1;
        } else {
1887
            if (VIR_STRDUP(path, dev->source.caps.u.misc.chardev) < 0)
1888 1889
                return -1;
        }
1890
        ret = virSecuritySELinuxSetFilecon(mgr, path, secdef->imagelabel);
1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903
        VIR_FREE(path);
        break;
    }

    default:
        ret = 0;
        break;
    }

    return ret;
}


1904
static int
1905 1906 1907 1908
virSecuritySELinuxSetHostdevLabel(virSecurityManagerPtr mgr,
                                  virDomainDefPtr def,
                                  virDomainHostdevDefPtr dev,
                                  const char *vroot)
1909 1910 1911 1912 1913

{
    virSecurityLabelDefPtr secdef;

    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
1914
    if (!secdef || !secdef->relabel)
1915 1916 1917 1918
        return 0;

    switch (dev->mode) {
    case VIR_DOMAIN_HOSTDEV_MODE_SUBSYS:
1919
        return virSecuritySELinuxSetHostdevSubsysLabel(mgr, def, dev, vroot);
1920

1921
    case VIR_DOMAIN_HOSTDEV_MODE_CAPABILITIES:
1922
        return virSecuritySELinuxSetHostdevCapsLabel(mgr, def, dev, vroot);
1923

1924 1925 1926 1927 1928
    default:
        return 0;
    }
}

1929
static int
1930 1931 1932
virSecuritySELinuxRestorePCILabel(virPCIDevicePtr dev ATTRIBUTE_UNUSED,
                                  const char *file,
                                  void *opaque)
1933
{
1934 1935
    virSecurityManagerPtr mgr = opaque;

1936
    return virSecuritySELinuxRestoreFileLabel(mgr, file);
1937 1938 1939
}

static int
1940 1941 1942
virSecuritySELinuxRestoreUSBLabel(virUSBDevicePtr dev ATTRIBUTE_UNUSED,
                                  const char *file,
                                  void *opaque)
1943
{
1944 1945
    virSecurityManagerPtr mgr = opaque;

1946
    return virSecuritySELinuxRestoreFileLabel(mgr, file);
1947 1948
}

1949

1950
static int
1951 1952 1953
virSecuritySELinuxRestoreSCSILabel(virSCSIDevicePtr dev,
                                   const char *file,
                                   void *opaque)
1954 1955 1956
{
    virSecurityManagerPtr mgr = opaque;

1957 1958 1959 1960 1961 1962
    /* Don't restore labels on a shareable or readonly hostdev, because
     * other VMs may still be accessing.
     */
    if (virSCSIDeviceGetShareable(dev) || virSCSIDeviceGetReadonly(dev))
        return 0;

1963
    return virSecuritySELinuxRestoreFileLabel(mgr, file);
1964 1965
}

1966 1967 1968 1969 1970 1971 1972 1973 1974 1975
static int
virSecuritySELinuxRestoreHostLabel(virSCSIVHostDevicePtr dev ATTRIBUTE_UNUSED,
                                   const char *file,
                                   void *opaque)
{
    virSecurityManagerPtr mgr = opaque;

    return virSecuritySELinuxRestoreFileLabel(mgr, file);
}

1976
static int
1977 1978 1979
virSecuritySELinuxRestoreHostdevSubsysLabel(virSecurityManagerPtr mgr,
                                            virDomainHostdevDefPtr dev,
                                            const char *vroot)
1980 1981

{
1982
    virDomainHostdevSubsysUSBPtr usbsrc = &dev->source.subsys.u.usb;
1983
    virDomainHostdevSubsysPCIPtr pcisrc = &dev->source.subsys.u.pci;
1984
    virDomainHostdevSubsysSCSIPtr scsisrc = &dev->source.subsys.u.scsi;
1985
    virDomainHostdevSubsysSCSIVHostPtr hostsrc = &dev->source.subsys.u.scsi_host;
1986 1987
    int ret = -1;

1988
    /* Like virSecuritySELinuxRestoreImageLabelInt() for a networked
1989 1990
     * disk, do nothing for an iSCSI hostdev
     */
1991 1992
    if (dev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI &&
        scsisrc->protocol == VIR_DOMAIN_HOSTDEV_SCSI_PROTOCOL_TYPE_ISCSI)
1993 1994
        return 0;

1995
    switch ((virDomainHostdevSubsysType) dev->source.subsys.type) {
1996
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB: {
1997
        virUSBDevicePtr usb;
1998 1999 2000

        if (dev->missing)
            return 0;
2001

2002 2003
        usb = virUSBDeviceNew(usbsrc->bus,
                              usbsrc->device,
2004
                              vroot);
2005 2006 2007
        if (!usb)
            goto done;

2008
        ret = virUSBDeviceFileIterate(usb, virSecuritySELinuxRestoreUSBLabel, mgr);
2009
        virUSBDeviceFree(usb);
2010 2011 2012 2013 2014

        break;
    }

    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI: {
2015
        virPCIDevicePtr pci =
2016 2017
            virPCIDeviceNew(pcisrc->addr.domain, pcisrc->addr.bus,
                            pcisrc->addr.slot, pcisrc->addr.function);
2018 2019 2020 2021

        if (!pci)
            goto done;

2022
        if (pcisrc->backend == VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO) {
2023
            char *vfioGroupDev = virPCIDeviceGetIOMMUGroupDev(pci);
2024

2025 2026
            if (!vfioGroupDev) {
                virPCIDeviceFree(pci);
2027
                goto done;
2028
            }
2029
            ret = virSecuritySELinuxRestorePCILabel(pci, vfioGroupDev, mgr);
2030 2031
            VIR_FREE(vfioGroupDev);
        } else {
2032
            ret = virPCIDeviceFileIterate(pci, virSecuritySELinuxRestorePCILabel, mgr);
2033
        }
2034
        virPCIDeviceFree(pci);
2035 2036 2037
        break;
    }

2038
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI: {
2039
        virDomainHostdevSubsysSCSIHostPtr scsihostsrc = &scsisrc->u.host;
2040
        virSCSIDevicePtr scsi =
2041
            virSCSIDeviceNew(NULL,
2042 2043
                             scsihostsrc->adapter, scsihostsrc->bus,
                             scsihostsrc->target, scsihostsrc->unit,
2044
                             dev->readonly, dev->shareable);
2045

J
Ján Tomko 已提交
2046 2047
        if (!scsi)
            goto done;
2048

2049
        ret = virSCSIDeviceFileIterate(scsi, virSecuritySELinuxRestoreSCSILabel, mgr);
J
Ján Tomko 已提交
2050
        virSCSIDeviceFree(scsi);
2051

J
Ján Tomko 已提交
2052 2053
        break;
    }
2054

2055
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI_HOST: {
2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066
        virSCSIVHostDevicePtr host = virSCSIVHostDeviceNew(hostsrc->wwpn);

        if (!host)
            goto done;

        ret = virSCSIVHostDeviceFileIterate(host,
                                            virSecuritySELinuxRestoreHostLabel,
                                            mgr);
        virSCSIVHostDeviceFree(host);

        break;
2067 2068
    }

2069
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_MDEV:
2070
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST:
2071 2072 2073 2074
        ret = 0;
        break;
    }

2075
 done:
2076 2077 2078
    return ret;
}

2079

2080
static int
2081 2082 2083
virSecuritySELinuxRestoreHostdevCapsLabel(virSecurityManagerPtr mgr,
                                          virDomainHostdevDefPtr dev,
                                          const char *vroot)
2084 2085 2086 2087 2088 2089 2090 2091
{
    int ret = -1;
    char *path;

    switch (dev->source.caps.type) {
    case VIR_DOMAIN_HOSTDEV_CAPS_TYPE_STORAGE: {
        if (vroot) {
            if (virAsprintf(&path, "%s/%s", vroot,
2092
                            dev->source.caps.u.storage.block) < 0)
2093 2094
                return -1;
        } else {
2095
            if (VIR_STRDUP(path, dev->source.caps.u.storage.block) < 0)
2096 2097
                return -1;
        }
2098
        ret = virSecuritySELinuxRestoreFileLabel(mgr, path);
2099 2100 2101 2102 2103 2104 2105
        VIR_FREE(path);
        break;
    }

    case VIR_DOMAIN_HOSTDEV_CAPS_TYPE_MISC: {
        if (vroot) {
            if (virAsprintf(&path, "%s/%s", vroot,
2106
                            dev->source.caps.u.misc.chardev) < 0)
2107 2108
                return -1;
        } else {
2109
            if (VIR_STRDUP(path, dev->source.caps.u.misc.chardev) < 0)
2110 2111
                return -1;
        }
2112
        ret = virSecuritySELinuxRestoreFileLabel(mgr, path);
2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125
        VIR_FREE(path);
        break;
    }

    default:
        ret = 0;
        break;
    }

    return ret;
}


2126
static int
2127 2128 2129 2130
virSecuritySELinuxRestoreHostdevLabel(virSecurityManagerPtr mgr,
                                      virDomainDefPtr def,
                                      virDomainHostdevDefPtr dev,
                                      const char *vroot)
2131 2132 2133 2134 2135

{
    virSecurityLabelDefPtr secdef;

    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
2136
    if (!secdef || !secdef->relabel)
2137 2138 2139 2140
        return 0;

    switch (dev->mode) {
    case VIR_DOMAIN_HOSTDEV_MODE_SUBSYS:
2141
        return virSecuritySELinuxRestoreHostdevSubsysLabel(mgr, dev, vroot);
2142

2143
    case VIR_DOMAIN_HOSTDEV_MODE_CAPABILITIES:
2144
        return virSecuritySELinuxRestoreHostdevCapsLabel(mgr, dev, vroot);
2145

2146 2147 2148 2149 2150 2151
    default:
        return 0;
    }
}


2152
static int
2153 2154 2155 2156
virSecuritySELinuxSetChardevLabel(virSecurityManagerPtr mgr,
                                  virDomainDefPtr def,
                                  virDomainChrDefPtr dev,
                                  virDomainChrSourceDefPtr dev_source)
2157 2158

{
2159 2160 2161
    virSecurityLabelDefPtr seclabel;
    virSecurityDeviceLabelDefPtr chr_seclabel = NULL;
    char *imagelabel = NULL;
2162 2163 2164
    char *in = NULL, *out = NULL;
    int ret = -1;

2165
    seclabel = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
2166
    if (!seclabel || !seclabel->relabel)
2167
        return 0;
2168

2169 2170 2171 2172
    if (dev)
        chr_seclabel = virDomainChrDefGetSecurityLabelDef(dev,
                                                          SECURITY_SELINUX_NAME);

2173
    if (chr_seclabel && !chr_seclabel->relabel)
2174 2175
        return 0;

2176 2177 2178 2179 2180 2181
    if (chr_seclabel)
        imagelabel = chr_seclabel->label;
    if (!imagelabel)
        imagelabel = seclabel->imagelabel;

    switch (dev_source->type) {
2182 2183
    case VIR_DOMAIN_CHR_TYPE_DEV:
    case VIR_DOMAIN_CHR_TYPE_FILE:
2184 2185
        ret = virSecuritySELinuxSetFilecon(mgr,
                                           dev_source->data.file.path,
2186 2187 2188 2189 2190
                                           imagelabel);
        break;

    case VIR_DOMAIN_CHR_TYPE_UNIX:
        if (!dev_source->data.nix.listen) {
2191 2192
            if (virSecuritySELinuxSetFilecon(mgr,
                                             dev_source->data.nix.path,
2193 2194 2195 2196
                                             imagelabel) < 0)
                goto done;
        }
        ret = 0;
2197 2198 2199
        break;

    case VIR_DOMAIN_CHR_TYPE_PIPE:
2200
        if ((virAsprintf(&in, "%s.in", dev_source->data.file.path) < 0) ||
2201
            (virAsprintf(&out, "%s.out", dev_source->data.file.path) < 0))
2202 2203
            goto done;
        if (virFileExists(in) && virFileExists(out)) {
2204 2205
            if ((virSecuritySELinuxSetFilecon(mgr, in, imagelabel) < 0) ||
                (virSecuritySELinuxSetFilecon(mgr, out, imagelabel) < 0)) {
2206
                goto done;
2207
            }
2208 2209
        } else if (virSecuritySELinuxSetFilecon(mgr,
                                                dev_source->data.file.path,
2210
                                                imagelabel) < 0) {
2211
            goto done;
2212 2213 2214 2215 2216 2217 2218 2219 2220
        }
        ret = 0;
        break;

    default:
        ret = 0;
        break;
    }

2221
 done:
2222 2223 2224 2225 2226 2227
    VIR_FREE(in);
    VIR_FREE(out);
    return ret;
}

static int
2228 2229 2230 2231
virSecuritySELinuxRestoreChardevLabel(virSecurityManagerPtr mgr,
                                      virDomainDefPtr def,
                                      virDomainChrDefPtr dev,
                                      virDomainChrSourceDefPtr dev_source)
2232 2233

{
2234 2235
    virSecurityLabelDefPtr seclabel;
    virSecurityDeviceLabelDefPtr chr_seclabel = NULL;
2236 2237 2238
    char *in = NULL, *out = NULL;
    int ret = -1;

2239
    seclabel = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
2240
    if (!seclabel || !seclabel->relabel)
2241
        return 0;
2242

2243 2244 2245
    if (dev)
        chr_seclabel = virDomainChrDefGetSecurityLabelDef(dev,
                                                          SECURITY_SELINUX_NAME);
2246
    if (chr_seclabel && !chr_seclabel->relabel)
2247 2248
        return 0;

2249
    switch (dev_source->type) {
2250 2251
    case VIR_DOMAIN_CHR_TYPE_DEV:
    case VIR_DOMAIN_CHR_TYPE_FILE:
2252
        if (virSecuritySELinuxRestoreFileLabel(mgr, dev_source->data.file.path) < 0)
2253 2254
            goto done;
        ret = 0;
2255
        break;
2256 2257 2258

    case VIR_DOMAIN_CHR_TYPE_UNIX:
        if (!dev_source->data.nix.listen) {
2259
            if (virSecuritySELinuxRestoreFileLabel(mgr, dev_source->data.file.path) < 0)
2260 2261 2262 2263 2264
                goto done;
        }
        ret = 0;
        break;

2265
    case VIR_DOMAIN_CHR_TYPE_PIPE:
2266
        if ((virAsprintf(&out, "%s.out", dev_source->data.file.path) < 0) ||
2267
            (virAsprintf(&in, "%s.in", dev_source->data.file.path) < 0))
2268
            goto done;
2269
        if (virFileExists(in) && virFileExists(out)) {
2270 2271
            if ((virSecuritySELinuxRestoreFileLabel(mgr, out) < 0) ||
                (virSecuritySELinuxRestoreFileLabel(mgr, in) < 0)) {
2272 2273
                goto done;
            }
2274
        } else if (virSecuritySELinuxRestoreFileLabel(mgr, dev_source->data.file.path) < 0) {
2275
            goto done;
2276
        }
2277 2278 2279 2280 2281 2282 2283 2284
        ret = 0;
        break;

    default:
        ret = 0;
        break;
    }

2285
 done:
2286 2287 2288 2289 2290 2291 2292
    VIR_FREE(in);
    VIR_FREE(out);
    return ret;
}


static int
2293 2294
virSecuritySELinuxRestoreSecurityChardevCallback(virDomainDefPtr def,
                                                 virDomainChrDefPtr dev,
2295
                                                 void *opaque)
2296
{
2297 2298
    virSecurityManagerPtr mgr = opaque;

2299 2300 2301 2302 2303
    /* 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;

2304
    return virSecuritySELinuxRestoreChardevLabel(mgr, def, dev, dev->source);
2305 2306 2307
}


E
Eric Blake 已提交
2308
static int
2309 2310
virSecuritySELinuxRestoreSecuritySmartcardCallback(virDomainDefPtr def,
                                                   virDomainSmartcardDefPtr dev,
2311
                                                   void *opaque)
E
Eric Blake 已提交
2312
{
2313
    virSecurityManagerPtr mgr = opaque;
E
Eric Blake 已提交
2314 2315 2316 2317 2318 2319 2320 2321 2322 2323
    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;
2324
        return virSecuritySELinuxRestoreFileLabel(mgr, database);
E
Eric Blake 已提交
2325 2326

    case VIR_DOMAIN_SMARTCARD_TYPE_PASSTHROUGH:
2327
        return virSecuritySELinuxRestoreChardevLabel(mgr, def, NULL, dev->data.passthru);
E
Eric Blake 已提交
2328 2329

    default:
2330 2331 2332
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unknown smartcard type %d"),
                       dev->type);
E
Eric Blake 已提交
2333 2334 2335 2336 2337 2338 2339
        return -1;
    }

    return 0;
}


2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350
static const char *
virSecuritySELinuxGetBaseLabel(virSecurityManagerPtr mgr, int virtType)
{
    virSecuritySELinuxDataPtr priv = virSecurityManagerGetPrivateData(mgr);
    if (virtType == VIR_DOMAIN_VIRT_QEMU && priv->alt_domain_context)
        return priv->alt_domain_context;
    else
        return priv->domain_context;
}


2351
static int
2352 2353 2354
virSecuritySELinuxRestoreAllLabel(virSecurityManagerPtr mgr,
                                  virDomainDefPtr def,
                                  bool migrated)
2355
{
2356
    virSecurityLabelDefPtr secdef;
2357
    virSecuritySELinuxDataPtr data = virSecurityManagerGetPrivateData(mgr);
2358
    size_t i;
2359
    int rc = 0;
2360

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

2363 2364
    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);

2365
    if (!secdef || !secdef->relabel || data->skipAllLabel)
2366 2367
        return 0;

2368
    if (def->tpm) {
2369
        if (virSecuritySELinuxRestoreTPMFileLabelInt(mgr, def, def->tpm) < 0)
2370 2371 2372
            rc = -1;
    }

2373
    for (i = 0; i < def->nhostdevs; i++) {
2374 2375 2376 2377
        if (virSecuritySELinuxRestoreHostdevLabel(mgr,
                                                  def,
                                                  def->hostdevs[i],
                                                  NULL) < 0)
2378
            rc = -1;
2379
    }
2380 2381 2382 2383 2384 2385

    for (i = 0; i < def->ninputs; i++) {
        if (virSecuritySELinuxRestoreInputLabel(mgr, def, def->inputs[i]) < 0)
            rc = -1;
    }

2386 2387 2388 2389 2390
    for (i = 0; i < def->nmems; i++) {
        if (virSecuritySELinuxRestoreMemoryLabel(mgr, def, def->mems[i]) < 0)
            return -1;
    }

2391
    for (i = 0; i < def->ndisks; i++) {
2392 2393
        virDomainDiskDefPtr disk = def->disks[i];

2394 2395
        if (virSecuritySELinuxRestoreImageLabelInt(mgr, def, disk->src,
                                                   migrated) < 0)
2396 2397
            rc = -1;
    }
2398

2399
    if (virDomainChrDefForeach(def,
2400
                               false,
2401
                               virSecuritySELinuxRestoreSecurityChardevCallback,
2402
                               mgr) < 0)
2403 2404
        rc = -1;

2405
    if (virDomainSmartcardDefForeach(def,
E
Eric Blake 已提交
2406
                                     false,
2407
                                     virSecuritySELinuxRestoreSecuritySmartcardCallback,
2408
                                     mgr) < 0)
E
Eric Blake 已提交
2409 2410
        rc = -1;

2411
    if (def->os.loader && def->os.loader->nvram &&
2412
        virSecuritySELinuxRestoreFileLabel(mgr, def->os.loader->nvram) < 0)
2413 2414
        rc = -1;

2415 2416 2417 2418
    return rc;
}

static int
2419 2420
virSecuritySELinuxReleaseLabel(virSecurityManagerPtr mgr,
                               virDomainDefPtr def)
2421
{
2422 2423 2424 2425
    virSecurityLabelDefPtr secdef;

    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
    if (secdef == NULL)
2426
        return 0;
2427

2428 2429 2430 2431
    if (secdef->type == VIR_DOMAIN_SECLABEL_DYNAMIC) {
        if (secdef->label != NULL) {
            context_t con = context_new(secdef->label);
            if (con) {
2432
                virSecuritySELinuxMCSRemove(mgr, context_range_get(con));
2433 2434 2435 2436 2437 2438
                context_free(con);
            }
        }
        VIR_FREE(secdef->label);
        if (!secdef->baselabel)
            VIR_FREE(secdef->model);
2439 2440 2441
    }
    VIR_FREE(secdef->imagelabel);

2442
    return 0;
2443 2444
}

2445 2446

static int
2447
virSecuritySELinuxSetSavedStateLabel(virSecurityManagerPtr mgr,
2448 2449
                                     virDomainDefPtr def,
                                     const char *savefile)
2450
{
2451 2452 2453
    virSecurityLabelDefPtr secdef;

    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
2454
    if (!secdef || !secdef->relabel)
2455 2456
        return 0;

2457
    return virSecuritySELinuxSetFilecon(mgr, savefile, secdef->imagelabel);
2458 2459 2460 2461
}


static int
2462
virSecuritySELinuxRestoreSavedStateLabel(virSecurityManagerPtr mgr,
2463 2464
                                         virDomainDefPtr def,
                                         const char *savefile)
2465
{
2466 2467 2468
    virSecurityLabelDefPtr secdef;

    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
2469
    if (!secdef || !secdef->relabel)
2470 2471
        return 0;

2472
    return virSecuritySELinuxRestoreFileLabel(mgr, savefile);
2473 2474 2475
}


2476
static int
2477 2478
virSecuritySELinuxVerify(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
                         virDomainDefPtr def)
2479
{
2480 2481 2482 2483
    virSecurityLabelDefPtr secdef;

    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
    if (secdef == NULL)
2484
        return 0;
2485

2486
    if (STRNEQ(SECURITY_SELINUX_NAME, secdef->model)) {
2487 2488 2489 2490
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("security label driver mismatch: "
                         "'%s' model configured for domain, but "
                         "hypervisor driver is '%s'."),
2491
                       secdef->model, SECURITY_SELINUX_NAME);
2492 2493 2494
        return -1;
    }

2495 2496
    if (secdef->type == VIR_DOMAIN_SECLABEL_STATIC) {
        if (security_check_context(secdef->label) != 0) {
2497 2498
            virReportError(VIR_ERR_XML_ERROR,
                           _("Invalid security label %s"), secdef->label);
2499 2500 2501 2502 2503 2504
            return -1;
        }
    }
    return 0;
}

2505
static int
2506 2507
virSecuritySELinuxSetProcessLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
                                  virDomainDefPtr def)
2508 2509
{
    /* TODO: verify DOI */
2510 2511 2512
    virSecurityLabelDefPtr secdef;

    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
2513
    if (!secdef || !secdef->label)
2514 2515
        return 0;

2516
    VIR_DEBUG("label=%s", secdef->label);
2517
    if (STRNEQ(SECURITY_SELINUX_NAME, secdef->model)) {
2518 2519 2520 2521
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("security label driver mismatch: "
                         "'%s' model configured for domain, but "
                         "hypervisor driver is '%s'."),
2522
                       secdef->model, SECURITY_SELINUX_NAME);
2523
        if (security_getenforce() == 1)
2524
            return -1;
2525 2526
    }

M
Martin Kletzander 已提交
2527
    if (setexeccon_raw(secdef->label) == -1) {
2528
        virReportSystemError(errno,
2529 2530
                             _("unable to set security context '%s'"),
                             secdef->label);
2531
        if (security_getenforce() == 1)
2532
            return -1;
2533 2534
    }

2535 2536 2537
    return 0;
}

2538
static int
2539 2540 2541
virSecuritySELinuxSetChildProcessLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
                                       virDomainDefPtr def,
                                       virCommandPtr cmd)
2542 2543 2544 2545 2546
{
    /* TODO: verify DOI */
    virSecurityLabelDefPtr secdef;

    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
2547
    if (!secdef || !secdef->label)
2548 2549 2550
        return 0;

    VIR_DEBUG("label=%s", secdef->label);
2551
    if (STRNEQ(SECURITY_SELINUX_NAME, secdef->model)) {
2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("security label driver mismatch: "
                         "'%s' model configured for domain, but "
                         "hypervisor driver is '%s'."),
                       secdef->model, SECURITY_SELINUX_NAME);
        if (security_getenforce() == 1)
            return -1;
    }

    /* save in cmd to be set after fork/before child process is exec'ed */
    virCommandSetSELinuxLabel(cmd, secdef->label);
    return 0;
}

2566
static int
2567 2568
virSecuritySELinuxSetDaemonSocketLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
                                       virDomainDefPtr def)
2569 2570
{
    /* TODO: verify DOI */
2571
    virSecurityLabelDefPtr secdef;
2572
    security_context_t scon = NULL;
2573
    char *str = NULL;
2574 2575
    int rc = -1;

2576
    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
2577
    if (!secdef || !secdef->label)
2578 2579
        return 0;

2580
    if (STRNEQ(SECURITY_SELINUX_NAME, secdef->model)) {
2581 2582 2583 2584
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("security label driver mismatch: "
                         "'%s' model configured for domain, but "
                         "hypervisor driver is '%s'."),
2585
                       secdef->model, SECURITY_SELINUX_NAME);
2586 2587 2588
        goto done;
    }

M
Martin Kletzander 已提交
2589
    if (getcon_raw(&scon) == -1) {
2590 2591 2592 2593 2594 2595
        virReportSystemError(errno,
                             _("unable to get current process context '%s'"),
                             secdef->label);
        goto done;
    }

2596
    if (!(str = virSecuritySELinuxContextAddRange(secdef->label, scon)))
2597 2598
        goto done;

2599 2600
    VIR_DEBUG("Setting VM %s socket context %s", def->name, str);
    if (setsockcreatecon_raw(str) == -1) {
2601
        virReportSystemError(errno,
2602
                             _("unable to set socket security context '%s'"), str);
2603 2604 2605 2606
        goto done;
    }

    rc = 0;
2607
 done:
2608 2609 2610 2611

    if (security_getenforce() != 1)
        rc = 0;
    freecon(scon);
2612
    VIR_FREE(str);
2613 2614 2615
    return rc;
}

2616
static int
2617 2618
virSecuritySELinuxSetSocketLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
                                 virDomainDefPtr vm)
2619
{
2620
    virSecurityLabelDefPtr secdef;
2621 2622
    int rc = -1;

2623
    secdef = virDomainDefGetSecurityLabelDef(vm, SECURITY_SELINUX_NAME);
2624
    if (!secdef || !secdef->label)
2625 2626
        return 0;

2627
    if (STRNEQ(SECURITY_SELINUX_NAME, secdef->model)) {
2628 2629 2630 2631
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("security label driver mismatch: "
                         "'%s' model configured for domain, but "
                         "hypervisor driver is '%s'."),
2632
                       secdef->model, SECURITY_SELINUX_NAME);
2633 2634 2635 2636
        goto done;
    }

    VIR_DEBUG("Setting VM %s socket context %s",
2637
              vm->name, secdef->label);
M
Martin Kletzander 已提交
2638
    if (setsockcreatecon_raw(secdef->label) == -1) {
2639 2640 2641 2642 2643 2644 2645 2646
        virReportSystemError(errno,
                             _("unable to set socket security context '%s'"),
                             secdef->label);
        goto done;
    }

    rc = 0;

2647
 done:
2648 2649 2650 2651 2652 2653
    if (security_getenforce() != 1)
        rc = 0;

    return rc;
}

2654
static int
2655 2656
virSecuritySELinuxClearSocketLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
                                   virDomainDefPtr def)
2657 2658
{
    /* TODO: verify DOI */
2659 2660 2661
    virSecurityLabelDefPtr secdef;

    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
2662
    if (!secdef || !secdef->label)
2663 2664
        return 0;

2665
    if (STRNEQ(SECURITY_SELINUX_NAME, secdef->model)) {
2666 2667 2668 2669
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("security label driver mismatch: "
                         "'%s' model configured for domain, but "
                         "hypervisor driver is '%s'."),
2670
                       secdef->model, SECURITY_SELINUX_NAME);
2671 2672 2673 2674
        if (security_getenforce() == 1)
            return -1;
    }

M
Martin Kletzander 已提交
2675
    if (setsockcreatecon_raw(NULL) == -1) {
2676 2677 2678 2679 2680 2681 2682 2683 2684
        virReportSystemError(errno,
                             _("unable to clear socket security context '%s'"),
                             secdef->label);
        if (security_getenforce() == 1)
            return -1;
    }
    return 0;
}

2685 2686

static int
2687 2688
virSecuritySELinuxSetSecurityChardevCallback(virDomainDefPtr def,
                                             virDomainChrDefPtr dev,
2689
                                             void *opaque)
2690
{
2691 2692
    virSecurityManagerPtr mgr = opaque;

2693 2694 2695 2696 2697
    /* 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;

2698
    return virSecuritySELinuxSetChardevLabel(mgr, def, dev, dev->source);
2699 2700 2701
}


E
Eric Blake 已提交
2702
static int
2703 2704 2705
virSecuritySELinuxSetSecuritySmartcardCallback(virDomainDefPtr def,
                                               virDomainSmartcardDefPtr dev,
                                               void *opaque)
E
Eric Blake 已提交
2706 2707
{
    const char *database;
2708 2709
    virSecurityManagerPtr mgr = opaque;
    virSecuritySELinuxDataPtr data = virSecurityManagerGetPrivateData(mgr);
E
Eric Blake 已提交
2710 2711 2712 2713 2714 2715 2716 2717 2718

    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;
2719
        return virSecuritySELinuxSetFilecon(mgr, database, data->content_context);
E
Eric Blake 已提交
2720 2721

    case VIR_DOMAIN_SMARTCARD_TYPE_PASSTHROUGH:
2722
        return virSecuritySELinuxSetChardevLabel(mgr, def, NULL,
2723
                                                 dev->data.passthru);
E
Eric Blake 已提交
2724 2725

    default:
2726 2727 2728
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unknown smartcard type %d"),
                       dev->type);
E
Eric Blake 已提交
2729 2730 2731 2732 2733 2734 2735
        return -1;
    }

    return 0;
}


2736
static int
2737 2738 2739
virSecuritySELinuxSetAllLabel(virSecurityManagerPtr mgr,
                              virDomainDefPtr def,
                              const char *stdin_path)
2740
{
2741
    size_t i;
2742 2743 2744 2745
    virSecuritySELinuxDataPtr data = virSecurityManagerGetPrivateData(mgr);
    virSecurityLabelDefPtr secdef;

    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
2746

2747
    if (!secdef || !secdef->relabel || data->skipAllLabel)
2748 2749
        return 0;

2750
    for (i = 0; i < def->ndisks; i++) {
2751
        /* XXX fixme - we need to recursively label the entire tree :-( */
E
Eric Blake 已提交
2752
        if (virDomainDiskGetType(def->disks[i]) == VIR_STORAGE_TYPE_DIR) {
2753
            VIR_WARN("Unable to relabel directory tree %s for disk %s",
2754 2755
                     virDomainDiskGetSource(def->disks[i]),
                     def->disks[i]->dst);
2756
            continue;
2757
        }
2758 2759
        if (virSecuritySELinuxSetDiskLabel(mgr,
                                           def, def->disks[i]) < 0)
2760 2761
            return -1;
    }
2762
    /* XXX fixme process  def->fss if relabel == true */
2763

2764
    for (i = 0; i < def->nhostdevs; i++) {
2765 2766 2767 2768
        if (virSecuritySELinuxSetHostdevLabel(mgr,
                                              def,
                                              def->hostdevs[i],
                                              NULL) < 0)
2769
            return -1;
2770
    }
2771 2772 2773 2774 2775 2776

    for (i = 0; i < def->ninputs; i++) {
        if (virSecuritySELinuxSetInputLabel(mgr, def, def->inputs[i]) < 0)
            return -1;
    }

2777 2778 2779 2780 2781
    for (i = 0; i < def->nmems; i++) {
        if (virSecuritySELinuxSetMemoryLabel(mgr, def, def->mems[i]) < 0)
            return -1;
    }

2782
    if (def->tpm) {
2783
        if (virSecuritySELinuxSetTPMFileLabel(mgr, def, def->tpm) < 0)
2784 2785
            return -1;
    }
2786

2787
    if (virDomainChrDefForeach(def,
2788
                               true,
2789
                               virSecuritySELinuxSetSecurityChardevCallback,
2790
                               mgr) < 0)
2791 2792
        return -1;

2793
    if (virDomainSmartcardDefForeach(def,
E
Eric Blake 已提交
2794
                                     true,
2795
                                     virSecuritySELinuxSetSecuritySmartcardCallback,
2796
                                     mgr) < 0)
E
Eric Blake 已提交
2797 2798
        return -1;

M
Michal Privoznik 已提交
2799 2800
    /* This is different than kernel or initrd. The nvram store
     * is really a disk, qemu can read and write to it. */
2801
    if (def->os.loader && def->os.loader->nvram &&
M
Michal Privoznik 已提交
2802
        secdef && secdef->imagelabel &&
2803 2804
        virSecuritySELinuxSetFilecon(mgr, def->os.loader->nvram,
                                     secdef->imagelabel) < 0)
2805 2806
        return -1;

2807
    if (def->os.kernel &&
2808 2809
        virSecuritySELinuxSetFilecon(mgr, def->os.kernel,
                                     data->content_context) < 0)
2810 2811
        return -1;

2812
    if (def->os.initrd &&
2813 2814
        virSecuritySELinuxSetFilecon(mgr, def->os.initrd,
                                     data->content_context) < 0)
2815 2816
        return -1;

O
Olivia Yin 已提交
2817
    if (def->os.dtb &&
2818 2819
        virSecuritySELinuxSetFilecon(mgr, def->os.dtb,
                                     data->content_context) < 0)
O
Olivia Yin 已提交
2820 2821
        return -1;

J
Ján Tomko 已提交
2822 2823 2824 2825 2826
    if (def->os.slic_table &&
        virSecuritySELinuxSetFilecon(mgr, def->os.slic_table,
                                     data->content_context) < 0)
        return -1;

2827
    if (stdin_path &&
2828 2829
        virSecuritySELinuxSetFilecon(mgr, stdin_path,
                                     data->content_context) < 0)
2830
        return -1;
2831

2832 2833 2834
    return 0;
}

2835
static int
2836 2837 2838
virSecuritySELinuxSetImageFDLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
                                  virDomainDefPtr def,
                                  int fd)
2839
{
2840 2841 2842
    virSecurityLabelDefPtr secdef;

    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
2843
    if (!secdef || !secdef->imagelabel)
2844 2845
        return 0;

2846
    return virSecuritySELinuxFSetFilecon(fd, secdef->imagelabel);
2847 2848
}

2849
static int
2850
virSecuritySELinuxSetTapFDLabel(virSecurityManagerPtr mgr,
2851 2852 2853
                                virDomainDefPtr def,
                                int fd)
{
2854 2855
    struct stat buf;
    security_context_t fcon = NULL;
2856
    virSecurityLabelDefPtr secdef;
2857
    char *str = NULL, *proc = NULL, *fd_path = NULL;
2858
    int rc = -1;
2859 2860

    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
2861
    if (!secdef || !secdef->label)
2862 2863
        return 0;

2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874
    if (fstat(fd, &buf) < 0) {
        virReportSystemError(errno, _("cannot stat tap fd %d"), fd);
        goto cleanup;
    }

    if ((buf.st_mode & S_IFMT) != S_IFCHR) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("tap fd %d is not character device"), fd);
        goto cleanup;
    }

2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892
    /* Label /dev/tap.* devices only. Leave /dev/net/tun alone! */
    if (virAsprintf(&proc, "/proc/self/fd/%d", fd) == -1)
        goto cleanup;

    if (virFileResolveLink(proc, &fd_path) < 0) {
        virReportSystemError(errno,
                             _("Unable to resolve link: %s"), proc);
        goto cleanup;
    }

    if (!STRPREFIX(fd_path, "/dev/tap")) {
        VIR_DEBUG("fd=%d points to %s not setting SELinux label",
                  fd, fd_path);
        rc = 0;
        goto cleanup;
    }

    if (getContext(mgr, "/dev/tap*", buf.st_mode, &fcon) < 0) {
2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 2905
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("cannot lookup default selinux label for tap fd %d"), fd);
        goto cleanup;
    }

    if (!(str = virSecuritySELinuxContextAddRange(secdef->label, fcon))) {
        goto cleanup;
    } else {
        rc = virSecuritySELinuxFSetFilecon(fd, str);
    }

 cleanup:
    freecon(fcon);
2906 2907
    VIR_FREE(fd_path);
    VIR_FREE(proc);
2908 2909
    VIR_FREE(str);
    return rc;
2910 2911
}

2912 2913 2914 2915
static char *
virSecuritySELinuxGenImageLabel(virSecurityManagerPtr mgr,
                                virDomainDefPtr def)
{
2916
    virSecurityLabelDefPtr secdef;
2917 2918 2919 2920
    virSecuritySELinuxDataPtr data = virSecurityManagerGetPrivateData(mgr);
    const char *range;
    context_t ctx = NULL;
    char *label = NULL;
2921
    char *mcs = NULL;
2922

2923 2924 2925 2926
    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
    if (secdef == NULL)
        goto cleanup;

2927 2928 2929
    if (secdef->label) {
        ctx = context_new(secdef->label);
        if (!ctx) {
2930 2931
            virReportSystemError(errno, _("unable to create selinux context for: %s"),
                                 secdef->label);
2932 2933 2934 2935
            goto cleanup;
        }
        range = context_range_get(ctx);
        if (range) {
2936
            if (VIR_STRDUP(mcs, range) < 0)
2937
                goto cleanup;
2938 2939
            if (!(label = virSecuritySELinuxGenNewContext(data->file_context,
                                                          mcs, true)))
2940 2941 2942 2943
                goto cleanup;
        }
    }

2944
 cleanup:
2945 2946 2947
    context_free(ctx);
    VIR_FREE(mcs);
    return label;
2948 2949
}

2950 2951 2952 2953
static char *
virSecuritySELinuxGetSecurityMountOptions(virSecurityManagerPtr mgr,
                                          virDomainDefPtr def)
{
2954
    char *opts = NULL;
2955 2956
    virSecurityLabelDefPtr secdef;

2957 2958 2959 2960 2961 2962 2963
    if ((secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME))) {
        if (!secdef->imagelabel)
            secdef->imagelabel = virSecuritySELinuxGenImageLabel(mgr, def);

        if (secdef->imagelabel &&
            virAsprintf(&opts,
                        ",context=\"%s\"",
2964
                        (const char*) secdef->imagelabel) < 0)
2965 2966
            return NULL;
    }
2967

2968
    if (!opts && VIR_STRDUP(opts, "") < 0)
2969
        return NULL;
2970

2971 2972
    VIR_DEBUG("imageLabel=%s opts=%s",
              secdef ? secdef->imagelabel : "(null)", opts);
2973 2974 2975
    return opts;
}

G
Guido Günther 已提交
2976
static int
2977 2978 2979
virSecuritySELinuxDomainSetPathLabel(virSecurityManagerPtr mgr,
                                     virDomainDefPtr def,
                                     const char *path)
2980 2981 2982 2983 2984 2985 2986
{
    virSecurityLabelDefPtr seclabel;

    seclabel = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
    if (!seclabel || !seclabel->relabel)
        return 0;

2987
    return virSecuritySELinuxSetFilecon(mgr, path, seclabel->imagelabel);
2988 2989
}

2990
virSecurityDriver virSecurityDriverSELinux = {
2991 2992
    .privateDataLen                     = sizeof(virSecuritySELinuxData),
    .name                               = SECURITY_SELINUX_NAME,
2993 2994 2995
    .probe                              = virSecuritySELinuxDriverProbe,
    .open                               = virSecuritySELinuxDriverOpen,
    .close                              = virSecuritySELinuxDriverClose,
2996

2997 2998
    .getModel                           = virSecuritySELinuxGetModel,
    .getDOI                             = virSecuritySELinuxGetDOI,
2999

3000 3001 3002 3003
    .transactionStart                   = virSecuritySELinuxTransactionStart,
    .transactionCommit                  = virSecuritySELinuxTransactionCommit,
    .transactionAbort                   = virSecuritySELinuxTransactionAbort,

3004
    .domainSecurityVerify               = virSecuritySELinuxVerify,
3005

3006 3007
    .domainSetSecurityDiskLabel         = virSecuritySELinuxSetDiskLabel,
    .domainRestoreSecurityDiskLabel     = virSecuritySELinuxRestoreDiskLabel,
3008

3009 3010
    .domainSetSecurityImageLabel        = virSecuritySELinuxSetImageLabel,
    .domainRestoreSecurityImageLabel    = virSecuritySELinuxRestoreImageLabel,
3011

3012 3013 3014
    .domainSetSecurityMemoryLabel       = virSecuritySELinuxSetMemoryLabel,
    .domainRestoreSecurityMemoryLabel   = virSecuritySELinuxRestoreMemoryLabel,

3015 3016 3017
    .domainSetSecurityDaemonSocketLabel = virSecuritySELinuxSetDaemonSocketLabel,
    .domainSetSecuritySocketLabel       = virSecuritySELinuxSetSocketLabel,
    .domainClearSecuritySocketLabel     = virSecuritySELinuxClearSocketLabel,
3018

3019 3020 3021
    .domainGenSecurityLabel             = virSecuritySELinuxGenLabel,
    .domainReserveSecurityLabel         = virSecuritySELinuxReserveLabel,
    .domainReleaseSecurityLabel         = virSecuritySELinuxReleaseLabel,
3022

3023 3024 3025
    .domainGetSecurityProcessLabel      = virSecuritySELinuxGetProcessLabel,
    .domainSetSecurityProcessLabel      = virSecuritySELinuxSetProcessLabel,
    .domainSetSecurityChildProcessLabel = virSecuritySELinuxSetChildProcessLabel,
3026

3027 3028
    .domainSetSecurityAllLabel          = virSecuritySELinuxSetAllLabel,
    .domainRestoreSecurityAllLabel      = virSecuritySELinuxRestoreAllLabel,
3029

3030 3031
    .domainSetSecurityHostdevLabel      = virSecuritySELinuxSetHostdevLabel,
    .domainRestoreSecurityHostdevLabel  = virSecuritySELinuxRestoreHostdevLabel,
3032

3033 3034
    .domainSetSavedStateLabel           = virSecuritySELinuxSetSavedStateLabel,
    .domainRestoreSavedStateLabel       = virSecuritySELinuxRestoreSavedStateLabel,
3035

3036
    .domainSetSecurityImageFDLabel      = virSecuritySELinuxSetImageFDLabel,
3037
    .domainSetSecurityTapFDLabel        = virSecuritySELinuxSetTapFDLabel,
3038

3039
    .domainGetSecurityMountOptions      = virSecuritySELinuxGetSecurityMountOptions,
3040
    .getBaseLabel                       = virSecuritySELinuxGetBaseLabel,
3041

3042
    .domainSetPathLabel                 = virSecuritySELinuxDomainSetPathLabel,
3043
};