security_selinux.c 74.7 KB
Newer Older
1
/*
2
 * Copyright (C) 2008-2013 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 "virstoragefile.h"
E
Eric Blake 已提交
43
#include "virfile.h"
44
#include "virhash.h"
45
#include "virrandom.h"
46
#include "virconf.h"
47
#include "virtpm.h"
48
#include "virstring.h"
D
Daniel P. Berrange 已提交
49 50 51

#define VIR_FROM_THIS VIR_FROM_SECURITY

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

typedef struct _virSecuritySELinuxData virSecuritySELinuxData;
typedef virSecuritySELinuxData *virSecuritySELinuxDataPtr;

typedef struct _virSecuritySELinuxCallbackData virSecuritySELinuxCallbackData;
typedef virSecuritySELinuxCallbackData *virSecuritySELinuxCallbackDataPtr;

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 75 76
};

struct _virSecuritySELinuxCallbackData {
    virSecurityManagerPtr manager;
    virSecurityLabelDefPtr secdef;
};

77 78 79
#define SECURITY_SELINUX_VOID_DOI       "0"
#define SECURITY_SELINUX_NAME "selinux"

80 81 82 83 84 85
static int
virSecuritySELinuxRestoreSecurityTPMFileLabelInt(virSecurityManagerPtr mgr,
                                                 virDomainDefPtr def,
                                                 virDomainTPMDefPtr tpm);


86 87 88
/*
 * Returns 0 on success, 1 if already reserved, or -1 on fatal error
 */
89
static int
90 91
virSecuritySELinuxMCSAdd(virSecurityManagerPtr mgr,
                         const char *mcs)
92
{
93
    virSecuritySELinuxDataPtr data = virSecurityManagerGetPrivateData(mgr);
94

95 96 97 98
    if (virHashLookup(data->mcs, mcs))
        return 1;

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

101 102 103
    return 0;
}

104 105 106
static void
virSecuritySELinuxMCSRemove(virSecurityManagerPtr mgr,
                            const char *mcs)
107
{
108 109 110
    virSecuritySELinuxDataPtr data = virSecurityManagerGetPrivateData(mgr);

    virHashRemoveEntry(data->mcs, mcs);
111 112
}

113 114

static char *
115 116 117 118
virSecuritySELinuxMCSFind(virSecurityManagerPtr mgr,
                          const char *sens,
                          int catMin,
                          int catMax)
119 120
{
    virSecuritySELinuxDataPtr data = virSecurityManagerGetPrivateData(mgr);
121
    int catRange;
122
    char *mcs = NULL;
123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143

    /* +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) {
144
            if (virAsprintf(&mcs, "%s:c%d", sens, catMin + c1) < 0)
145 146 147 148 149 150 151
                return NULL;
        } else {
            if (c1 > c2) {
                int t = c1;
                c1 = c2;
                c2 = t;
            }
152
            if (virAsprintf(&mcs, "%s:c%d,c%d", sens, catMin + c1, catMin + c2) < 0)
153 154 155 156 157 158 159 160 161 162 163 164
                return NULL;
        }

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

        VIR_FREE(mcs);
    }

    return mcs;
}

165 166 167 168

/*
 * This needs to cope with several styles of range
 *
169
 * system_u:system_r:virtd_t
170 171 172 173
 * 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
 *
174 175
 * In the first case we'll assume s0:c0.c1023 and
 * in the next two cases, we'll assume c0.c1023 for
176 177 178 179 180
 * 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
 * mode when run with a wierd process label.
 */
181 182 183 184 185
static int
virSecuritySELinuxMCSGetProcessRange(char **sens,
                                     int *catMin,
                                     int *catMax)
{
186 187
    security_context_t ourSecContext = NULL;
    context_t ourContext = NULL;
188 189
    char *cat = NULL;
    char *tmp;
190
    const char *contextRange;
191
    int ret = -1;
192

M
Martin Kletzander 已提交
193
    if (getcon_raw(&ourSecContext) < 0) {
194 195 196 197 198 199 200 201 202 203
        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;
    }
204 205
    if (!(contextRange = context_range_get(ourContext)))
        contextRange = "s0";
206

207
    if (VIR_STRDUP(*sens, contextRange) < 0)
208 209
        goto cleanup;

210 211 212 213 214
    /* Find and blank out the category part (if any) */
    tmp = strchr(*sens, ':');
    if (tmp) {
        *tmp = '\0';
        cat = tmp + 1;
215 216
    }
    /* Find and blank out the sensitivity upper bound */
217
    if ((tmp = strchr(*sens, '-')))
218 219 220
        *tmp = '\0';
    /* sens now just contains the sensitivity lower bound */

221 222 223 224 225 226 227 228
    /* If there was no category part, just assume c0.c1024 */
    if (!cat) {
        *catMin = 0;
        *catMax = 1024;
        ret = 0;
        goto cleanup;
    }

229 230 231 232 233 234 235 236 237
    /* Find & extract category min */
    tmp = cat;
    if (tmp[0] != 'c') {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Cannot parse category in %s"),
                       cat);
        goto cleanup;
    }
    tmp++;
238
    if (virStrToLong_i(tmp, &tmp, 10, catMin) < 0) {
239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267
        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++;
268
    if (virStrToLong_i(tmp, &tmp, 10, catMax) < 0) {
269 270 271 272 273 274
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Cannot parse category in %s"),
                       cat);
        goto cleanup;
    }

275
    ret = 0;
276 277

cleanup:
278 279
    if (ret < 0)
        VIR_FREE(*sens);
280 281
    freecon(ourSecContext);
    context_free(ourContext);
282
    return ret;
283 284
}

285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314
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;
    }

315
    ignore_value(VIR_STRDUP(ret, str));
316 317 318 319 320 321

cleanup:
    if (srccon) context_free(srccon);
    if (dstcon) context_free(dstcon);
    return ret;
}
322

323
static char *
324 325 326
virSecuritySELinuxGenNewContext(const char *basecontext,
                                const char *mcs,
                                bool isObjectContext)
327
{
328
    context_t context = NULL;
329 330
    char *ret = NULL;
    char *str;
331 332 333
    security_context_t ourSecContext = NULL;
    context_t ourContext = NULL;

334 335 336
    VIR_DEBUG("basecontext=%s mcs=%s isObjectContext=%d",
              basecontext, mcs, isObjectContext);

M
Martin Kletzander 已提交
337
    if (getcon_raw(&ourSecContext) < 0) {
338 339 340 341 342 343 344 345 346 347
        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;
    }
348
    VIR_DEBUG("process=%s", ourSecContext);
349 350 351 352 353 354 355 356

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

357 358 359 360 361 362 363 364
    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;
    }

365 366
    if (!isObjectContext &&
        context_role_set(context,
367 368
                         context_role_get(ourContext)) != 0) {
        virReportSystemError(errno,
369
                             _("Unable to set SELinux context role '%s'"),
370 371 372 373
                             context_role_get(ourContext));
        goto cleanup;
    }

374 375 376 377 378 379 380 381 382 383 384
    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;
    }
385
    if (VIR_STRDUP(ret, str) < 0)
386
        goto cleanup;
387
    VIR_DEBUG("Generated context '%s'",  ret);
388
cleanup:
389 390
    freecon(ourSecContext);
    context_free(ourContext);
391 392
    context_free(context);
    return ret;
393 394
}

395

396
#ifdef HAVE_SELINUX_LXC_CONTEXTS_PATH
397
static int
398
virSecuritySELinuxLXCInitialize(virSecurityManagerPtr mgr)
399 400 401 402 403 404 405
{
    virConfValuePtr scon = NULL;
    virConfValuePtr tcon = NULL;
    virConfValuePtr dcon = NULL;
    virConfPtr selinux_conf;
    virSecuritySELinuxDataPtr data = virSecurityManagerGetPrivateData(mgr);

406 407
    data->skipAllLabel = true;

408
# if HAVE_SELINUX_LABEL_H
409 410 411 412 413 414
    data->label_handle = selabel_open(SELABEL_CTX_FILE, NULL, 0);
    if (!data->label_handle) {
        virReportSystemError(errno, "%s",
                             _("cannot open SELinux label_handle"));
        return -1;
    }
415
# endif
416

417 418 419 420 421
    selinux_conf = virConfReadFile(selinux_lxc_contexts_path(), 0);
    if (!selinux_conf) {
        virReportSystemError(errno,
                             _("cannot open SELinux lxc contexts file '%s'"),
                             selinux_lxc_contexts_path());
422
        goto error;
423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448
    }

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

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

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

449 450 451
    if (VIR_STRDUP(data->domain_context, scon->str) < 0 ||
        VIR_STRDUP(data->file_context, tcon->str) < 0 ||
        VIR_STRDUP(data->content_context, dcon->str) < 0)
452
        goto error;
453 454 455 456

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

457 458 459 460
    virConfFree(selinux_conf);
    return 0;

error:
461
# if HAVE_SELINUX_LABEL_H
462
    selabel_close(data->label_handle);
463
# endif
464 465 466 467
    virConfFree(selinux_conf);
    VIR_FREE(data->domain_context);
    VIR_FREE(data->file_context);
    VIR_FREE(data->content_context);
468
    virHashFree(data->mcs);
469 470
    return -1;
}
471 472
#else
static int
473
virSecuritySELinuxLXCInitialize(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED)
474 475 476 477 478 479
{
    virReportSystemError(ENOSYS, "%s",
                         _("libselinux does not support LXC contexts path"));
    return -1;
}
#endif
480 481 482


