security_selinux.c 79.2 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 "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
VIR_LOG_INIT("security.security_selinux");

54 55 56 57 58 59 60
#define MAX_CONTEXT 1024

typedef struct _virSecuritySELinuxData virSecuritySELinuxData;
typedef virSecuritySELinuxData *virSecuritySELinuxDataPtr;

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

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

74 75 76 77 78 79
/* Data structure to pass to *FileIterate so we have everything we need */
struct SELinuxSCSICallbackData {
    virSecurityManagerPtr mgr;
    virDomainDefPtr def;
};

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
 * 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 已提交
179
 * mode when run with a weird process label.
180
 */
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
    /* If there was no category part, just assume c0.c1023 */
222 223
    if (!cat) {
        *catMin = 0;
224
        *catMax = 1023;
225 226 227 228
        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
 cleanup:
318 319 320 321
    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
    if (!(selinux_conf = virConfReadFile(selinux_lxc_contexts_path(), 0)))
418
        goto error;
419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443

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

444 445 446
    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)
447
        goto error;
448 449 450 451

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

452 453 454
    virConfFree(selinux_conf);
    return 0;

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


static int
479
virSecuritySELinuxQEMUInitialize(virSecurityManagerPtr mgr)
480
{
481 482
    char *ptr;
    virSecuritySELinuxDataPtr data = virSecurityManagerGetPrivateData(mgr);
483

484 485
    data->skipAllLabel = false;

486 487 488 489 490 491 492 493 494
#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

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

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

517

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

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

535 536 537
    VIR_DEBUG("Loaded file context '%s', content context '%s'",
              data->file_context, data->content_context);

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

541
    return 0;
542

543
 error:
544 545
#if HAVE_SELINUX_LABEL_H
    selabel_close(data->label_handle);
546
    data->label_handle = NULL;
547
#endif
548
    VIR_FREE(data->domain_context);
549
    VIR_FREE(data->alt_domain_context);
550 551
    VIR_FREE(data->file_context);
    VIR_FREE(data->content_context);
552
    virHashFree(data->mcs);
553
    return -1;
554 555
}

556 557

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


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

584
    seclabel = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
P
Peter Krempa 已提交
585
    if (seclabel == NULL)
586
        return 0;
587 588 589 590 591 592

    data = virSecurityManagerGetPrivateData(mgr);

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

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

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

612
    VIR_DEBUG("type=%d", seclabel->type);
613

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

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

    case VIR_DOMAIN_SECLABEL_DYNAMIC:
632 633 634 635 636 637 638 639 640
        if (virSecuritySELinuxMCSGetProcessRange(&sens,
                                                 &catMin,
                                                 &catMax) < 0)
            goto cleanup;

        if (!(mcs = virSecuritySELinuxMCSFind(mgr,
                                              sens,
                                              catMin,
                                              catMax)))
641 642 643 644
            goto cleanup;

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

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

666 667
        seclabel->label = virSecuritySELinuxGenNewContext(baselabel, mcs, false);
        if (!seclabel->label)
668
            goto cleanup;
669

670 671 672
        break;

    case VIR_DOMAIN_SECLABEL_NONE:
673 674 675 676 677 678 679 680
        if (virSecuritySELinuxMCSGetProcessRange(&sens,
                                                 &catMin,
                                                 &catMax) < 0)
            goto cleanup;

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

681 682 683
        break;

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

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

697
    if (!seclabel->model &&
698
        VIR_STRDUP(seclabel->model, SECURITY_SELINUX_NAME) < 0)
699
        goto cleanup;
D
Daniel P. Berrange 已提交
700

701
    rc = 0;
702

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

    if (ctx)
        context_free(ctx);
D
Daniel P. Berrange 已提交
715
    VIR_FREE(scontext);
716
    VIR_FREE(mcs);
717
    VIR_FREE(sens);
718 719

    VIR_DEBUG("model=%s label=%s imagelabel=%s baselabel=%s",
720 721 722 723
              NULLSTR(seclabel->model),
              NULLSTR(seclabel->label),
              NULLSTR(seclabel->imagelabel),
              NULLSTR(seclabel->baselabel));
724

725 726 727
    return rc;
}

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

739
    seclabel = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
740 741 742
    if (!seclabel ||
        seclabel->type == VIR_DOMAIN_SECLABEL_NONE ||
        seclabel->type == VIR_DOMAIN_SECLABEL_STATIC)
743 744
        return 0;

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

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

    mcs = context_range_get(ctx);
    if (!mcs)
758 759
        goto error;

760
    if ((rv = virSecuritySELinuxMCSAdd(mgr, mcs)) < 0)
761
        goto error;
762

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

    context_free(ctx);

    return 0;

774
 error:
775 776 777 778 779
    context_free(ctx);
    return -1;
}


780
static int
781
virSecuritySELinuxSecurityDriverProbe(const char *virtDriver)
782
{
783
    if (is_selinux_enabled() <= 0)
784 785
        return SECURITY_DRIVER_DISABLE;

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

    return SECURITY_DRIVER_ENABLE;
794 795
}

796

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

803

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

    if (!data)
        return 0;

812
#if HAVE_SELINUX_LABEL_H
813 814
    if (data->label_handle)
        selabel_close(data->label_handle);
815 816
#endif

817 818
    virHashFree(data->mcs);

819
    VIR_FREE(data->domain_context);
820
    VIR_FREE(data->alt_domain_context);
821 822 823
    VIR_FREE(data->file_context);
    VIR_FREE(data->content_context);

824 825 826 827
    return 0;
}


828 829
static const char *
virSecuritySELinuxSecurityGetModel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED)
830 831 832 833
{
    return SECURITY_SELINUX_NAME;
}

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

static int
845 846 847 848
virSecuritySELinuxGetSecurityProcessLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
                                          virDomainDefPtr def ATTRIBUTE_UNUSED,
                                          pid_t pid,
                                          virSecurityLabelPtr sec)
849 850 851
{
    security_context_t ctx;

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

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

    strcpy(sec->label, (char *) ctx);
869
    freecon(ctx);
870

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

    return 0;
}

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

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

M
Martin Kletzander 已提交
892
    if (setfilecon_raw(path, tcon) < 0) {
893 894
        int setfilecon_errno = errno;

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

904 905 906 907 908
        /* 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 ...
909
         */
910 911
        if (setfilecon_errno != EOPNOTSUPP && setfilecon_errno != ENOTSUP &&
            setfilecon_errno != EROFS) {
912
            virReportSystemError(setfilecon_errno,
913
                                 _("unable to set security context '%s' on '%s'"),
914
                                 tcon, path);
915 916
            if (security_getenforce() == 1)
                return -1;
917
        } else {
918
            const char *msg;
919
            if (virFileIsSharedFSType(path, VIR_FILE_SHFS_NFS) == 1 &&
920 921 922
                security_get_boolean_active("virt_use_nfs") != 1) {
                msg = _("Setting security context '%s' on '%s' not supported. "
                        "Consider setting virt_use_nfs");
923 924 925 926
                if (security_getenforce() == 1)
                    VIR_WARN(msg, tcon, path);
                else
                    VIR_INFO(msg, tcon, path);
927 928 929 930
            } else {
                VIR_INFO("Setting security context '%s' on '%s' not supported",
                         tcon, path);
            }
931 932
            if (optional)
                return 1;
933
        }
934 935 936 937
    }
    return 0;
}

938
static int
939
virSecuritySELinuxSetFileconOptional(const char *path, char *tcon)
940
{
941
    return virSecuritySELinuxSetFileconHelper(path, tcon, true);
942 943 944
}

static int
945
virSecuritySELinuxSetFilecon(const char *path, char *tcon)
946
{
947
    return virSecuritySELinuxSetFileconHelper(path, tcon, false);
948 949
}

950
static int
951
virSecuritySELinuxFSetFilecon(int fd, char *tcon)
952 953 954 955 956
{
    security_context_t econ;

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

M
Martin Kletzander 已提交
957
    if (fsetfilecon_raw(fd, tcon) < 0) {
958 959
        int fsetfilecon_errno = errno;

M
Martin Kletzander 已提交
960
        if (fgetfilecon_raw(fd, &econ) >= 0) {
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 986 987 988
            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 已提交
989 990
/* Set fcon to the appropriate label for path and mode, or return -1.  */
static int
991
getContext(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
992
           const char *newpath, mode_t mode, security_context_t *fcon)
E
Eric Blake 已提交
993 994
{
#if HAVE_SELINUX_LABEL_H
995
    virSecuritySELinuxDataPtr data = virSecurityManagerGetPrivateData(mgr);
E
Eric Blake 已提交
996

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

1003 1004 1005

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

1016 1017
    VIR_INFO("Restoring SELinux context on '%s'", path);

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

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

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

1040
 err:
1041
    freecon(fcon);
1042 1043
    VIR_FREE(newpath);
    return rc;
1044 1045
}

1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058

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)
1059
        return 0;
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

    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)
1101
        return 0;
1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122

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


1123
static int
1124
virSecuritySELinuxRestoreSecurityImageLabelInt(virSecurityManagerPtr mgr,
1125
                                               virDomainDefPtr def,
1126
                                               virStorageSourcePtr src,
1127
                                               bool migrated)
1128
{
1129 1130
    virSecurityLabelDefPtr seclabel;
    virSecurityDeviceLabelDefPtr disk_seclabel;
1131 1132 1133

    if (!src->path || !virStorageSourceIsLocalStorage(src))
        return 0;
1134 1135 1136

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

1139
    disk_seclabel = virStorageSourceGetSecurityLabelDef(src,
1140
                                                        SECURITY_SELINUX_NAME);
1141
    if (!seclabel->relabel || (disk_seclabel && !disk_seclabel->relabel))
1142 1143
        return 0;

1144 1145 1146
    /* 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
1147
     * per-file attribute instead of a disk attribute. */
1148
    if (disk_seclabel && disk_seclabel->labelskip &&
1149
        !src->backingStore)
1150 1151
        return 0;

1152
    /* Don't restore labels on readonly/shared disks, because other VMs may
1153 1154 1155 1156 1157
     * 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)
1158 1159 1160
        return 0;


1161 1162 1163
    /* 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 :-) */
1164
    if (migrated) {
1165
        int rc = virFileIsSharedFS(src->path);
1166 1167 1168 1169
        if (rc < 0)
            return -1;
        if (rc == 1) {
            VIR_DEBUG("Skipping image label restore on %s because FS is shared",
1170
                      src->path);
1171 1172 1173 1174
            return 0;
        }
    }

1175
    return virSecuritySELinuxRestoreSecurityFileLabel(mgr, src->path);
1176 1177
}

1178 1179

static int
1180 1181 1182
virSecuritySELinuxRestoreSecurityDiskLabel(virSecurityManagerPtr mgr,
                                           virDomainDefPtr def,
                                           virDomainDiskDefPtr disk)
1183
{
1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194
    return virSecuritySELinuxRestoreSecurityImageLabelInt(mgr, def, disk->src,
                                                          false);
}


static int
virSecuritySELinuxRestoreSecurityImageLabel(virSecurityManagerPtr mgr,
                                            virDomainDefPtr def,
                                            virStorageSourcePtr src)
{
    return virSecuritySELinuxRestoreSecurityImageLabelInt(mgr, def, src, false);
1195 1196 1197
}


1198
static int
1199 1200 1201 1202
virSecuritySELinuxSetSecurityImageLabelInternal(virSecurityManagerPtr mgr,
                                                virDomainDefPtr def,
                                                virStorageSourcePtr src,
                                                bool first)
1203
{
1204 1205
    virSecuritySELinuxDataPtr data = virSecurityManagerGetPrivateData(mgr);
    virSecurityLabelDefPtr secdef;
1206
    virSecurityDeviceLabelDefPtr disk_seclabel;
1207
    int ret;
1208

1209 1210 1211 1212
    if (!src->path || !virStorageSourceIsLocalStorage(src))
        return 0;

    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
1213
    if (!secdef || !secdef->relabel)
1214 1215 1216
        return 0;

    disk_seclabel = virStorageSourceGetSecurityLabelDef(src,
1217 1218
                                                        SECURITY_SELINUX_NAME);

1219
    if (disk_seclabel && !disk_seclabel->relabel)
1220 1221
        return 0;

1222
    if (disk_seclabel && disk_seclabel->relabel && disk_seclabel->label) {
1223 1224 1225 1226 1227 1228 1229 1230
        ret = virSecuritySELinuxSetFilecon(src->path, disk_seclabel->label);
    } else if (first) {
        if (src->shared) {
            ret = virSecuritySELinuxSetFileconOptional(src->path,
                                                       data->file_context);
        } else if (src->readonly) {
            ret = virSecuritySELinuxSetFileconOptional(src->path,
                                                       data->content_context);
1231
        } else if (secdef->imagelabel) {
1232 1233
            ret = virSecuritySELinuxSetFileconOptional(src->path,
                                                       secdef->imagelabel);
1234
        } else {
1235
            ret = 0;
1236 1237
        }
    } else {
1238 1239
        ret = virSecuritySELinuxSetFileconOptional(src->path,
                                                   data->content_context);
1240
    }
1241

1242
    if (ret == 1 && !disk_seclabel) {
1243 1244
        /* If we failed to set a label, but virt_use_nfs let us
         * proceed anyway, then we don't need to relabel later.  */
1245
        disk_seclabel = virSecurityDeviceLabelDefNew(SECURITY_SELINUX_NAME);
1246
        if (!disk_seclabel)
1247
            return -1;
1248
        disk_seclabel->labelskip = true;
1249
        if (VIR_APPEND_ELEMENT(src->seclabels, src->nseclabels,
1250
                               disk_seclabel) < 0) {
1251 1252 1253
            virSecurityDeviceLabelDefFree(disk_seclabel);
            return -1;
        }
1254
        ret = 0;
1255
    }
1256

1257
    return ret;
1258 1259
}

1260 1261 1262 1263 1264 1265 1266 1267 1268 1269

static int
virSecuritySELinuxSetSecurityImageLabel(virSecurityManagerPtr mgr,
                                        virDomainDefPtr def,
                                        virStorageSourcePtr src)
{
    return virSecuritySELinuxSetSecurityImageLabelInternal(mgr, def, src, true);
}


1270
static int
1271 1272 1273
virSecuritySELinuxSetSecurityDiskLabel(virSecurityManagerPtr mgr,
                                       virDomainDefPtr def,
                                       virDomainDiskDefPtr disk)
1274 1275

{
1276 1277
    bool first = true;
    virStorageSourcePtr next;
1278

1279 1280 1281 1282
    for (next = disk->src; next; next = next->backingStore) {
        if (virSecuritySELinuxSetSecurityImageLabelInternal(mgr, def, next,
                                                            first) < 0)
            return -1;
1283

1284 1285 1286 1287
        first = false;
    }

    return 0;
1288 1289
}

1290

1291
static int
1292
virSecuritySELinuxSetSecurityHostdevLabelHelper(const char *file, void *opaque)
1293
{
1294
    virSecurityLabelDefPtr secdef;
1295
    virDomainDefPtr def = opaque;
1296

1297 1298
    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
    if (secdef == NULL)
1299
        return 0;
1300
    return virSecuritySELinuxSetFilecon(file, secdef->imagelabel);
1301 1302 1303
}

static int
1304
virSecuritySELinuxSetSecurityPCILabel(virPCIDevicePtr dev ATTRIBUTE_UNUSED,
1305
                                      const char *file, void *opaque)
1306
{
1307 1308
    return virSecuritySELinuxSetSecurityHostdevLabelHelper(file, opaque);
}
1309

1310 1311 1312 1313 1314
static int
virSecuritySELinuxSetSecurityUSBLabel(virUSBDevicePtr dev ATTRIBUTE_UNUSED,
                                      const char *file, void *opaque)
{
    return virSecuritySELinuxSetSecurityHostdevLabelHelper(file, opaque);
1315 1316
}

1317
static int
1318
virSecuritySELinuxSetSecuritySCSILabel(virSCSIDevicePtr dev,
1319 1320
                                       const char *file, void *opaque)
{
1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337
    virSecurityLabelDefPtr secdef;
    struct SELinuxSCSICallbackData *ptr = opaque;
    virSecurityManagerPtr mgr = ptr->mgr;
    virSecuritySELinuxDataPtr data = virSecurityManagerGetPrivateData(mgr);

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

    if (virSCSIDeviceGetShareable(dev))
        return virSecuritySELinuxSetFileconOptional(file,
                                                    data->file_context);
    else if (virSCSIDeviceGetReadonly(dev))
        return virSecuritySELinuxSetFileconOptional(file,
                                                    data->content_context);
    else
        return virSecuritySELinuxSetFileconOptional(file, secdef->imagelabel);
1338
}
1339

1340
static int
1341 1342
virSecuritySELinuxSetSecurityHostdevSubsysLabel(virSecurityManagerPtr mgr,
                                                virDomainDefPtr def,
1343 1344
                                                virDomainHostdevDefPtr dev,
                                                const char *vroot)
1345 1346

{
1347
    virDomainHostdevSubsysUSBPtr usbsrc = &dev->source.subsys.u.usb;
1348
    virDomainHostdevSubsysPCIPtr pcisrc = &dev->source.subsys.u.pci;
1349
    virDomainHostdevSubsysSCSIPtr scsisrc = &dev->source.subsys.u.scsi;
1350 1351
    int ret = -1;

1352 1353 1354
    /* Like virSecuritySELinuxSetSecurityImageLabelInternal() for a networked
     * disk, do nothing for an iSCSI hostdev
     */
1355 1356
    if (dev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI &&
        scsisrc->protocol == VIR_DOMAIN_HOSTDEV_SCSI_PROTOCOL_TYPE_ISCSI)
1357 1358
        return 0;

1359 1360
    switch (dev->source.subsys.type) {
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB: {
1361
        virUSBDevicePtr usb;
1362

1363 1364 1365
        if (dev->missing)
            return 0;

1366 1367
        usb = virUSBDeviceNew(usbsrc->bus,
                              usbsrc->device,
1368
                              vroot);
1369 1370
        if (!usb)
            goto done;
1371

1372 1373
        ret = virUSBDeviceFileIterate(usb, virSecuritySELinuxSetSecurityUSBLabel, def);
        virUSBDeviceFree(usb);
M
Mark McLoughlin 已提交
1374
        break;
1375 1376 1377
    }

    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI: {
1378
        virPCIDevicePtr pci =
1379 1380
            virPCIDeviceNew(pcisrc->addr.domain, pcisrc->addr.bus,
                            pcisrc->addr.slot, pcisrc->addr.function);
1381 1382 1383 1384

        if (!pci)
            goto done;

1385
        if (pcisrc->backend == VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO) {
1386
            char *vfioGroupDev = virPCIDeviceGetIOMMUGroupDev(pci);
1387

1388 1389
            if (!vfioGroupDev) {
                virPCIDeviceFree(pci);
1390
                goto done;
1391
            }
1392 1393 1394 1395 1396
            ret = virSecuritySELinuxSetSecurityPCILabel(pci, vfioGroupDev, def);
            VIR_FREE(vfioGroupDev);
        } else {
            ret = virPCIDeviceFileIterate(pci, virSecuritySELinuxSetSecurityPCILabel, def);
        }
1397
        virPCIDeviceFree(pci);
1398 1399 1400
        break;
    }

1401
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI: {
1402
        virDomainHostdevSubsysSCSIHostPtr scsihostsrc = &scsisrc->u.host;
1403 1404
        struct SELinuxSCSICallbackData data = {.mgr = mgr, .def = def};

1405
        virSCSIDevicePtr scsi =
1406
            virSCSIDeviceNew(NULL,
1407 1408
                             scsihostsrc->adapter, scsihostsrc->bus,
                             scsihostsrc->target, scsihostsrc->unit,
1409
                             dev->readonly, dev->shareable);
1410 1411 1412 1413

        if (!scsi)
            goto done;

1414 1415 1416
        ret = virSCSIDeviceFileIterate(scsi,
                                       virSecuritySELinuxSetSecuritySCSILabel,
                                       &data);
1417 1418 1419 1420 1421
        virSCSIDeviceFree(scsi);

        break;
    }

1422 1423 1424 1425 1426
    default:
        ret = 0;
        break;
    }

1427
 done:
1428 1429 1430
    return ret;
}

1431

1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442
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)
1443
        return 0;