static int
483
virSecuritySELinuxQEMUInitialize(virSecurityManagerPtr mgr)
484
{
485 486
    char *ptr;
    virSecuritySELinuxDataPtr data = virSecurityManagerGetPrivateData(mgr);
487

488 489
    data->skipAllLabel = false;

490 491 492 493 494 495 496 497 498
#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

499
    if (virFileReadAll(selinux_virtual_domain_context_path(), MAX_CONTEXT, &(data->domain_context)) < 0) {
500
        virReportSystemError(errno,
501
                             _("cannot read SELinux virtual domain context file '%s'"),
502
                             selinux_virtual_domain_context_path());
503
        goto error;
504 505
    }

506
    ptr = strchrnul(data->domain_context, '\n');
507
    if (ptr && *ptr == '\n') {
508
        *ptr = '\0';
509 510
        ptr++;
        if (*ptr != '\0') {
511
            if (VIR_STRDUP(data->alt_domain_context, ptr) < 0)
512 513 514 515 516 517 518 519 520
                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));

521

522
    if (virFileReadAll(selinux_virtual_image_context_path(), 2*MAX_CONTEXT, &(data->file_context)) < 0) {
523
        virReportSystemError(errno,
524 525
                             _("cannot read SELinux virtual image context file %s"),
                             selinux_virtual_image_context_path());
526
        goto error;
527 528
    }

529 530
    ptr = strchrnul(data->file_context, '\n');
    if (ptr && *ptr == '\n') {
531
        *ptr = '\0';
532
        if (VIR_STRDUP(data->content_context, ptr + 1) < 0)
533 534 535
            goto error;
        ptr = strchrnul(data->content_context, '\n');
        if (ptr && *ptr == '\n')
536 537
            *ptr = '\0';
    }
538

539 540 541
    VIR_DEBUG("Loaded file context '%s', content context '%s'",
              data->file_context, data->content_context);

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

545
    return 0;
546 547

error:
548 549 550
#if HAVE_SELINUX_LABEL_H
    selabel_close(data->label_handle);
#endif
551
    VIR_FREE(data->domain_context);
552
    VIR_FREE(data->alt_domain_context);
553 554
    VIR_FREE(data->file_context);
    VIR_FREE(data->content_context);
555
    virHashFree(data->mcs);
556
    return -1;
557 558
}

559 560

static int
561
virSecuritySELinuxInitialize(virSecurityManagerPtr mgr)
562 563 564
{
    VIR_DEBUG("SELinuxInitialize %s", virSecurityManagerGetDriver(mgr));
    if (STREQ(virSecurityManagerGetDriver(mgr),  "LXC")) {
565
        return virSecuritySELinuxLXCInitialize(mgr);
566
    } else {
567
        return virSecuritySELinuxQEMUInitialize(mgr);
568 569 570 571
    }
}


572
static int
573 574
virSecuritySELinuxGenSecurityLabel(virSecurityManagerPtr mgr,
                                   virDomainDefPtr def)
575 576
{
    int rc = -1;
577
    char *mcs = NULL;
578
    char *scontext = NULL;
579
    context_t ctx = NULL;
580
    const char *range;
581 582
    virSecurityLabelDefPtr seclabel;
    virSecuritySELinuxDataPtr data;
583
    const char *baselabel;
584 585
    char *sens = NULL;
    int catMin, catMax;
586

587
    seclabel = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
P
Peter Krempa 已提交
588
    if (seclabel == NULL)
589 590 591 592 593 594 595
        return rc;

    data = virSecurityManagerGetPrivateData(mgr);

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

601
    if (seclabel->imagelabel) {
P
Peter Krempa 已提交
602 603
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("security image label already defined for VM"));
604 605 606
        return rc;
    }

607 608
    if (seclabel->model &&
        STRNEQ(seclabel->model, SECURITY_SELINUX_NAME)) {
609 610
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("security label model %s is not supported with selinux"),
611
                       seclabel->model);
612 613 614
        return rc;
    }

615
    VIR_DEBUG("type=%d", seclabel->type);
616

617
    switch (seclabel->type) {
618
    case VIR_DOMAIN_SECLABEL_STATIC:
619
        if (!(ctx = context_new(seclabel->label))) {
620 621
            virReportSystemError(errno,
                                 _("unable to allocate socket security context '%s'"),
622
                                 seclabel->label);
623
            return rc;
624 625
        }

P
Peter Krempa 已提交
626
        if (!(range = context_range_get(ctx))) {
627
            virReportSystemError(errno, "%s", _("unable to get selinux context range"));
628 629
            goto cleanup;
        }
630 631
        if (VIR_STRDUP(mcs, range) < 0)
            goto cleanup;
632 633 634
        break;

    case VIR_DOMAIN_SECLABEL_DYNAMIC:
635 636 637 638 639 640 641 642 643
        if (virSecuritySELinuxMCSGetProcessRange(&sens,
                                                 &catMin,
                                                 &catMax) < 0)
            goto cleanup;

        if (!(mcs = virSecuritySELinuxMCSFind(mgr,
                                              sens,
                                              catMin,
                                              catMax)))
644 645 646 647
            goto cleanup;

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

649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668
        baselabel = seclabel->baselabel;
        if (!baselabel) {
            if (def->virtType == VIR_DOMAIN_VIRT_QEMU) {
                if (data->alt_domain_context == NULL) {
                    static bool warned = false;
                    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;
            }
        }

669 670
        seclabel->label = virSecuritySELinuxGenNewContext(baselabel, mcs, false);
        if (!seclabel->label)
671
            goto cleanup;
672

673 674 675 676 677 678 679
        break;

    case VIR_DOMAIN_SECLABEL_NONE:
        /* no op */
        break;

    default:
680 681
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected security label type '%s'"),
682
                       virDomainSeclabelTypeToString(seclabel->type));
683
        goto cleanup;
D
Daniel P. Berrange 已提交
684
    }
685

686 687 688 689 690 691
    /* always generate a image label, needed to label new objects */
    seclabel->imagelabel = virSecuritySELinuxGenNewContext(data->file_context,
                                                           mcs,
                                                           true);
    if (!seclabel->imagelabel)
        goto cleanup;
692

693
    if (!seclabel->model &&
694
        VIR_STRDUP(seclabel->model, SECURITY_SELINUX_NAME) < 0)
695
        goto cleanup;
D
Daniel P. Berrange 已提交
696

697
    rc = 0;
698 699 700

cleanup:
    if (rc != 0) {
701 702 703 704 705 706
        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);
707 708 709 710
    }

    if (ctx)
        context_free(ctx);
D
Daniel P. Berrange 已提交
711
    VIR_FREE(scontext);
712
    VIR_FREE(mcs);
713
    VIR_FREE(sens);
714 715

    VIR_DEBUG("model=%s label=%s imagelabel=%s baselabel=%s",
716 717 718 719
              NULLSTR(seclabel->model),
              NULLSTR(seclabel->label),
              NULLSTR(seclabel->imagelabel),
              NULLSTR(seclabel->baselabel));
720

721 722 723
    return rc;
}

724
static int
725
virSecuritySELinuxReserveSecurityLabel(virSecurityManagerPtr mgr,
726 727
                                       virDomainDefPtr def,
                                       pid_t pid)
728 729 730 731
{
    security_context_t pctx;
    context_t ctx = NULL;
    const char *mcs;
732
    int rv;
733
    virSecurityLabelDefPtr seclabel;
734

735 736 737 738 739 740
    seclabel = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
    if (seclabel == NULL) {
        return -1;
    }

    if (seclabel->type == VIR_DOMAIN_SECLABEL_STATIC)
741 742
        return 0;

M
Martin Kletzander 已提交
743
    if (getpidcon_raw(pid, &pctx) == -1) {
744
        virReportSystemError(errno,
745
                             _("unable to get PID %d security context"), pid);
746 747 748 749
        return -1;
    }

    ctx = context_new(pctx);
750
    freecon(pctx);
751
    if (!ctx)
752
        goto error;
753 754 755

    mcs = context_range_get(ctx);
    if (!mcs)
756 757
        goto error;

758
    if ((rv = virSecuritySELinuxMCSAdd(mgr, mcs)) < 0)
759
        goto error;
760

761 762 763 764 765 766
    if (rv == 1) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("MCS level for existing domain label %s already reserved"),
                       (char*)pctx);
        goto error;
    }
767 768 769 770 771

    context_free(ctx);

    return 0;

772
error:
773 774 775 776 777
    context_free(ctx);
    return -1;
}


778
static int
779
virSecuritySELinuxSecurityDriverProbe(const char *virtDriver)
780
{
781 782 783
    if (!is_selinux_enabled())
        return SECURITY_DRIVER_DISABLE;

784 785 786 787 788 789
    if (virtDriver && STREQ(virtDriver, "LXC")) {
#if HAVE_SELINUX_LXC_CONTEXTS_PATH
        if (!virFileExists(selinux_lxc_contexts_path()))
#endif
            return SECURITY_DRIVER_DISABLE;
    }
790 791

    return SECURITY_DRIVER_ENABLE;
792 793
}

794

795
static int
796
virSecuritySELinuxSecurityDriverOpen(virSecurityManagerPtr mgr)
797
{
798
    return virSecuritySELinuxInitialize(mgr);
799 800
}

801

802
static int
803
virSecuritySELinuxSecurityDriverClose(virSecurityManagerPtr mgr)
804
{
805 806 807 808 809
    virSecuritySELinuxDataPtr data = virSecurityManagerGetPrivateData(mgr);

    if (!data)
        return 0;

810 811 812 813
#if HAVE_SELINUX_LABEL_H
    selabel_close(data->label_handle);
#endif

814 815
    virHashFree(data->mcs);

816
    VIR_FREE(data->domain_context);
817
    VIR_FREE(data->alt_domain_context);
818 819 820
    VIR_FREE(data->file_context);
    VIR_FREE(data->content_context);

821 822 823 824
    return 0;
}


825 826
static const char *
virSecuritySELinuxSecurityGetModel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED)
827 828 829 830
{
    return SECURITY_SELINUX_NAME;
}

831 832
static const char *
virSecuritySELinuxSecurityGetDOI(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED)
833 834 835 836 837
{
    /*
     * Where will the DOI come from?  SELinux configuration, or qemu
     * configuration? For the moment, we'll just set it to "0".
     */
838
    return SECURITY_SELINUX_VOID_DOI;
839 840 841
}

static int
842 843 844 845
virSecuritySELinuxGetSecurityProcessLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
                                          virDomainDefPtr def ATTRIBUTE_UNUSED,
                                          pid_t pid,
                                          virSecurityLabelPtr sec)
846 847 848
{
    security_context_t ctx;

M
Martin Kletzander 已提交
849
    if (getpidcon_raw(pid, &ctx) == -1) {
850
        virReportSystemError(errno,
851
                             _("unable to get PID %d security context"),
852
                             pid);
853 854 855 856
        return -1;
    }

    if (strlen((char *) ctx) >= VIR_SECURITY_LABEL_BUFLEN) {
857 858 859 860
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("security label exceeds "
                         "maximum length: %d"),
                       VIR_SECURITY_LABEL_BUFLEN - 1);
861
        freecon(ctx);
862 863 864 865
        return -1;
    }

    strcpy(sec->label, (char *) ctx);
866
    freecon(ctx);
867

868
    VIR_DEBUG("label=%s", sec->label);
869 870
    sec->enforcing = security_getenforce();
    if (sec->enforcing == -1) {
871
        virReportSystemError(errno, "%s",
872
                             _("error calling security_getenforce()"));
873 874 875 876 877 878
        return -1;
    }

    return 0;
}

879 880 881
/* 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.  */
882
static int
883
virSecuritySELinuxSetFileconHelper(const char *path, char *tcon, bool optional)
884
{
885
    security_context_t econ;
886

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

M
Martin Kletzander 已提交
889
    if (setfilecon_raw(path, tcon) < 0) {
890 891
        int setfilecon_errno = errno;

M
Martin Kletzander 已提交
892
        if (getfilecon_raw(path, &econ) >= 0) {
893 894 895
            if (STREQ(tcon, econ)) {
                freecon(econ);
                /* It's alright, there's nothing to change anyway. */
896
                return optional ? 1 : 0;
897 898 899
            }
            freecon(econ);
        }
900 901

        /* if the error complaint is related to an image hosted on
902 903
         * an nfs mount, or a usbfs/sysfs filesystem not supporting
         * labelling, then just ignore it & hope for the best.
904
         * The user hopefully set one of the necessary SELinux
905
         * virt_use_{nfs,usb,pci}  boolean tunables to allow it...
906
         */
907
        if (setfilecon_errno != EOPNOTSUPP && setfilecon_errno != ENOTSUP) {
908
            virReportSystemError(setfilecon_errno,
909
                                 _("unable to set security context '%s' on '%s'"),
910
                                 tcon, path);
911 912
            if (security_getenforce() == 1)
                return -1;
913
        } else {
914 915 916 917 918 919 920 921 922 923 924 925 926 927
            const char *msg;
            if ((virStorageFileIsSharedFSType(path,
                                              VIR_STORAGE_FILE_SHFS_NFS) == 1) &&
                security_get_boolean_active("virt_use_nfs") != 1) {
                msg = _("Setting security context '%s' on '%s' not supported. "
                        "Consider setting virt_use_nfs");
               if (security_getenforce() == 1)
                   VIR_WARN(msg, tcon, path);
               else
                   VIR_INFO(msg, tcon, path);
            } else {
                VIR_INFO("Setting security context '%s' on '%s' not supported",
                         tcon, path);
            }
928 929
            if (optional)
                return 1;
930
        }
931 932 933 934
    }
    return 0;
}

935
static int
936
virSecuritySELinuxSetFileconOptional(const char *path, char *tcon)
937
{
938
    return virSecuritySELinuxSetFileconHelper(path, tcon, true);
939 940 941
}

static int
942
virSecuritySELinuxSetFilecon(const char *path, char *tcon)
943
{
944
    return virSecuritySELinuxSetFileconHelper(path, tcon, false);
945 946
}