1444 1445 1446 1447 1448

    switch (dev->source.caps.type) {
    case VIR_DOMAIN_HOSTDEV_CAPS_TYPE_STORAGE: {
        if (vroot) {
            if (virAsprintf(&path, "%s/%s", vroot,
1449
                            dev->source.caps.u.storage.block) < 0)
1450 1451
                return -1;
        } else {
1452
            if (VIR_STRDUP(path, dev->source.caps.u.storage.block) < 0)
1453 1454 1455 1456 1457 1458 1459 1460 1461 1462
                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,
1463
                            dev->source.caps.u.misc.chardev) < 0)
1464 1465
                return -1;
        } else {
1466
            if (VIR_STRDUP(path, dev->source.caps.u.misc.chardev) < 0)
1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482
                return -1;
        }
        ret = virSecuritySELinuxSetFilecon(path, secdef->imagelabel);
        VIR_FREE(path);
        break;
    }

    default:
        ret = 0;
        break;
    }

    return ret;
}


1483
static int
1484
virSecuritySELinuxSetSecurityHostdevLabel(virSecurityManagerPtr mgr,
1485 1486 1487 1488 1489 1490 1491 1492
                                          virDomainDefPtr def,
                                          virDomainHostdevDefPtr dev,
                                          const char *vroot)

{
    virSecurityLabelDefPtr secdef;

    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
1493
    if (!secdef || !secdef->relabel)
1494 1495 1496 1497
        return 0;

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

1501 1502 1503
    case VIR_DOMAIN_HOSTDEV_MODE_CAPABILITIES:
        return virSecuritySELinuxSetSecurityHostdevCapsLabel(def, dev, vroot);

1504 1505 1506 1507 1508
    default:
        return 0;
    }
}

1509
static int
1510
virSecuritySELinuxRestoreSecurityPCILabel(virPCIDevicePtr dev ATTRIBUTE_UNUSED,
1511
                                          const char *file,
1512
                                          void *opaque)
1513
{
1514 1515 1516
    virSecurityManagerPtr mgr = opaque;

    return virSecuritySELinuxRestoreSecurityFileLabel(mgr, file);
1517 1518 1519
}

static int
1520
virSecuritySELinuxRestoreSecurityUSBLabel(virUSBDevicePtr dev ATTRIBUTE_UNUSED,
1521
                                          const char *file,
1522
                                          void *opaque)
1523
{
1524 1525 1526
    virSecurityManagerPtr mgr = opaque;

    return virSecuritySELinuxRestoreSecurityFileLabel(mgr, file);
1527 1528
}

1529

1530
static int
1531
virSecuritySELinuxRestoreSecuritySCSILabel(virSCSIDevicePtr dev,
1532 1533 1534 1535 1536
                                           const char *file,
                                           void *opaque)
{
    virSecurityManagerPtr mgr = opaque;

1537 1538 1539 1540 1541 1542
    /* Don't restore labels on a shareable or readonly hostdev, because
     * other VMs may still be accessing.
     */
    if (virSCSIDeviceGetShareable(dev) || virSCSIDeviceGetReadonly(dev))
        return 0;

1543 1544 1545
    return virSecuritySELinuxRestoreSecurityFileLabel(mgr, file);
}

1546
static int
1547 1548
virSecuritySELinuxRestoreSecurityHostdevSubsysLabel(virSecurityManagerPtr mgr,
                                                    virDomainHostdevDefPtr dev,
1549
                                                    const char *vroot)
1550 1551

{
1552
    virDomainHostdevSubsysUSBPtr usbsrc = &dev->source.subsys.u.usb;
1553
    virDomainHostdevSubsysPCIPtr pcisrc = &dev->source.subsys.u.pci;
1554
    virDomainHostdevSubsysSCSIPtr scsisrc = &dev->source.subsys.u.scsi;
1555 1556
    int ret = -1;

1557 1558 1559
    /* Like virSecuritySELinuxRestoreSecurityImageLabelInt() for a networked
     * disk, do nothing for an iSCSI hostdev
     */
1560 1561
    if (dev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI &&
        scsisrc->protocol == VIR_DOMAIN_HOSTDEV_SCSI_PROTOCOL_TYPE_ISCSI)
1562 1563
        return 0;

1564 1565
    switch (dev->source.subsys.type) {
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB: {
1566
        virUSBDevicePtr usb;
1567 1568 1569

        if (dev->missing)
            return 0;
1570

1571 1572
        usb = virUSBDeviceNew(usbsrc->bus,
                              usbsrc->device,
1573
                              vroot);
1574 1575 1576
        if (!usb)
            goto done;

1577 1578
        ret = virUSBDeviceFileIterate(usb, virSecuritySELinuxRestoreSecurityUSBLabel, mgr);
        virUSBDeviceFree(usb);
1579 1580 1581 1582 1583

        break;
    }

    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI: {
1584
        virPCIDevicePtr pci =
1585 1586
            virPCIDeviceNew(pcisrc->addr.domain, pcisrc->addr.bus,
                            pcisrc->addr.slot, pcisrc->addr.function);
1587 1588 1589 1590

        if (!pci)
            goto done;

1591
        if (pcisrc->backend == VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO) {
1592
            char *vfioGroupDev = virPCIDeviceGetIOMMUGroupDev(pci);
1593

1594 1595
            if (!vfioGroupDev) {
                virPCIDeviceFree(pci);
1596
                goto done;
1597
            }
1598 1599 1600 1601 1602
            ret = virSecuritySELinuxRestoreSecurityPCILabel(pci, vfioGroupDev, mgr);
            VIR_FREE(vfioGroupDev);
        } else {
            ret = virPCIDeviceFileIterate(pci, virSecuritySELinuxRestoreSecurityPCILabel, mgr);
        }
1603
        virPCIDeviceFree(pci);
1604 1605 1606
        break;
    }

1607
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI: {
1608
        virDomainHostdevSubsysSCSIHostPtr scsihostsrc = &scsisrc->u.host;
1609
        virSCSIDevicePtr scsi =
1610
            virSCSIDeviceNew(NULL,
1611 1612
                             scsihostsrc->adapter, scsihostsrc->bus,
                             scsihostsrc->target, scsihostsrc->unit,
1613
                             dev->readonly, dev->shareable);
1614 1615 1616 1617 1618 1619 1620 1621 1622 1623

            if (!scsi)
                goto done;

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

            break;
       }

1624 1625 1626 1627 1628
    default:
        ret = 0;
        break;
    }

1629
 done:
1630 1631 1632
    return ret;
}

1633

1634
static int
1635 1636
virSecuritySELinuxRestoreSecurityHostdevCapsLabel(virSecurityManagerPtr mgr,
                                                  virDomainHostdevDefPtr dev,
1637 1638 1639 1640 1641 1642 1643 1644 1645
                                                  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,
1646
                            dev->source.caps.u.storage.block) < 0)
1647 1648
                return -1;
        } else {
1649
            if (VIR_STRDUP(path, dev->source.caps.u.storage.block) < 0)
1650 1651
                return -1;
        }
1652
        ret = virSecuritySELinuxRestoreSecurityFileLabel(mgr, path);
1653 1654 1655 1656 1657 1658 1659
        VIR_FREE(path);
        break;
    }

    case VIR_DOMAIN_HOSTDEV_CAPS_TYPE_MISC: {
        if (vroot) {
            if (virAsprintf(&path, "%s/%s", vroot,
1660
                            dev->source.caps.u.misc.chardev) < 0)
1661 1662
                return -1;
        } else {
1663
            if (VIR_STRDUP(path, dev->source.caps.u.misc.chardev) < 0)
1664 1665
                return -1;
        }
1666
        ret = virSecuritySELinuxRestoreSecurityFileLabel(mgr, path);
1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679
        VIR_FREE(path);
        break;
    }

    default:
        ret = 0;
        break;
    }

    return ret;
}


1680
static int
1681
virSecuritySELinuxRestoreSecurityHostdevLabel(virSecurityManagerPtr mgr,
1682 1683 1684 1685 1686 1687 1688 1689
                                              virDomainDefPtr def,
                                              virDomainHostdevDefPtr dev,
                                              const char *vroot)

{
    virSecurityLabelDefPtr secdef;

    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
1690
    if (!secdef || !secdef->relabel)
1691 1692 1693 1694
        return 0;

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

1697
    case VIR_DOMAIN_HOSTDEV_MODE_CAPABILITIES:
1698
        return virSecuritySELinuxRestoreSecurityHostdevCapsLabel(mgr, dev, vroot);
1699

1700 1701 1702 1703 1704 1705
    default:
        return 0;
    }
}