947
static int
948
virSecuritySELinuxFSetFilecon(int fd, char *tcon)
949 950 951 952 953
{
    security_context_t econ;

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

M
Martin Kletzander 已提交
954
    if (fsetfilecon_raw(fd, tcon) < 0) {
955 956
        int fsetfilecon_errno = errno;

M
Martin Kletzander 已提交
957
        if (fgetfilecon_raw(fd, &econ) >= 0) {
958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985
            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 已提交
986 987
/* Set fcon to the appropriate label for path and mode, or return -1.  */
static int
988
getContext(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
989
           const char *newpath, mode_t mode, security_context_t *fcon)
E
Eric Blake 已提交
990 991
{
#if HAVE_SELINUX_LABEL_H
992
    virSecuritySELinuxDataPtr data = virSecurityManagerGetPrivateData(mgr);
E
Eric Blake 已提交
993

994
    return selabel_lookup_raw(data->label_handle, fcon, newpath, mode);
E
Eric Blake 已提交
995 996 997 998 999
#else
    return matchpathcon(newpath, mode, fcon);
#endif
}

1000 1001 1002

/* This method shouldn't raise errors, since they'll overwrite
 * errors that the caller(s) are already dealing with */
1003
static int
1004 1005
virSecuritySELinuxRestoreSecurityFileLabel(virSecurityManagerPtr mgr,
                                           const char *path)
1006
{
1007 1008 1009 1010
    struct stat buf;
    security_context_t fcon = NULL;
    int rc = -1;
    char *newpath = NULL;
1011
    char ebuf[1024];
1012

1013 1014
    VIR_INFO("Restoring SELinux context on '%s'", path);

1015
    if (virFileResolveLink(path, &newpath) < 0) {
1016 1017
        VIR_WARN("cannot resolve symlink %s: %s", path,
                 virStrerror(errno, ebuf, sizeof(ebuf)));
D
Daniel P. Berrange 已提交
1018
        goto err;
1019
    }
1020

1021
    if (stat(newpath, &buf) != 0) {
1022 1023
        VIR_WARN("cannot stat %s: %s", newpath,
                 virStrerror(errno, ebuf, sizeof(ebuf)));
D
Daniel P. Berrange 已提交
1024
        goto err;
1025
    }
D
Daniel P. Berrange 已提交
1026

1027
    if (getContext(mgr, newpath, buf.st_mode, &fcon) < 0) {
1028 1029 1030
        /* Any user created path likely does not have a default label,
         * which makes this an expected non error
         */
1031
        VIR_WARN("cannot lookup default selinux label for %s", newpath);
1032
        rc = 0;
1033
    } else {
1034
        rc = virSecuritySELinuxSetFilecon(newpath, fcon);
1035
    }
1036

1037
err:
1038
    freecon(fcon);
1039 1040
    VIR_FREE(newpath);
    return rc;
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 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119

static int
virSecuritySELinuxSetSecurityTPMFileLabel(virSecurityManagerPtr mgr,
                                          virDomainDefPtr def,
                                          virDomainTPMDefPtr tpm)
{
    int rc;
    virSecurityLabelDefPtr seclabel;
    char *cancel_path;
    const char *tpmdev;

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

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

        if ((cancel_path = virTPMCreateCancelPath(tpmdev)) != NULL) {
            rc = virSecuritySELinuxSetFilecon(cancel_path,
                                              seclabel->imagelabel);
            VIR_FREE(cancel_path);
            if (rc < 0) {
                virSecuritySELinuxRestoreSecurityTPMFileLabelInt(mgr, def,
                                                                 tpm);
                return -1;
            }
        } else {
            return -1;
        }
        break;
    case VIR_DOMAIN_TPM_TYPE_LAST:
        break;
    }

    return 0;
}


static int
virSecuritySELinuxRestoreSecurityTPMFileLabelInt(virSecurityManagerPtr mgr,
                                                 virDomainDefPtr def,
                                                 virDomainTPMDefPtr tpm)
{
    int rc = 0;
    virSecurityLabelDefPtr seclabel;
    char *cancel_path;
    const char *tpmdev;

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

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

        if ((cancel_path = virTPMCreateCancelPath(tpmdev)) != NULL) {
            if (virSecuritySELinuxRestoreSecurityFileLabel(mgr,
                                  cancel_path) < 0)
                rc = -1;
            VIR_FREE(cancel_path);
        }
        break;
    case VIR_DOMAIN_TPM_TYPE_LAST:
        break;
    }

    return rc;
}


1120
static int
1121
virSecuritySELinuxRestoreSecurityImageLabelInt(virSecurityManagerPtr mgr,
1122 1123 1124
                                               virDomainDefPtr def,
                                               virDomainDiskDefPtr disk,
                                               int migrated)
1125
{
1126 1127 1128 1129 1130 1131
    virSecurityLabelDefPtr seclabel;
    virSecurityDeviceLabelDefPtr disk_seclabel;

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

1133 1134 1135
    disk_seclabel = virDomainDiskDefGetSecurityLabelDef(disk,
                                                        SECURITY_SELINUX_NAME);
    if (seclabel->norelabel || (disk_seclabel && disk_seclabel->norelabel))
1136 1137
        return 0;

1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148
    /* Don't restore labels on readoly/shared disks, because
     * other VMs may still be accessing these
     * Alternatively we could iterate over all running
     * domains and try to figure out if it is in use, but
     * this would not work for clustered filesystems, since
     * we can't see running VMs using the file on other nodes
     * Safest bet is thus to skip the restore step.
     */
    if (disk->readonly || disk->shared)
        return 0;

1149
    if (!disk->src || disk->type == VIR_DOMAIN_DISK_TYPE_NETWORK)
1150 1151
        return 0;

1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167
    /* If we have a shared FS & doing migrated, we must not
     * change ownership, because that kills access on the
     * destination host which is sub-optimal for the guest
     * VM's I/O attempts :-)
     */
    if (migrated) {
        int rc = virStorageFileIsSharedFS(disk->src);
        if (rc < 0)
            return -1;
        if (rc == 1) {
            VIR_DEBUG("Skipping image label restore on %s because FS is shared",
                      disk->src);
            return 0;
        }
    }

1168
    return virSecuritySELinuxRestoreSecurityFileLabel(mgr, disk->src);
1169 1170
}

1171 1172

static int
1173 1174 1175
virSecuritySELinuxRestoreSecurityImageLabel(virSecurityManagerPtr mgr,
                                            virDomainDefPtr def,
                                            virDomainDiskDefPtr disk)
1176
{
1177
    return virSecuritySELinuxRestoreSecurityImageLabelInt(mgr, def, disk, 0);
1178 1179 1180
}


1181
static int
1182 1183 1184 1185
virSecuritySELinuxSetSecurityFileLabel(virDomainDiskDefPtr disk,
                                       const char *path,
                                       size_t depth,
                                       void *opaque)
1186
{
1187 1188
    int ret;
    virSecurityDeviceLabelDefPtr disk_seclabel;
1189 1190 1191
    virSecuritySELinuxCallbackDataPtr cbdata = opaque;
    const virSecurityLabelDefPtr secdef = cbdata->secdef;
    virSecuritySELinuxDataPtr data = virSecurityManagerGetPrivateData(cbdata->manager);
1192

1193 1194 1195 1196
    disk_seclabel = virDomainDiskDefGetSecurityLabelDef(disk,
                                                        SECURITY_SELINUX_NAME);

    if (disk_seclabel && disk_seclabel->norelabel)
1197 1198
        return 0;

1199 1200 1201
    if (disk_seclabel && !disk_seclabel->norelabel &&
        disk_seclabel->label) {
        ret = virSecuritySELinuxSetFilecon(path, disk_seclabel->label);
1202
    } else if (depth == 0) {
1203

1204
        if (disk->shared) {
1205
            ret = virSecuritySELinuxSetFileconOptional(path, data->file_context);
1206
        } else if (disk->readonly) {
1207
            ret = virSecuritySELinuxSetFileconOptional(path, data->content_context);
1208
        } else if (secdef->imagelabel) {
1209
            ret = virSecuritySELinuxSetFileconOptional(path, secdef->imagelabel);
1210
        } else {
1211
            ret = 0;
1212 1213
        }
    } else {
1214
        ret = virSecuritySELinuxSetFileconOptional(path, data->content_context);
1215
    }
1216
    if (ret == 1 && !disk_seclabel) {
1217 1218
        /* If we failed to set a label, but virt_use_nfs let us
         * proceed anyway, then we don't need to relabel later.  */
1219
        disk_seclabel = virDomainDiskDefGenSecurityLabelDef(SECURITY_SELINUX_NAME);
1220
        if (!disk_seclabel)
1221
            return -1;
1222
        disk_seclabel->norelabel = true;
1223 1224
        if (VIR_APPEND_ELEMENT(disk->seclabels, disk->nseclabels,
                               disk_seclabel) < 0) {
1225 1226 1227
            virSecurityDeviceLabelDefFree(disk_seclabel);
            return -1;
        }
1228
        ret = 0;
1229
    }
1230
    return ret;
1231 1232
}

1233
static int
1234 1235 1236
virSecuritySELinuxSetSecurityImageLabel(virSecurityManagerPtr mgr,
                                        virDomainDefPtr def,
                                        virDomainDiskDefPtr disk)
1237 1238

{
1239 1240
    virSecuritySELinuxCallbackData cbdata;
    cbdata.manager = mgr;
1241
    cbdata.secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
1242

1243 1244
    if (cbdata.secdef == NULL)
        return -1;
1245

1246
    if (cbdata.secdef->norelabel)
1247 1248
        return 0;

1249 1250 1251
    if (disk->type == VIR_DOMAIN_DISK_TYPE_NETWORK)
        return 0;

1252
    return virDomainDiskDefForeachPath(disk,
1253
                                       true,
1254
                                       virSecuritySELinuxSetSecurityFileLabel,
1255
                                       &cbdata);
1256 1257
}

1258
static int
1259
virSecuritySELinuxSetSecurityHostdevLabelHelper(const char *file, void *opaque)
1260
{
1261
    virSecurityLabelDefPtr secdef;
1262
    virDomainDefPtr def = opaque;
1263

1264 1265 1266
    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
    if (secdef == NULL)
        return -1;
1267
    return virSecuritySELinuxSetFilecon(file, secdef->imagelabel);
1268 1269 1270
}

static int
1271
virSecuritySELinuxSetSecurityPCILabel(virPCIDevicePtr dev ATTRIBUTE_UNUSED,
1272
                                      const char *file, void *opaque)
1273
{
1274 1275
    return virSecuritySELinuxSetSecurityHostdevLabelHelper(file, opaque);
}
1276

1277 1278 1279 1280 1281
static int
virSecuritySELinuxSetSecurityUSBLabel(virUSBDevicePtr dev ATTRIBUTE_UNUSED,
                                      const char *file, void *opaque)
{
    return virSecuritySELinuxSetSecurityHostdevLabelHelper(file, opaque);
1282 1283
}

1284 1285 1286 1287 1288 1289
static int
virSecuritySELinuxSetSecuritySCSILabel(virSCSIDevicePtr dev ATTRIBUTE_UNUSED,
                                       const char *file, void *opaque)
{
    return virSecuritySELinuxSetSecurityHostdevLabelHelper(file, opaque);
}
1290

1291
static int
1292 1293 1294
virSecuritySELinuxSetSecurityHostdevSubsysLabel(virDomainDefPtr def,
                                                virDomainHostdevDefPtr dev,
                                                const char *vroot)
1295 1296 1297 1298 1299 1300

{
    int ret = -1;

    switch (dev->source.subsys.type) {
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB: {
1301
        virUSBDevicePtr usb;
1302

1303 1304 1305
        if (dev->missing)
            return 0;

1306 1307 1308
        usb = virUSBDeviceNew(dev->source.subsys.u.usb.bus,
                              dev->source.subsys.u.usb.device,
                              vroot);
1309 1310
        if (!usb)
            goto done;
1311

1312 1313
        ret = virUSBDeviceFileIterate(usb, virSecuritySELinuxSetSecurityUSBLabel, def);
        virUSBDeviceFree(usb);
M
Mark McLoughlin 已提交
1314
        break;
1315 1316 1317
    }

    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI: {
1318
        virPCIDevicePtr pci =
1319 1320 1321 1322
            virPCIDeviceNew(dev->source.subsys.u.pci.addr.domain,
                            dev->source.subsys.u.pci.addr.bus,
                            dev->source.subsys.u.pci.addr.slot,
                            dev->source.subsys.u.pci.addr.function);
1323 1324 1325 1326

        if (!pci)
            goto done;

1327
        if (dev->source.subsys.u.pci.backend
1328
            == VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO) {
1329
            char *vfioGroupDev = virPCIDeviceGetIOMMUGroupDev(pci);
1330

1331 1332
            if (!vfioGroupDev) {
                virPCIDeviceFree(pci);
1333
                goto done;
1334
            }
1335 1336 1337 1338 1339
            ret = virSecuritySELinuxSetSecurityPCILabel(pci, vfioGroupDev, def);
            VIR_FREE(vfioGroupDev);
        } else {
            ret = virPCIDeviceFileIterate(pci, virSecuritySELinuxSetSecurityPCILabel, def);
        }
1340
        virPCIDeviceFree(pci);
1341 1342 1343
        break;
    }

1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI: {
        virSCSIDevicePtr scsi =
            virSCSIDeviceNew(dev->source.subsys.u.scsi.adapter,
                             dev->source.subsys.u.scsi.bus,
                             dev->source.subsys.u.scsi.target,
                             dev->source.subsys.u.scsi.unit,
                             dev->readonly);

        if (!scsi)
            goto done;

        ret = virSCSIDeviceFileIterate(scsi, virSecuritySELinuxSetSecuritySCSILabel, def);
        virSCSIDeviceFree(scsi);

        break;
    }

1361 1362 1363 1364 1365 1366 1367 1368 1369
    default:
        ret = 0;
        break;
    }

done:
    return ret;
}

1370

1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387
static int
virSecuritySELinuxSetSecurityHostdevCapsLabel(virDomainDefPtr def,
                                              virDomainHostdevDefPtr dev,
                                              const char *vroot)
{
    int ret = -1;
    virSecurityLabelDefPtr secdef;
    char *path;

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

    switch (dev->source.caps.type) {
    case VIR_DOMAIN_HOSTDEV_CAPS_TYPE_STORAGE: {
        if (vroot) {
            if (virAsprintf(&path, "%s/%s", vroot,
1388
                            dev->source.caps.u.storage.block) < 0)
1389 1390
                return -1;
        } else {
1391
            if (VIR_STRDUP(path, dev->source.caps.u.storage.block) < 0)
1392 1393 1394 1395 1396 1397 1398 1399 1400 1401
                return -1;
        }
        ret = virSecuritySELinuxSetFilecon(path, secdef->imagelabel);
        VIR_FREE(path);
        break;
    }

    case VIR_DOMAIN_HOSTDEV_CAPS_TYPE_MISC: {
        if (vroot) {
            if (virAsprintf(&path, "%s/%s", vroot,
1402
                            dev->source.caps.u.misc.chardev) < 0)
1403 1404
                return -1;
        } else {
1405
            if (VIR_STRDUP(path, dev->source.caps.u.misc.chardev) < 0)
1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421
                return -1;
        }
        ret = virSecuritySELinuxSetFilecon(path, secdef->imagelabel);
        VIR_FREE(path);
        break;
    }

    default:
        ret = 0;
        break;
    }

    return ret;
}


1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441
static int
virSecuritySELinuxSetSecurityHostdevLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
                                          virDomainDefPtr def,
                                          virDomainHostdevDefPtr dev,
                                          const char *vroot)

{
    virSecurityLabelDefPtr secdef;

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

    if (secdef->norelabel)
        return 0;

    switch (dev->mode) {
    case VIR_DOMAIN_HOSTDEV_MODE_SUBSYS:
        return virSecuritySELinuxSetSecurityHostdevSubsysLabel(def, dev, vroot);

1442 1443 1444
    case VIR_DOMAIN_HOSTDEV_MODE_CAPABILITIES:
        return virSecuritySELinuxSetSecurityHostdevCapsLabel(def, dev, vroot);

1445 1446 1447 1448 1449
    default:
        return 0;
    }
}

1450
static int
1451
virSecuritySELinuxRestoreSecurityPCILabel(virPCIDevicePtr dev ATTRIBUTE_UNUSED,
1452
                                          const char *file,
1453
                                          void *opaque)
1454
{
1455 1456 1457
    virSecurityManagerPtr mgr = opaque;

    return virSecuritySELinuxRestoreSecurityFileLabel(mgr, file);
1458 1459 1460
}

static int
1461
virSecuritySELinuxRestoreSecurityUSBLabel(virUSBDevicePtr dev ATTRIBUTE_UNUSED,
1462
                                          const char *file,
1463
                                          void *opaque)
1464
{
1465 1466 1467
    virSecurityManagerPtr mgr = opaque;

    return virSecuritySELinuxRestoreSecurityFileLabel(mgr, file);
1468 1469
}

1470

1471 1472 1473 1474 1475 1476 1477 1478 1479 1480
static int
virSecuritySELinuxRestoreSecuritySCSILabel(virSCSIDevicePtr dev ATTRIBUTE_UNUSED,
                                           const char *file,
                                           void *opaque)
{
    virSecurityManagerPtr mgr = opaque;

    return virSecuritySELinuxRestoreSecurityFileLabel(mgr, file);
}

1481
static int
1482 1483
virSecuritySELinuxRestoreSecurityHostdevSubsysLabel(virSecurityManagerPtr mgr,
                                                    virDomainHostdevDefPtr dev,
1484
                                                    const char *vroot)
1485 1486 1487 1488 1489 1490

{
    int ret = -1;

    switch (dev->source.subsys.type) {
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB: {
1491
        virUSBDevicePtr usb;
1492 1493 1494

        if (dev->missing)
            return 0;
1495

1496 1497 1498
        usb = virUSBDeviceNew(dev->source.subsys.u.usb.bus,
                              dev->source.subsys.u.usb.device,
                              vroot);
1499 1500 1501
        if (!usb)
            goto done;

1502 1503
        ret = virUSBDeviceFileIterate(usb, virSecuritySELinuxRestoreSecurityUSBLabel, mgr);
        virUSBDeviceFree(usb);
1504 1505 1506 1507 1508

        break;
    }

    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI: {
1509
        virPCIDevicePtr pci =
1510 1511 1512 1513
            virPCIDeviceNew(dev->source.subsys.u.pci.addr.domain,
                            dev->source.subsys.u.pci.addr.bus,
                            dev->source.subsys.u.pci.addr.slot,
                            dev->source.subsys.u.pci.addr.function);
1514 1515 1516 1517

        if (!pci)
            goto done;

1518
        if (dev->source.subsys.u.pci.backend
1519
            == VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO) {
1520
            char *vfioGroupDev = virPCIDeviceGetIOMMUGroupDev(pci);
1521

1522 1523
            if (!vfioGroupDev) {
                virPCIDeviceFree(pci);
1524
                goto done;
1525
            }
1526 1527 1528 1529 1530
            ret = virSecuritySELinuxRestoreSecurityPCILabel(pci, vfioGroupDev, mgr);
            VIR_FREE(vfioGroupDev);
        } else {
            ret = virPCIDeviceFileIterate(pci, virSecuritySELinuxRestoreSecurityPCILabel, mgr);
        }
1531
        virPCIDeviceFree(pci);
1532 1533 1534
        break;
    }

1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI: {
        virSCSIDevicePtr scsi =
            virSCSIDeviceNew(dev->source.subsys.u.scsi.adapter,
                             dev->source.subsys.u.scsi.bus,
                             dev->source.subsys.u.scsi.target,
                             dev->source.subsys.u.scsi.unit,
                             dev->readonly);

            if (!scsi)
                goto done;

            ret = virSCSIDeviceFileIterate(scsi, virSecuritySELinuxRestoreSecuritySCSILabel, mgr);
            virSCSIDeviceFree(scsi);

            break;
       }

1552 1553 1554 1555 1556 1557 1558 1559 1560
    default:
        ret = 0;
        break;
    }

done:
    return ret;
}

1561

1562
static int
1563 1564
virSecuritySELinuxRestoreSecurityHostdevCapsLabel(virSecurityManagerPtr mgr,
                                                  virDomainHostdevDefPtr dev,
1565 1566 1567 1568 1569 1570 1571 1572 1573
                                                  const char *vroot)
{
    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,
1574
                            dev->source.caps.u.storage.block) < 0)