1706
static int
1707
virSecuritySELinuxSetSecurityChardevLabel(virDomainDefPtr def,
1708 1709
                                          virDomainChrDefPtr dev,
                                          virDomainChrSourceDefPtr dev_source)
1710 1711

{
1712 1713 1714
    virSecurityLabelDefPtr seclabel;
    virSecurityDeviceLabelDefPtr chr_seclabel = NULL;
    char *imagelabel = NULL;
1715 1716 1717
    char *in = NULL, *out = NULL;
    int ret = -1;

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

1722 1723 1724 1725
    if (dev)
        chr_seclabel = virDomainChrDefGetSecurityLabelDef(dev,
                                                          SECURITY_SELINUX_NAME);

1726
    if (chr_seclabel && !chr_seclabel->relabel)
1727 1728
        return 0;

1729 1730 1731 1732 1733 1734
    if (chr_seclabel)
        imagelabel = chr_seclabel->label;
    if (!imagelabel)
        imagelabel = seclabel->imagelabel;

    switch (dev_source->type) {
1735 1736
    case VIR_DOMAIN_CHR_TYPE_DEV:
    case VIR_DOMAIN_CHR_TYPE_FILE:
1737 1738 1739 1740 1741 1742
        ret = virSecuritySELinuxSetFilecon(dev_source->data.file.path,
                                           imagelabel);
        break;

    case VIR_DOMAIN_CHR_TYPE_UNIX:
        if (!dev_source->data.nix.listen) {
1743
            if (virSecuritySELinuxSetFilecon(dev_source->data.nix.path,
1744 1745 1746 1747
                                             imagelabel) < 0)
                goto done;
        }
        ret = 0;
1748 1749 1750
        break;

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

    default:
        ret = 0;
        break;
    }

1771
 done:
1772 1773 1774 1775 1776 1777
    VIR_FREE(in);
    VIR_FREE(out);
    return ret;
}

static int
1778 1779
virSecuritySELinuxRestoreSecurityChardevLabel(virSecurityManagerPtr mgr,
                                              virDomainDefPtr def,
1780 1781
                                              virDomainChrDefPtr dev,
                                              virDomainChrSourceDefPtr dev_source)
1782 1783

{
1784 1785
    virSecurityLabelDefPtr seclabel;
    virSecurityDeviceLabelDefPtr chr_seclabel = NULL;
1786 1787 1788
    char *in = NULL, *out = NULL;
    int ret = -1;

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

1793 1794 1795
    if (dev)
        chr_seclabel = virDomainChrDefGetSecurityLabelDef(dev,
                                                          SECURITY_SELINUX_NAME);
1796
    if (chr_seclabel && !chr_seclabel->relabel)
1797 1798
        return 0;

1799
    switch (dev_source->type) {
1800 1801
    case VIR_DOMAIN_CHR_TYPE_DEV:
    case VIR_DOMAIN_CHR_TYPE_FILE:
1802
        if (virSecuritySELinuxRestoreSecurityFileLabel(mgr, dev_source->data.file.path) < 0)
1803 1804
            goto done;
        ret = 0;
1805
        break;
1806 1807 1808

    case VIR_DOMAIN_CHR_TYPE_UNIX:
        if (!dev_source->data.nix.listen) {
1809
            if (virSecuritySELinuxRestoreSecurityFileLabel(mgr, dev_source->data.file.path) < 0)
1810 1811 1812 1813 1814
                goto done;
        }
        ret = 0;
        break;

1815
    case VIR_DOMAIN_CHR_TYPE_PIPE:
1816
        if ((virAsprintf(&out, "%s.out", dev_source->data.file.path) < 0) ||
1817
            (virAsprintf(&in, "%s.in", dev_source->data.file.path) < 0))
1818
            goto done;
1819
        if (virFileExists(in) && virFileExists(out)) {
1820 1821
            if ((virSecuritySELinuxRestoreSecurityFileLabel(mgr, out) < 0) ||
                (virSecuritySELinuxRestoreSecurityFileLabel(mgr, in) < 0)) {
1822 1823
                goto done;
            }
1824
        } else if (virSecuritySELinuxRestoreSecurityFileLabel(mgr, dev_source->data.file.path) < 0) {
1825
            goto done;
1826
        }
1827 1828 1829 1830 1831 1832 1833 1834
        ret = 0;
        break;

    default:
        ret = 0;
        break;
    }

1835
 done:
1836 1837 1838 1839 1840 1841 1842
    VIR_FREE(in);
    VIR_FREE(out);
    return ret;
}


static int
1843 1844
virSecuritySELinuxRestoreSecurityChardevCallback(virDomainDefPtr def,
                                                 virDomainChrDefPtr dev,
1845
                                                 void *opaque)
1846
{
1847 1848
    virSecurityManagerPtr mgr = opaque;

1849 1850 1851 1852 1853
    /* 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;

1854
    return virSecuritySELinuxRestoreSecurityChardevLabel(mgr, def, dev,
1855
                                                         &dev->source);
1856 1857 1858
}


E
Eric Blake 已提交
1859
static int
1860 1861
virSecuritySELinuxRestoreSecuritySmartcardCallback(virDomainDefPtr def,
                                                   virDomainSmartcardDefPtr dev,
1862
                                                   void *opaque)
E
Eric Blake 已提交
1863
{
1864
    virSecurityManagerPtr mgr = opaque;
E
Eric Blake 已提交
1865 1866 1867 1868 1869 1870 1871 1872 1873 1874
    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;
1875
        return virSecuritySELinuxRestoreSecurityFileLabel(mgr, database);
E
Eric Blake 已提交
1876 1877

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

    default:
1881 1882 1883
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unknown smartcard type %d"),
                       dev->type);
E
Eric Blake 已提交
1884 1885 1886 1887 1888 1889 1890
        return -1;
    }

    return 0;
}


1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901
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;
}


1902
static int
1903
virSecuritySELinuxRestoreSecurityAllLabel(virSecurityManagerPtr mgr,
1904
                                          virDomainDefPtr def,
1905
                                          bool migrated)
1906
{
1907
    virSecurityLabelDefPtr secdef;
1908
    virSecuritySELinuxDataPtr data = virSecurityManagerGetPrivateData(mgr);
1909
    size_t i;
1910
    int rc = 0;
1911

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

1914 1915
    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);

1916
    if (!secdef || !secdef->relabel || data->skipAllLabel)
1917 1918
        return 0;

1919 1920 1921 1922 1923 1924
    if (def->tpm) {
        if (virSecuritySELinuxRestoreSecurityTPMFileLabelInt(mgr, def,
                                                             def->tpm) < 0)
            rc = -1;
    }

1925
    for (i = 0; i < def->nhostdevs; i++) {
1926 1927
        if (virSecuritySELinuxRestoreSecurityHostdevLabel(mgr,
                                                          def,
1928 1929
                                                          def->hostdevs[i],
                                                          NULL) < 0)
1930
            rc = -1;
1931
    }
1932
    for (i = 0; i < def->ndisks; i++) {
1933 1934 1935
        virDomainDiskDefPtr disk = def->disks[i];

        if (virSecuritySELinuxRestoreSecurityImageLabelInt(mgr, def, disk->src,
1936
                                                           migrated) < 0)
1937 1938
            rc = -1;
    }
1939

1940
    if (virDomainChrDefForeach(def,
1941
                               false,
1942
                               virSecuritySELinuxRestoreSecurityChardevCallback,
1943
                               mgr) < 0)
1944 1945
        rc = -1;

1946
    if (virDomainSmartcardDefForeach(def,
E
Eric Blake 已提交
1947
                                     false,
1948
                                     virSecuritySELinuxRestoreSecuritySmartcardCallback,
1949
                                     mgr) < 0)
E
Eric Blake 已提交
1950 1951
        rc = -1;

1952 1953 1954 1955
    if (def->os.loader && def->os.loader->nvram &&
        virSecuritySELinuxRestoreSecurityFileLabel(mgr, def->os.loader->nvram) < 0)
        rc = -1;

1956
    if (def->os.kernel &&
1957
        virSecuritySELinuxRestoreSecurityFileLabel(mgr, def->os.kernel) < 0)
1958 1959
        rc = -1;

1960
    if (def->os.initrd &&
1961
        virSecuritySELinuxRestoreSecurityFileLabel(mgr, def->os.initrd) < 0)
1962 1963
        rc = -1;

O
Olivia Yin 已提交
1964 1965 1966 1967
    if (def->os.dtb &&
        virSecuritySELinuxRestoreSecurityFileLabel(mgr, def->os.dtb) < 0)
        rc = -1;

1968 1969 1970 1971
    return rc;
}

static int
1972
virSecuritySELinuxReleaseSecurityLabel(virSecurityManagerPtr mgr,
1973
                                       virDomainDefPtr def)
1974
{
1975 1976 1977 1978
    virSecurityLabelDefPtr secdef;

    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
    if (secdef == NULL)
1979
        return 0;
1980

1981 1982 1983 1984
    if (secdef->type == VIR_DOMAIN_SECLABEL_DYNAMIC) {
        if (secdef->label != NULL) {
            context_t con = context_new(secdef->label);
            if (con) {
1985
                virSecuritySELinuxMCSRemove(mgr, context_range_get(con));
1986 1987 1988 1989 1990 1991
                context_free(con);
            }
        }
        VIR_FREE(secdef->label);
        if (!secdef->baselabel)
            VIR_FREE(secdef->model);
1992 1993 1994
    }
    VIR_FREE(secdef->imagelabel);

1995
    return 0;
1996 1997
}

1998 1999

static int
2000 2001 2002
virSecuritySELinuxSetSavedStateLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
                                     virDomainDefPtr def,
                                     const char *savefile)
2003
{
2004 2005 2006
    virSecurityLabelDefPtr secdef;

    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
2007
    if (!secdef || !secdef->relabel)
2008 2009
        return 0;

2010
    return virSecuritySELinuxSetFilecon(savefile, secdef->imagelabel);
2011 2012 2013 2014
}


static int
2015
virSecuritySELinuxRestoreSavedStateLabel(virSecurityManagerPtr mgr,
2016 2017
                                         virDomainDefPtr def,
                                         const char *savefile)
2018
{
2019 2020 2021
    virSecurityLabelDefPtr secdef;

    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
2022
    if (!secdef || !secdef->relabel)
2023 2024
        return 0;

2025
    return virSecuritySELinuxRestoreSecurityFileLabel(mgr, savefile);
2026 2027 2028
}


2029
static int
2030 2031
virSecuritySELinuxSecurityVerify(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
                                 virDomainDefPtr def)
2032
{
2033 2034 2035 2036
    virSecurityLabelDefPtr secdef;

    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
    if (secdef == NULL)
2037
        return 0;
2038

2039
    if (!STREQ(SECURITY_SELINUX_NAME, secdef->model)) {
2040 2041 2042 2043
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("security label driver mismatch: "
                         "'%s' model configured for domain, but "
                         "hypervisor driver is '%s'."),
2044
                       secdef->model, SECURITY_SELINUX_NAME);
2045 2046 2047
        return -1;
    }

2048 2049
    if (secdef->type == VIR_DOMAIN_SECLABEL_STATIC) {
        if (security_check_context(secdef->label) != 0) {
2050 2051
            virReportError(VIR_ERR_XML_ERROR,
                           _("Invalid security label %s"), secdef->label);
2052 2053 2054 2055 2056 2057
            return -1;
        }
    }
    return 0;
}

2058
static int
2059
virSecuritySELinuxSetSecurityProcessLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
2060
                                          virDomainDefPtr def)
2061 2062
{
    /* TODO: verify DOI */
2063 2064 2065
    virSecurityLabelDefPtr secdef;

    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
2066
    if (!secdef || !secdef->label)
2067 2068
        return 0;

2069
    VIR_DEBUG("label=%s", secdef->label);
2070
    if (!STREQ(SECURITY_SELINUX_NAME, secdef->model)) {
2071 2072 2073 2074
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("security label driver mismatch: "
                         "'%s' model configured for domain, but "
                         "hypervisor driver is '%s'."),
2075
                       secdef->model, SECURITY_SELINUX_NAME);
2076
        if (security_getenforce() == 1)
2077
            return -1;
2078 2079
    }

M
Martin Kletzander 已提交
2080
    if (setexeccon_raw(secdef->label) == -1) {
2081
        virReportSystemError(errno,
2082 2083
                             _("unable to set security context '%s'"),
                             secdef->label);
2084
        if (security_getenforce() == 1)
2085
            return -1;
2086 2087
    }

2088 2089 2090
    return 0;
}

2091 2092 2093 2094 2095 2096 2097 2098 2099
static int
virSecuritySELinuxSetSecurityChildProcessLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
                                               virDomainDefPtr def,
                                               virCommandPtr cmd)
{
    /* TODO: verify DOI */
    virSecurityLabelDefPtr secdef;

    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
2100
    if (!secdef || !secdef->label)
2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118
        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;
}

2119
static int
2120
virSecuritySELinuxSetSecurityDaemonSocketLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
2121
                                               virDomainDefPtr def)
2122 2123
{
    /* TODO: verify DOI */
2124
    virSecurityLabelDefPtr secdef;
2125
    security_context_t scon = NULL;
2126
    char *str = NULL;
2127 2128
    int rc = -1;

2129
    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
2130
    if (!secdef || !secdef->label)
2131 2132
        return 0;

2133
    if (!STREQ(SECURITY_SELINUX_NAME, secdef->model)) {
2134 2135 2136 2137
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("security label driver mismatch: "
                         "'%s' model configured for domain, but "
                         "hypervisor driver is '%s'."),
2138
                       secdef->model, SECURITY_SELINUX_NAME);
2139 2140 2141
        goto done;
    }

M
Martin Kletzander 已提交
2142
    if (getcon_raw(&scon) == -1) {
2143 2144 2145 2146 2147 2148
        virReportSystemError(errno,
                             _("unable to get current process context '%s'"),
                             secdef->label);
        goto done;
    }

2149
    if (!(str = virSecuritySELinuxContextAddRange(secdef->label, scon)))
2150 2151
        goto done;

2152 2153
    VIR_DEBUG("Setting VM %s socket context %s", def->name, str);
    if (setsockcreatecon_raw(str) == -1) {
2154
        virReportSystemError(errno,
2155
                             _("unable to set socket security context '%s'"), str);
2156 2157 2158 2159
        goto done;
    }

    rc = 0;
2160
 done:
2161 2162 2163 2164

    if (security_getenforce() != 1)
        rc = 0;
    freecon(scon);