1575 1576
                return -1;
        } else {
1577
            if (VIR_STRDUP(path, dev->source.caps.u.storage.block) < 0)
1578 1579
                return -1;
        }
1580
        ret = virSecuritySELinuxRestoreSecurityFileLabel(mgr, path);
1581 1582 1583 1584 1585 1586 1587
        VIR_FREE(path);
        break;
    }

    case VIR_DOMAIN_HOSTDEV_CAPS_TYPE_MISC: {
        if (vroot) {
            if (virAsprintf(&path, "%s/%s", vroot,
1588
                            dev->source.caps.u.misc.chardev) < 0)
1589 1590
                return -1;
        } else {
1591
            if (VIR_STRDUP(path, dev->source.caps.u.misc.chardev) < 0)
1592 1593
                return -1;
        }
1594
        ret = virSecuritySELinuxRestoreSecurityFileLabel(mgr, path);
1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607
        VIR_FREE(path);
        break;
    }

    default:
        ret = 0;
        break;
    }

    return ret;
}


1608
static int
1609
virSecuritySELinuxRestoreSecurityHostdevLabel(virSecurityManagerPtr mgr,
1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625
                                              virDomainDefPtr def,
                                              virDomainHostdevDefPtr dev,
                                              const char *vroot)

{
    virSecurityLabelDefPtr secdef;

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

    if (secdef->norelabel)
        return 0;

    switch (dev->mode) {
    case VIR_DOMAIN_HOSTDEV_MODE_SUBSYS:
1626
        return virSecuritySELinuxRestoreSecurityHostdevSubsysLabel(mgr, dev, vroot);
1627

1628
    case VIR_DOMAIN_HOSTDEV_MODE_CAPABILITIES:
1629
        return virSecuritySELinuxRestoreSecurityHostdevCapsLabel(mgr, dev, vroot);
1630

1631 1632 1633 1634 1635 1636
    default:
        return 0;
    }
}


1637
static int
1638
virSecuritySELinuxSetSecurityChardevLabel(virDomainDefPtr def,
1639 1640
                                          virDomainChrDefPtr dev,
                                          virDomainChrSourceDefPtr dev_source)
1641 1642

{
1643 1644 1645
    virSecurityLabelDefPtr seclabel;
    virSecurityDeviceLabelDefPtr chr_seclabel = NULL;
    char *imagelabel = NULL;
1646 1647 1648
    char *in = NULL, *out = NULL;
    int ret = -1;

1649 1650
    seclabel = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
    if (seclabel == NULL)
1651 1652
        return -1;

1653 1654 1655 1656 1657
    if (dev)
        chr_seclabel = virDomainChrDefGetSecurityLabelDef(dev,
                                                          SECURITY_SELINUX_NAME);

    if (seclabel->norelabel || (chr_seclabel && chr_seclabel->norelabel))
1658 1659
        return 0;

1660 1661 1662 1663 1664 1665
    if (chr_seclabel)
        imagelabel = chr_seclabel->label;
    if (!imagelabel)
        imagelabel = seclabel->imagelabel;

    switch (dev_source->type) {
1666 1667
    case VIR_DOMAIN_CHR_TYPE_DEV:
    case VIR_DOMAIN_CHR_TYPE_FILE:
1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678
        ret = virSecuritySELinuxSetFilecon(dev_source->data.file.path,
                                           imagelabel);
        break;

    case VIR_DOMAIN_CHR_TYPE_UNIX:
        if (!dev_source->data.nix.listen) {
            if (virSecuritySELinuxSetFilecon(dev_source->data.file.path,
                                             imagelabel) < 0)
                goto done;
        }
        ret = 0;
1679 1680 1681
        break;

    case VIR_DOMAIN_CHR_TYPE_PIPE:
1682
        if ((virAsprintf(&in, "%s.in", dev_source->data.file.path) < 0) ||
1683
            (virAsprintf(&out, "%s.out", dev_source->data.file.path) < 0))
1684 1685
            goto done;
        if (virFileExists(in) && virFileExists(out)) {
1686 1687
            if ((virSecuritySELinuxSetFilecon(in, imagelabel) < 0) ||
                (virSecuritySELinuxSetFilecon(out, imagelabel) < 0)) {
1688
                goto done;
1689
            }
1690 1691
        } else if (virSecuritySELinuxSetFilecon(dev_source->data.file.path,
                                                imagelabel) < 0) {
1692
            goto done;
1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708
        }
        ret = 0;
        break;

    default:
        ret = 0;
        break;
    }

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

static int
1709 1710
virSecuritySELinuxRestoreSecurityChardevLabel(virSecurityManagerPtr mgr,
                                              virDomainDefPtr def,
1711 1712
                                              virDomainChrDefPtr dev,
                                              virDomainChrSourceDefPtr dev_source)
1713 1714

{
1715 1716
    virSecurityLabelDefPtr seclabel;
    virSecurityDeviceLabelDefPtr chr_seclabel = NULL;
1717 1718 1719
    char *in = NULL, *out = NULL;
    int ret = -1;

1720 1721
    seclabel = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
    if (seclabel == NULL)
1722 1723
        return -1;

1724 1725 1726 1727
    if (dev)
        chr_seclabel = virDomainChrDefGetSecurityLabelDef(dev,
                                                          SECURITY_SELINUX_NAME);
    if (seclabel->norelabel || (chr_seclabel && chr_seclabel->norelabel))
1728 1729
        return 0;

1730
    switch (dev_source->type) {
1731 1732
    case VIR_DOMAIN_CHR_TYPE_DEV:
    case VIR_DOMAIN_CHR_TYPE_FILE:
1733
        if (virSecuritySELinuxRestoreSecurityFileLabel(mgr, dev_source->data.file.path) < 0)
1734 1735
            goto done;
        ret = 0;
1736
        break;
1737 1738 1739

    case VIR_DOMAIN_CHR_TYPE_UNIX:
        if (!dev_source->data.nix.listen) {
1740
            if (virSecuritySELinuxRestoreSecurityFileLabel(mgr, dev_source->data.file.path) < 0)
1741 1742 1743 1744 1745
                goto done;
        }
        ret = 0;
        break;

1746
    case VIR_DOMAIN_CHR_TYPE_PIPE:
1747
        if ((virAsprintf(&out, "%s.out", dev_source->data.file.path) < 0) ||
1748
            (virAsprintf(&in, "%s.in", dev_source->data.file.path) < 0))
1749
            goto done;
1750
        if (virFileExists(in) && virFileExists(out)) {
1751 1752
            if ((virSecuritySELinuxRestoreSecurityFileLabel(mgr, out) < 0) ||
                (virSecuritySELinuxRestoreSecurityFileLabel(mgr, in) < 0)) {
1753 1754
                goto done;
            }
1755
        } else if (virSecuritySELinuxRestoreSecurityFileLabel(mgr, dev_source->data.file.path) < 0) {
1756
            goto done;
1757
        }
1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773
        ret = 0;
        break;

    default:
        ret = 0;
        break;
    }

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


static int
1774 1775
virSecuritySELinuxRestoreSecurityChardevCallback(virDomainDefPtr def,
                                                 virDomainChrDefPtr dev,
1776
                                                 void *opaque)
1777
{
1778 1779
    virSecurityManagerPtr mgr = opaque;

1780 1781 1782 1783 1784
    /* 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;

1785
    return virSecuritySELinuxRestoreSecurityChardevLabel(mgr, def, dev,
1786
                                                         &dev->source);
1787 1788 1789
}


E
Eric Blake 已提交
1790
static int
1791 1792
virSecuritySELinuxRestoreSecuritySmartcardCallback(virDomainDefPtr def,
                                                   virDomainSmartcardDefPtr dev,
1793
                                                   void *opaque)
E
Eric Blake 已提交
1794
{
1795
    virSecurityManagerPtr mgr = opaque;
E
Eric Blake 已提交
1796 1797 1798 1799 1800 1801 1802 1803 1804 1805
    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;
1806
        return virSecuritySELinuxRestoreSecurityFileLabel(mgr, database);
E
Eric Blake 已提交
1807 1808

    case VIR_DOMAIN_SMARTCARD_TYPE_PASSTHROUGH:
1809
        return virSecuritySELinuxRestoreSecurityChardevLabel(mgr, def, NULL, &dev->data.passthru);
E
Eric Blake 已提交
1810 1811

    default:
1812 1813 1814
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unknown smartcard type %d"),
                       dev->type);
E
Eric Blake 已提交
1815 1816 1817 1818 1819 1820 1821
        return -1;
    }

    return 0;
}


1822
static int
1823
virSecuritySELinuxRestoreSecurityAllLabel(virSecurityManagerPtr mgr,
1824 1825
                                          virDomainDefPtr def,
                                          int migrated ATTRIBUTE_UNUSED)
1826
{
1827
    virSecurityLabelDefPtr secdef;
1828
    virSecuritySELinuxDataPtr data = virSecurityManagerGetPrivateData(mgr);
1829 1830
    int i;
    int rc = 0;
1831

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

1834 1835 1836 1837
    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
    if (secdef == NULL)
        return -1;

1838
    if (secdef->norelabel || data->skipAllLabel)
1839 1840
        return 0;

1841 1842 1843 1844 1845 1846
    if (def->tpm) {
        if (virSecuritySELinuxRestoreSecurityTPMFileLabelInt(mgr, def,
                                                             def->tpm) < 0)
            rc = -1;
    }

1847
    for (i = 0; i < def->nhostdevs; i++) {
1848 1849
        if (virSecuritySELinuxRestoreSecurityHostdevLabel(mgr,
                                                          def,
1850 1851
                                                          def->hostdevs[i],
                                                          NULL) < 0)
1852
            rc = -1;
1853
    }
1854
    for (i = 0; i < def->ndisks; i++) {
1855 1856 1857 1858
        if (virSecuritySELinuxRestoreSecurityImageLabelInt(mgr,
                                                           def,
                                                           def->disks[i],
                                                           migrated) < 0)
1859 1860
            rc = -1;
    }
1861

1862
    if (virDomainChrDefForeach(def,
1863
                               false,
1864
                               virSecuritySELinuxRestoreSecurityChardevCallback,
1865
                               mgr) < 0)
1866 1867
        rc = -1;

1868
    if (virDomainSmartcardDefForeach(def,
E
Eric Blake 已提交
1869
                                     false,
1870
                                     virSecuritySELinuxRestoreSecuritySmartcardCallback,
1871
                                     mgr) < 0)
E
Eric Blake 已提交
1872 1873
        rc = -1;

1874
    if (def->os.kernel &&
1875
        virSecuritySELinuxRestoreSecurityFileLabel(mgr, def->os.kernel) < 0)
1876 1877
        rc = -1;

1878
    if (def->os.initrd &&
1879
        virSecuritySELinuxRestoreSecurityFileLabel(mgr, def->os.initrd) < 0)
1880 1881
        rc = -1;

O
Olivia Yin 已提交
1882 1883 1884 1885
    if (def->os.dtb &&
        virSecuritySELinuxRestoreSecurityFileLabel(mgr, def->os.dtb) < 0)
        rc = -1;

1886 1887 1888 1889
    return rc;
}

static int
1890
virSecuritySELinuxReleaseSecurityLabel(virSecurityManagerPtr mgr,
1891
                                       virDomainDefPtr def)
1892
{
1893 1894 1895 1896 1897
    virSecurityLabelDefPtr secdef;

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

1899 1900 1901 1902
    if (secdef->type == VIR_DOMAIN_SECLABEL_DYNAMIC) {
        if (secdef->label != NULL) {
            context_t con = context_new(secdef->label);
            if (con) {
1903
                virSecuritySELinuxMCSRemove(mgr, context_range_get(con));
1904 1905 1906 1907 1908 1909
                context_free(con);
            }
        }
        VIR_FREE(secdef->label);
        if (!secdef->baselabel)
            VIR_FREE(secdef->model);
1910 1911 1912
    }
    VIR_FREE(secdef->imagelabel);

1913
    return 0;
1914 1915
}

1916 1917

static int
1918 1919 1920
virSecuritySELinuxSetSavedStateLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
                                     virDomainDefPtr def,
                                     const char *savefile)
1921
{
1922 1923 1924 1925 1926
    virSecurityLabelDefPtr secdef;

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

1928
    if (secdef->norelabel)
1929 1930
        return 0;

1931
    return virSecuritySELinuxSetFilecon(savefile, secdef->imagelabel);
1932 1933 1934 1935
}


static int
1936
virSecuritySELinuxRestoreSavedStateLabel(virSecurityManagerPtr mgr,
1937 1938
                                         virDomainDefPtr def,
                                         const char *savefile)
1939
{
1940 1941 1942 1943 1944
    virSecurityLabelDefPtr secdef;

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

1946
    if (secdef->norelabel)
1947 1948
        return 0;

1949
    return virSecuritySELinuxRestoreSecurityFileLabel(mgr, savefile);
1950 1951 1952
}


1953
static int
1954 1955
virSecuritySELinuxSecurityVerify(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
                                 virDomainDefPtr def)
1956
{
1957 1958 1959 1960 1961 1962
    virSecurityLabelDefPtr secdef;

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

1963
    if (!STREQ(SECURITY_SELINUX_NAME, secdef->model)) {
1964 1965 1966 1967
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("security label driver mismatch: "
                         "'%s' model configured for domain, but "
                         "hypervisor driver is '%s'."),
1968
                       secdef->model, SECURITY_SELINUX_NAME);
1969 1970 1971
        return -1;
    }

1972 1973
    if (secdef->type == VIR_DOMAIN_SECLABEL_STATIC) {
        if (security_check_context(secdef->label) != 0) {
1974 1975
            virReportError(VIR_ERR_XML_ERROR,
                           _("Invalid security label %s"), secdef->label);
1976 1977 1978 1979 1980 1981
            return -1;
        }
    }
    return 0;
}

1982
static int
1983
virSecuritySELinuxSetSecurityProcessLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
1984
                                          virDomainDefPtr def)
1985 1986
{
    /* TODO: verify DOI */
1987 1988 1989 1990 1991
    virSecurityLabelDefPtr secdef;

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

1993
    if (secdef->label == NULL)
1994 1995
        return 0;

1996
    VIR_DEBUG("label=%s", secdef->label);
1997
    if (!STREQ(SECURITY_SELINUX_NAME, secdef->model)) {
1998 1999 2000 2001
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("security label driver mismatch: "
                         "'%s' model configured for domain, but "
                         "hypervisor driver is '%s'."),
2002
                       secdef->model, SECURITY_SELINUX_NAME);
2003
        if (security_getenforce() == 1)
2004
            return -1;
2005 2006
    }

M
Martin Kletzander 已提交
2007
    if (setexeccon_raw(secdef->label) == -1) {
2008
        virReportSystemError(errno,
2009 2010
                             _("unable to set security context '%s'"),
                             secdef->label);
2011
        if (security_getenforce() == 1)
2012
            return -1;
2013 2014
    }

2015 2016 2017
    return 0;
}

2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048
static int
virSecuritySELinuxSetSecurityChildProcessLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
                                               virDomainDefPtr def,
                                               virCommandPtr cmd)
{
    /* TODO: verify DOI */
    virSecurityLabelDefPtr secdef;

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

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

    VIR_DEBUG("label=%s", secdef->label);
    if (!STREQ(SECURITY_SELINUX_NAME, secdef->model)) {
        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;
}

2049
static int
2050
virSecuritySELinuxSetSecurityDaemonSocketLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
2051
                                               virDomainDefPtr def)