2165
    VIR_FREE(str);
2166 2167 2168
    return rc;
}

2169
static int
2170
virSecuritySELinuxSetSecuritySocketLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
2171
                                         virDomainDefPtr vm)
2172
{
2173
    virSecurityLabelDefPtr secdef;
2174 2175
    int rc = -1;

2176
    secdef = virDomainDefGetSecurityLabelDef(vm, SECURITY_SELINUX_NAME);
2177
    if (!secdef || !secdef->label)
2178 2179
        return 0;

2180
    if (!STREQ(SECURITY_SELINUX_NAME, secdef->model)) {
2181 2182 2183 2184
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("security label driver mismatch: "
                         "'%s' model configured for domain, but "
                         "hypervisor driver is '%s'."),
2185
                       secdef->model, SECURITY_SELINUX_NAME);
2186 2187 2188 2189
        goto done;
    }

    VIR_DEBUG("Setting VM %s socket context %s",
2190
              vm->name, secdef->label);
M
Martin Kletzander 已提交
2191
    if (setsockcreatecon_raw(secdef->label) == -1) {
2192 2193 2194 2195 2196 2197 2198 2199
        virReportSystemError(errno,
                             _("unable to set socket security context '%s'"),
                             secdef->label);
        goto done;
    }

    rc = 0;

2200
 done:
2201 2202 2203 2204 2205 2206
    if (security_getenforce() != 1)
        rc = 0;

    return rc;
}

2207
static int
2208
virSecuritySELinuxClearSecuritySocketLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
2209
                                           virDomainDefPtr def)
2210 2211
{
    /* TODO: verify DOI */
2212 2213 2214
    virSecurityLabelDefPtr secdef;

    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
2215
    if (!secdef || !secdef->label)
2216 2217
        return 0;

2218
    if (!STREQ(SECURITY_SELINUX_NAME, secdef->model)) {
2219 2220 2221 2222
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("security label driver mismatch: "
                         "'%s' model configured for domain, but "
                         "hypervisor driver is '%s'."),
2223
                       secdef->model, SECURITY_SELINUX_NAME);
2224 2225 2226 2227
        if (security_getenforce() == 1)
            return -1;
    }

M
Martin Kletzander 已提交
2228
    if (setsockcreatecon_raw(NULL) == -1) {
2229 2230 2231 2232 2233 2234 2235 2236 2237
        virReportSystemError(errno,
                             _("unable to clear socket security context '%s'"),
                             secdef->label);
        if (security_getenforce() == 1)
            return -1;
    }
    return 0;
}

2238 2239

static int
2240 2241 2242
virSecuritySELinuxSetSecurityChardevCallback(virDomainDefPtr def,
                                             virDomainChrDefPtr dev,
                                             void *opaque ATTRIBUTE_UNUSED)
2243
{
2244 2245 2246 2247 2248
    /* 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;

2249
    return virSecuritySELinuxSetSecurityChardevLabel(def, dev, &dev->source);
2250 2251 2252
}


E
Eric Blake 已提交
2253
static int
2254 2255 2256
virSecuritySELinuxSetSecuritySmartcardCallback(virDomainDefPtr def,
                                               virDomainSmartcardDefPtr dev,
                                               void *opaque)
E
Eric Blake 已提交
2257 2258
{
    const char *database;
2259 2260
    virSecurityManagerPtr mgr = opaque;
    virSecuritySELinuxDataPtr data = virSecurityManagerGetPrivateData(mgr);
E
Eric Blake 已提交
2261 2262 2263 2264 2265 2266 2267 2268 2269

    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;
2270
        return virSecuritySELinuxSetFilecon(database, data->content_context);
E
Eric Blake 已提交
2271 2272

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

    default:
2276 2277 2278
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unknown smartcard type %d"),
                       dev->type);
E
Eric Blake 已提交
2279 2280 2281 2282 2283 2284 2285
        return -1;
    }

    return 0;
}


2286
static int
2287 2288 2289
virSecuritySELinuxSetSecurityAllLabel(virSecurityManagerPtr mgr,
                                      virDomainDefPtr def,
                                      const char *stdin_path)
2290
{
2291
    size_t i;
2292 2293 2294 2295
    virSecuritySELinuxDataPtr data = virSecurityManagerGetPrivateData(mgr);
    virSecurityLabelDefPtr secdef;

    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
2296

2297
    if (!secdef || !secdef->relabel || data->skipAllLabel)
2298 2299
        return 0;

2300
    for (i = 0; i < def->ndisks; i++) {
2301
        /* XXX fixme - we need to recursively label the entire tree :-( */
E
Eric Blake 已提交
2302
        if (virDomainDiskGetType(def->disks[i]) == VIR_STORAGE_TYPE_DIR) {
2303
            VIR_WARN("Unable to relabel directory tree %s for disk %s",
2304 2305
                     virDomainDiskGetSource(def->disks[i]),
                     def->disks[i]->dst);
2306
            continue;
2307
        }
2308
        if (virSecuritySELinuxSetSecurityDiskLabel(mgr,
2309
                                                   def, def->disks[i]) < 0)
2310 2311
            return -1;
    }
2312
    /* XXX fixme process  def->fss if relabel == true */
2313

2314
    for (i = 0; i < def->nhostdevs; i++) {
2315
        if (virSecuritySELinuxSetSecurityHostdevLabel(mgr,
2316 2317 2318
                                                      def,
                                                      def->hostdevs[i],
                                                      NULL) < 0)
2319
            return -1;
2320
    }
2321 2322 2323 2324 2325
    if (def->tpm) {
        if (virSecuritySELinuxSetSecurityTPMFileLabel(mgr, def,
                                                      def->tpm) < 0)
            return -1;
    }
2326

2327
    if (virDomainChrDefForeach(def,
2328
                               true,
2329
                               virSecuritySELinuxSetSecurityChardevCallback,
2330
                               NULL) < 0)
2331 2332
        return -1;

2333
    if (virDomainSmartcardDefForeach(def,
E
Eric Blake 已提交
2334
                                     true,
2335
                                     virSecuritySELinuxSetSecuritySmartcardCallback,
2336
                                     mgr) < 0)
E
Eric Blake 已提交
2337 2338
        return -1;

M
Michal Privoznik 已提交
2339 2340
    /* This is different than kernel or initrd. The nvram store
     * is really a disk, qemu can read and write to it. */
2341
    if (def->os.loader && def->os.loader->nvram &&
M
Michal Privoznik 已提交
2342 2343
        secdef && secdef->imagelabel &&
        virSecuritySELinuxSetFilecon(def->os.loader->nvram, secdef->imagelabel) < 0)
2344 2345
        return -1;

2346
    if (def->os.kernel &&
2347
        virSecuritySELinuxSetFilecon(def->os.kernel, data->content_context) < 0)
2348 2349
        return -1;

2350
    if (def->os.initrd &&
2351
        virSecuritySELinuxSetFilecon(def->os.initrd, data->content_context) < 0)
2352 2353
        return -1;

O
Olivia Yin 已提交
2354 2355 2356 2357
    if (def->os.dtb &&
        virSecuritySELinuxSetFilecon(def->os.dtb, data->content_context) < 0)
        return -1;

2358 2359 2360
    if (stdin_path &&
        virSecuritySELinuxSetFilecon(stdin_path, data->content_context) < 0)
        return -1;