2052 2053
{
    /* TODO: verify DOI */
2054
    virSecurityLabelDefPtr secdef;
2055
    security_context_t scon = NULL;
2056
    char *str = NULL;
2057 2058
    int rc = -1;

2059 2060 2061 2062 2063
    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
    if (secdef == NULL)
        return -1;

    if (secdef->label == NULL)
2064 2065
        return 0;

2066
    if (!STREQ(SECURITY_SELINUX_NAME, secdef->model)) {
2067 2068 2069 2070
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("security label driver mismatch: "
                         "'%s' model configured for domain, but "
                         "hypervisor driver is '%s'."),
2071
                       secdef->model, SECURITY_SELINUX_NAME);
2072 2073 2074
        goto done;
    }

M
Martin Kletzander 已提交
2075
    if (getcon_raw(&scon) == -1) {
2076 2077 2078 2079 2080 2081
        virReportSystemError(errno,
                             _("unable to get current process context '%s'"),
                             secdef->label);
        goto done;
    }

2082
    if (!(str = virSecuritySELinuxContextAddRange(secdef->label, scon)))
2083 2084
        goto done;

2085 2086
    VIR_DEBUG("Setting VM %s socket context %s", def->name, str);
    if (setsockcreatecon_raw(str) == -1) {
2087
        virReportSystemError(errno,
2088
                             _("unable to set socket security context '%s'"), str);
2089 2090 2091 2092 2093 2094 2095 2096 2097
        goto done;
    }

    rc = 0;
done:

    if (security_getenforce() != 1)
        rc = 0;
    freecon(scon);
2098
    VIR_FREE(str);
2099 2100 2101
    return rc;
}

2102
static int
2103
virSecuritySELinuxSetSecuritySocketLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
2104
                                         virDomainDefPtr vm)
2105
{
2106
    virSecurityLabelDefPtr secdef;
2107 2108
    int rc = -1;

2109 2110 2111 2112
    secdef = virDomainDefGetSecurityLabelDef(vm, SECURITY_SELINUX_NAME);
    if (secdef == NULL)
        return -1;

2113 2114 2115
    if (secdef->label == NULL)
        return 0;

2116
    if (!STREQ(SECURITY_SELINUX_NAME, secdef->model)) {
2117 2118 2119 2120
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("security label driver mismatch: "
                         "'%s' model configured for domain, but "
                         "hypervisor driver is '%s'."),
2121
                       secdef->model, SECURITY_SELINUX_NAME);
2122 2123 2124 2125
        goto done;
    }

    VIR_DEBUG("Setting VM %s socket context %s",
2126
              vm->name, secdef->label);
M
Martin Kletzander 已提交
2127
    if (setsockcreatecon_raw(secdef->label) == -1) {
2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142
        virReportSystemError(errno,
                             _("unable to set socket security context '%s'"),
                             secdef->label);
        goto done;
    }

    rc = 0;

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

    return rc;
}

2143
static int
2144
virSecuritySELinuxClearSecuritySocketLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
2145
                                           virDomainDefPtr def)
2146 2147
{
    /* TODO: verify DOI */
2148 2149 2150 2151 2152
    virSecurityLabelDefPtr secdef;

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

2154
    if (secdef->label == NULL)
2155 2156
        return 0;

2157
    if (!STREQ(SECURITY_SELINUX_NAME, secdef->model)) {
2158 2159 2160 2161
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("security label driver mismatch: "
                         "'%s' model configured for domain, but "
                         "hypervisor driver is '%s'."),
2162
                       secdef->model, SECURITY_SELINUX_NAME);
2163 2164 2165 2166
        if (security_getenforce() == 1)
            return -1;
    }

M
Martin Kletzander 已提交
2167
    if (setsockcreatecon_raw(NULL) == -1) {
2168 2169 2170 2171 2172 2173 2174 2175 2176
        virReportSystemError(errno,
                             _("unable to clear socket security context '%s'"),
                             secdef->label);
        if (security_getenforce() == 1)
            return -1;
    }
    return 0;
}

2177 2178

static int
2179 2180 2181
virSecuritySELinuxSetSecurityChardevCallback(virDomainDefPtr def,
                                             virDomainChrDefPtr dev,
                                             void *opaque ATTRIBUTE_UNUSED)
2182
{
2183 2184 2185 2186 2187
    /* 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;

2188
    return virSecuritySELinuxSetSecurityChardevLabel(def, dev, &dev->source);
2189 2190 2191
}


E
Eric Blake 已提交
2192
static int
2193 2194 2195
virSecuritySELinuxSetSecuritySmartcardCallback(virDomainDefPtr def,
                                               virDomainSmartcardDefPtr dev,
                                               void *opaque)
E
Eric Blake 已提交
2196 2197
{
    const char *database;
2198 2199
    virSecurityManagerPtr mgr = opaque;
    virSecuritySELinuxDataPtr data = virSecurityManagerGetPrivateData(mgr);
E
Eric Blake 已提交
2200 2201 2202 2203 2204 2205 2206 2207 2208

    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;
2209
        return virSecuritySELinuxSetFilecon(database, data->content_context);
E
Eric Blake 已提交
2210 2211

    case VIR_DOMAIN_SMARTCARD_TYPE_PASSTHROUGH:
2212
        return virSecuritySELinuxSetSecurityChardevLabel(def, NULL, &dev->data.passthru);
E
Eric Blake 已提交
2213 2214

    default:
2215 2216 2217
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unknown smartcard type %d"),
                       dev->type);
E
Eric Blake 已提交
2218 2219 2220 2221 2222 2223 2224
        return -1;
    }

    return 0;
}


2225
static int
2226 2227 2228
virSecuritySELinuxSetSecurityAllLabel(virSecurityManagerPtr mgr,
                                      virDomainDefPtr def,
                                      const char *stdin_path)
2229 2230
{
    int i;
2231 2232 2233 2234 2235 2236
    virSecuritySELinuxDataPtr data = virSecurityManagerGetPrivateData(mgr);
    virSecurityLabelDefPtr secdef;

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

2238
    if (secdef->norelabel || data->skipAllLabel)
2239 2240
        return 0;

2241
    for (i = 0; i < def->ndisks; i++) {
2242
        /* XXX fixme - we need to recursively label the entire tree :-( */
2243
        if (def->disks[i]->type == VIR_DOMAIN_DISK_TYPE_DIR) {
2244
            VIR_WARN("Unable to relabel directory tree %s for disk %s",
2245
                     def->disks[i]->src, def->disks[i]->dst);
2246
            continue;
2247
        }
2248
        if (virSecuritySELinuxSetSecurityImageLabel(mgr,
2249
                                         def, def->disks[i]) < 0)
2250 2251
            return -1;
    }