2361

2362 2363 2364
    return 0;
}

2365
static int
2366 2367 2368
virSecuritySELinuxSetImageFDLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
                                  virDomainDefPtr def,
                                  int fd)
2369
{
2370 2371 2372
    virSecurityLabelDefPtr secdef;

    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
2373
    if (!secdef || !secdef->imagelabel)
2374 2375
        return 0;

2376
    return virSecuritySELinuxFSetFilecon(fd, secdef->imagelabel);
2377 2378
}

2379
static int
2380
virSecuritySELinuxSetTapFDLabel(virSecurityManagerPtr mgr,
2381 2382 2383
                                virDomainDefPtr def,
                                int fd)
{
2384 2385
    struct stat buf;
    security_context_t fcon = NULL;
2386
    virSecurityLabelDefPtr secdef;
2387
    char *str = NULL, *proc = NULL, *fd_path = NULL;
2388
    int rc = -1;
2389 2390

    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
2391
    if (!secdef || !secdef->label)
2392 2393
        return 0;

2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404
    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;
    }

2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422
    /* 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) {
2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435
        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);
2436 2437
    VIR_FREE(fd_path);
    VIR_FREE(proc);
2438 2439
    VIR_FREE(str);
    return rc;
2440 2441
}

2442 2443 2444 2445
static char *
virSecuritySELinuxGenImageLabel(virSecurityManagerPtr mgr,
                                virDomainDefPtr def)
{
2446
    virSecurityLabelDefPtr secdef;
2447 2448 2449 2450
    virSecuritySELinuxDataPtr data = virSecurityManagerGetPrivateData(mgr);
    const char *range;
    context_t ctx = NULL;
    char *label = NULL;
2451
    char *mcs = NULL;
2452

2453 2454 2455 2456
    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
    if (secdef == NULL)
        goto cleanup;

2457 2458 2459
    if (secdef->label) {
        ctx = context_new(secdef->label);
        if (!ctx) {
2460 2461
            virReportSystemError(errno, _("unable to create selinux context for: %s"),
                                 secdef->label);
2462 2463 2464 2465
            goto cleanup;
        }
        range = context_range_get(ctx);
        if (range) {
2466
            if (VIR_STRDUP(mcs, range) < 0)
2467
                goto cleanup;
2468 2469
            if (!(label = virSecuritySELinuxGenNewContext(data->file_context,
                                                          mcs, true)))
2470 2471 2472 2473
                goto cleanup;
        }
    }

2474
 cleanup:
2475 2476 2477
    context_free(ctx);
    VIR_FREE(mcs);
    return label;
2478 2479
}

2480 2481 2482 2483
static char *
virSecuritySELinuxGetSecurityMountOptions(virSecurityManagerPtr mgr,
                                          virDomainDefPtr def)
{
2484
    char *opts = NULL;
2485 2486
    virSecurityLabelDefPtr secdef;

2487 2488 2489 2490 2491 2492 2493
    if ((secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME))) {
        if (!secdef->imagelabel)
            secdef->imagelabel = virSecuritySELinuxGenImageLabel(mgr, def);

        if (secdef->imagelabel &&
            virAsprintf(&opts,
                        ",context=\"%s\"",
2494
                        (const char*) secdef->imagelabel) < 0)
2495 2496
            return NULL;
    }
2497

2498
    if (!opts && VIR_STRDUP(opts, "") < 0)
2499
        return NULL;
2500

2501 2502
    VIR_DEBUG("imageLabel=%s opts=%s",
              secdef ? secdef->imagelabel : "(null)", opts);
2503 2504 2505
    return opts;
}

G
Guido Günther 已提交
2506 2507
static int
virSecuritySELinuxDomainSetDirLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519
                                    virDomainDefPtr def,
                                    const char *path)
{
    virSecurityLabelDefPtr seclabel;

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

    return virSecuritySELinuxSetFilecon(path, seclabel->imagelabel);
}

2520
virSecurityDriver virSecurityDriverSELinux = {
2521 2522
    .privateDataLen                     = sizeof(virSecuritySELinuxData),
    .name                               = SECURITY_SELINUX_NAME,
2523 2524 2525
    .probe                              = virSecuritySELinuxSecurityDriverProbe,
    .open                               = virSecuritySELinuxSecurityDriverOpen,
    .close                              = virSecuritySELinuxSecurityDriverClose,
2526

2527 2528
    .getModel                           = virSecuritySELinuxSecurityGetModel,
    .getDOI                             = virSecuritySELinuxSecurityGetDOI,
2529

2530
    .domainSecurityVerify               = virSecuritySELinuxSecurityVerify,
2531

2532
    .domainSetSecurityDiskLabel         = virSecuritySELinuxSetSecurityDiskLabel,
2533
    .domainRestoreSecurityDiskLabel     = virSecuritySELinuxRestoreSecurityDiskLabel,
2534

2535
    .domainSetSecurityImageLabel        = virSecuritySELinuxSetSecurityImageLabel,
2536 2537
    .domainRestoreSecurityImageLabel    = virSecuritySELinuxRestoreSecurityImageLabel,

2538 2539 2540
    .domainSetSecurityDaemonSocketLabel = virSecuritySELinuxSetSecurityDaemonSocketLabel,
    .domainSetSecuritySocketLabel       = virSecuritySELinuxSetSecuritySocketLabel,
    .domainClearSecuritySocketLabel     = virSecuritySELinuxClearSecuritySocketLabel,
2541

2542 2543 2544
    .domainGenSecurityLabel             = virSecuritySELinuxGenSecurityLabel,
    .domainReserveSecurityLabel         = virSecuritySELinuxReserveSecurityLabel,
    .domainReleaseSecurityLabel         = virSecuritySELinuxReleaseSecurityLabel,
2545

2546 2547
    .domainGetSecurityProcessLabel      = virSecuritySELinuxGetSecurityProcessLabel,
    .domainSetSecurityProcessLabel      = virSecuritySELinuxSetSecurityProcessLabel,
2548
    .domainSetSecurityChildProcessLabel = virSecuritySELinuxSetSecurityChildProcessLabel,
2549

2550 2551
    .domainSetSecurityAllLabel          = virSecuritySELinuxSetSecurityAllLabel,
    .domainRestoreSecurityAllLabel      = virSecuritySELinuxRestoreSecurityAllLabel,
2552

2553 2554
    .domainSetSecurityHostdevLabel      = virSecuritySELinuxSetSecurityHostdevLabel,
    .domainRestoreSecurityHostdevLabel  = virSecuritySELinuxRestoreSecurityHostdevLabel,
2555

2556 2557
    .domainSetSavedStateLabel           = virSecuritySELinuxSetSavedStateLabel,
    .domainRestoreSavedStateLabel       = virSecuritySELinuxRestoreSavedStateLabel,
2558

2559
    .domainSetSecurityImageFDLabel      = virSecuritySELinuxSetImageFDLabel,
2560
    .domainSetSecurityTapFDLabel        = virSecuritySELinuxSetTapFDLabel,
2561

2562
    .domainGetSecurityMountOptions      = virSecuritySELinuxGetSecurityMountOptions,
2563
    .getBaseLabel                       = virSecuritySELinuxGetBaseLabel,
2564 2565

    .domainSetDirLabel                  = virSecuritySELinuxDomainSetDirLabel,
2566
};