2252
    /* XXX fixme process  def->fss if relabel == true */
2253

2254
    for (i = 0; i < def->nhostdevs; i++) {
2255
        if (virSecuritySELinuxSetSecurityHostdevLabel(mgr,
2256 2257 2258
                                                      def,
                                                      def->hostdevs[i],
                                                      NULL) < 0)
2259
            return -1;
2260
    }
2261 2262 2263 2264 2265
    if (def->tpm) {
        if (virSecuritySELinuxSetSecurityTPMFileLabel(mgr, def,
                                                      def->tpm) < 0)
            return -1;
    }
2266

2267
    if (virDomainChrDefForeach(def,
2268
                               true,
2269
                               virSecuritySELinuxSetSecurityChardevCallback,
2270
                               NULL) < 0)
2271 2272
        return -1;

2273
    if (virDomainSmartcardDefForeach(def,
E
Eric Blake 已提交
2274
                                     true,
2275
                                     virSecuritySELinuxSetSecuritySmartcardCallback,
2276
                                     mgr) < 0)
E
Eric Blake 已提交
2277 2278
        return -1;

2279
    if (def->os.kernel &&
2280
        virSecuritySELinuxSetFilecon(def->os.kernel, data->content_context) < 0)
2281 2282
        return -1;

2283
    if (def->os.initrd &&
2284
        virSecuritySELinuxSetFilecon(def->os.initrd, data->content_context) < 0)
2285 2286
        return -1;

O
Olivia Yin 已提交
2287 2288 2289 2290
    if (def->os.dtb &&
        virSecuritySELinuxSetFilecon(def->os.dtb, data->content_context) < 0)
        return -1;

2291
    if (stdin_path) {
2292
        if (virSecuritySELinuxSetFilecon(stdin_path, data->content_context) < 0 &&
2293 2294 2295 2296
            virStorageFileIsSharedFSType(stdin_path,
                                         VIR_STORAGE_FILE_SHFS_NFS) != 1)
            return -1;
    }
2297

2298 2299 2300
    return 0;
}

2301
static int
2302 2303 2304
virSecuritySELinuxSetImageFDLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
                                  virDomainDefPtr def,
                                  int fd)
2305
{
2306 2307 2308 2309 2310
    virSecurityLabelDefPtr secdef;

    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
    if (secdef == NULL)
        return -1;
2311 2312 2313 2314

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

2315
    return virSecuritySELinuxFSetFilecon(fd, secdef->imagelabel);
2316 2317
}

2318
static int
2319
virSecuritySELinuxSetTapFDLabel(virSecurityManagerPtr mgr,
2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346
                                virDomainDefPtr def,
                                int fd)
{
    struct stat buf;
    security_context_t fcon = NULL;
    virSecurityLabelDefPtr secdef;
    char *str = NULL;
    int rc = -1;

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

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

    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;
    }

2347
    if (getContext(mgr, "/dev/tap.*", buf.st_mode, &fcon) < 0) {
2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364
        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);
    VIR_FREE(str);
    return rc;
}

2365 2366 2367 2368
static char *
virSecuritySELinuxGenImageLabel(virSecurityManagerPtr mgr,
                                virDomainDefPtr def)
{
2369
    virSecurityLabelDefPtr secdef;
2370 2371 2372 2373
    virSecuritySELinuxDataPtr data = virSecurityManagerGetPrivateData(mgr);
    const char *range;
    context_t ctx = NULL;
    char *label = NULL;
2374
    char *mcs = NULL;
2375

2376 2377 2378 2379
    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
    if (secdef == NULL)
        goto cleanup;

2380 2381 2382
    if (secdef->label) {
        ctx = context_new(secdef->label);
        if (!ctx) {
2383 2384
            virReportSystemError(errno, _("unable to create selinux context for: %s"),
                                 secdef->label);
2385 2386 2387 2388
            goto cleanup;
        }
        range = context_range_get(ctx);
        if (range) {
2389
            if (VIR_STRDUP(mcs, range) < 0)
2390
                goto cleanup;
2391 2392
            if (!(label = virSecuritySELinuxGenNewContext(data->file_context,
                                                          mcs, true)))
2393 2394 2395 2396 2397
                goto cleanup;
        }
    }

cleanup:
2398 2399 2400
    context_free(ctx);
    VIR_FREE(mcs);
    return label;
2401 2402
}

2403 2404 2405 2406
static char *
virSecuritySELinuxGetSecurityMountOptions(virSecurityManagerPtr mgr,
                                          virDomainDefPtr def)
{
2407
    char *opts = NULL;
2408 2409
    virSecurityLabelDefPtr secdef;

2410 2411 2412 2413 2414 2415 2416
    if ((secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME))) {
        if (!secdef->imagelabel)
            secdef->imagelabel = virSecuritySELinuxGenImageLabel(mgr, def);

        if (secdef->imagelabel &&
            virAsprintf(&opts,
                        ",context=\"%s\"",
2417
                        (const char*) secdef->imagelabel) < 0)
2418 2419
            return NULL;
    }
2420

2421
    if (!opts && VIR_STRDUP(opts, "") < 0)
2422
        return NULL;
2423

2424 2425
    VIR_DEBUG("imageLabel=%s opts=%s",
              secdef ? secdef->imagelabel : "(null)", opts);
2426 2427 2428
    return opts;
}

2429
virSecurityDriver virSecurityDriverSELinux = {
2430 2431
    .privateDataLen                     = sizeof(virSecuritySELinuxData),
    .name                               = SECURITY_SELINUX_NAME,
2432 2433 2434
    .probe                              = virSecuritySELinuxSecurityDriverProbe,
    .open                               = virSecuritySELinuxSecurityDriverOpen,
    .close                              = virSecuritySELinuxSecurityDriverClose,
2435

2436 2437
    .getModel                           = virSecuritySELinuxSecurityGetModel,
    .getDOI                             = virSecuritySELinuxSecurityGetDOI,
2438

2439
    .domainSecurityVerify               = virSecuritySELinuxSecurityVerify,
2440

2441 2442
    .domainSetSecurityImageLabel        = virSecuritySELinuxSetSecurityImageLabel,
    .domainRestoreSecurityImageLabel    = virSecuritySELinuxRestoreSecurityImageLabel,
2443

2444 2445 2446
    .domainSetSecurityDaemonSocketLabel = virSecuritySELinuxSetSecurityDaemonSocketLabel,
    .domainSetSecuritySocketLabel       = virSecuritySELinuxSetSecuritySocketLabel,
    .domainClearSecuritySocketLabel     = virSecuritySELinuxClearSecuritySocketLabel,
2447

2448 2449 2450
    .domainGenSecurityLabel             = virSecuritySELinuxGenSecurityLabel,
    .domainReserveSecurityLabel         = virSecuritySELinuxReserveSecurityLabel,
    .domainReleaseSecurityLabel         = virSecuritySELinuxReleaseSecurityLabel,
2451

2452 2453
    .domainGetSecurityProcessLabel      = virSecuritySELinuxGetSecurityProcessLabel,
    .domainSetSecurityProcessLabel      = virSecuritySELinuxSetSecurityProcessLabel,
2454
    .domainSetSecurityChildProcessLabel = virSecuritySELinuxSetSecurityChildProcessLabel,
2455

2456 2457
    .domainSetSecurityAllLabel          = virSecuritySELinuxSetSecurityAllLabel,
    .domainRestoreSecurityAllLabel      = virSecuritySELinuxRestoreSecurityAllLabel,
2458

2459 2460
    .domainSetSecurityHostdevLabel      = virSecuritySELinuxSetSecurityHostdevLabel,
    .domainRestoreSecurityHostdevLabel  = virSecuritySELinuxRestoreSecurityHostdevLabel,
2461

2462 2463
    .domainSetSavedStateLabel           = virSecuritySELinuxSetSavedStateLabel,
    .domainRestoreSavedStateLabel       = virSecuritySELinuxRestoreSavedStateLabel,
2464

2465
    .domainSetSecurityImageFDLabel      = virSecuritySELinuxSetImageFDLabel,
2466
    .domainSetSecurityTapFDLabel        = virSecuritySELinuxSetTapFDLabel,
2467

2468
    .domainGetSecurityMountOptions      = virSecuritySELinuxGetSecurityMountOptions,
2469
};