security_selinux.c 80.7 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
/* Data structure to pass to various callbacks so we have everything we need */
typedef struct _virSecuritySELinuxCallbackData virSecuritySELinuxCallbackData;
typedef virSecuritySELinuxCallbackData *virSecuritySELinuxCallbackDataPtr;
74

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

80 81 82
#define SECURITY_SELINUX_VOID_DOI       "0"
#define SECURITY_SELINUX_NAME "selinux"

83
static int
84 85 86
virSecuritySELinuxRestoreTPMFileLabelInt(virSecurityManagerPtr mgr,
                                         virDomainDefPtr def,
                                         virDomainTPMDefPtr tpm);
87 88


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

98 99 100 101
    if (virHashLookup(data->mcs, mcs))
        return 1;

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

104 105 106
    return 0;
}

107 108 109
static void
virSecuritySELinuxMCSRemove(virSecurityManagerPtr mgr,
                            const char *mcs)
110
{
111 112 113
    virSecuritySELinuxDataPtr data = virSecurityManagerGetPrivateData(mgr);

    virHashRemoveEntry(data->mcs, mcs);
114 115
}

116 117

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

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

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

        VIR_FREE(mcs);
    }

    return mcs;
}

168 169 170 171

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

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

210
    if (VIR_STRDUP(*sens, contextRange) < 0)
211 212
        goto cleanup;

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

224
    /* If there was no category part, just assume c0.c1023 */
225 226
    if (!cat) {
        *catMin = 0;
227
        *catMax = 1023;
228 229 230 231
        ret = 0;
        goto cleanup;
    }

232 233 234 235 236 237 238 239 240
    /* Find & extract category min */
    tmp = cat;
    if (tmp[0] != 'c') {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Cannot parse category in %s"),
                       cat);
        goto cleanup;
    }
    tmp++;
241
    if (virStrToLong_i(tmp, &tmp, 10, catMin) < 0) {
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 268 269 270
        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++;
271
    if (virStrToLong_i(tmp, &tmp, 10, catMax) < 0) {
272 273 274 275 276 277
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Cannot parse category in %s"),
                       cat);
        goto cleanup;
    }

278
    ret = 0;
279

280
 cleanup:
281 282
    if (ret < 0)
        VIR_FREE(*sens);
283 284
    freecon(ourSecContext);
    context_free(ourContext);
285
    return ret;
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 315 316 317
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;
    }

318
    ignore_value(VIR_STRDUP(ret, str));
319

320
 cleanup:
321 322 323 324
    if (srccon) context_free(srccon);
    if (dstcon) context_free(dstcon);
    return ret;
}
325

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

337 338 339
    VIR_DEBUG("basecontext=%s mcs=%s isObjectContext=%d",
              basecontext, mcs, isObjectContext);

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

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

360 361 362 363 364 365 366 367
    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;
    }

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

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

398

399
#ifdef HAVE_SELINUX_LXC_CONTEXTS_PATH
400
static int
401
virSecuritySELinuxLXCInitialize(virSecurityManagerPtr mgr)
402 403 404 405
{
    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
    if (virConfGetValueString(selinux_conf, "process", &data->domain_context) < 0)
421 422
        goto error;

423 424 425 426
    if (!data->domain_context) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("missing 'process' value in selinux lxc contexts file '%s'"),
                       selinux_lxc_contexts_path());
427 428 429
        goto error;
    }

430 431 432 433 434 435 436
    if (virConfGetValueString(selinux_conf, "file", &data->file_context) < 0)
        goto error;

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

440 441 442 443 444 445 446
    if (virConfGetValueString(selinux_conf, "content", &data->content_context) < 0)
        goto error;

    if (!data->content_context) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("missing 'content' value in selinux lxc contexts file '%s'"),
                       selinux_lxc_contexts_path());
447
        goto error;
448
    }
449 450 451 452

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

453 454 455
    virConfFree(selinux_conf);
    return 0;

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


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

485 486
    data->skipAllLabel = false;

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

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

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

518

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

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

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

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

542
    return 0;
543

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

557 558

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


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

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

    data = virSecurityManagerGetPrivateData(mgr);

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

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

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

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

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

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

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

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

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

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

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

671 672 673
        break;

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

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

682 683 684
        break;

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

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

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

702
    rc = 0;
703

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

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

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

726 727 728
    return rc;
}

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

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

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

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

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

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

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

    context_free(ctx);

    return 0;

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


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

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

    return SECURITY_DRIVER_ENABLE;
795 796
}

797

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

804

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

    if (!data)
        return 0;

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

818 819
    virHashFree(data->mcs);

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

825 826 827 828
    return 0;
}


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

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

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

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

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

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

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

    return 0;
}

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

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

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

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

906 907 908 909 910
        /* 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 ...
911
         */
912
        VIR_WARNINGS_NO_WLOGICALOP_EQUAL_EXPR
913 914
        if (setfilecon_errno != EOPNOTSUPP && setfilecon_errno != ENOTSUP &&
            setfilecon_errno != EROFS) {
915
        VIR_WARNINGS_RESET
916
            virReportSystemError(setfilecon_errno,
917
                                 _("unable to set security context '%s' on '%s'"),
918
                                 tcon, path);
919 920 921 922
            /* However, don't claim error if SELinux is in Enforcing mode and
             * we are running as unprivileged user and we really did see EPERM.
             * Otherwise we want to return error if SELinux is Enforcing. */
            if (security_getenforce() == 1 && (setfilecon_errno != EPERM || privileged))
923
                return -1;
924
        } else {
925
            const char *msg;
926
            if (virFileIsSharedFSType(path, VIR_FILE_SHFS_NFS) == 1 &&
927 928 929
                security_get_boolean_active("virt_use_nfs") != 1) {
                msg = _("Setting security context '%s' on '%s' not supported. "
                        "Consider setting virt_use_nfs");
930 931 932 933
                if (security_getenforce() == 1)
                    VIR_WARN(msg, tcon, path);
                else
                    VIR_INFO(msg, tcon, path);
934 935 936 937
            } else {
                VIR_INFO("Setting security context '%s' on '%s' not supported",
                         tcon, path);
            }
938 939
            if (optional)
                return 1;
940
        }
941 942 943 944
    }
    return 0;
}

945
static int
946 947
virSecuritySELinuxSetFileconOptional(virSecurityManagerPtr mgr,
                                     const char *path, char *tcon)
948
{
949 950
    bool privileged = virSecurityManagerGetPrivileged(mgr);
    return virSecuritySELinuxSetFileconHelper(path, tcon, true, privileged);
951 952 953
}

static int
954 955
virSecuritySELinuxSetFilecon(virSecurityManagerPtr mgr,
                             const char *path, char *tcon)
956
{
957 958
    bool privileged = virSecurityManagerGetPrivileged(mgr);
    return virSecuritySELinuxSetFileconHelper(path, tcon, false, privileged);
959 960
}

961
static int
962
virSecuritySELinuxFSetFilecon(int fd, char *tcon)
963 964 965 966 967
{
    security_context_t econ;

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

M
Martin Kletzander 已提交
968
    if (fsetfilecon_raw(fd, tcon) < 0) {
969 970
        int fsetfilecon_errno = errno;

M
Martin Kletzander 已提交
971
        if (fgetfilecon_raw(fd, &econ) >= 0) {
972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999
            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 已提交
1000 1001
/* Set fcon to the appropriate label for path and mode, or return -1.  */
static int
1002
getContext(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
1003
           const char *newpath, mode_t mode, security_context_t *fcon)
E
Eric Blake 已提交
1004 1005
{
#if HAVE_SELINUX_LABEL_H
1006
    virSecuritySELinuxDataPtr data = virSecurityManagerGetPrivateData(mgr);
E
Eric Blake 已提交
1007

1008
    return selabel_lookup_raw(data->label_handle, fcon, newpath, mode);
E
Eric Blake 已提交
1009 1010 1011 1012 1013
#else
    return matchpathcon(newpath, mode, fcon);
#endif
}

1014 1015 1016

/* This method shouldn't raise errors, since they'll overwrite
 * errors that the caller(s) are already dealing with */
1017
static int
1018 1019
virSecuritySELinuxRestoreFileLabel(virSecurityManagerPtr mgr,
                                   const char *path)
1020
{
1021 1022 1023 1024
    struct stat buf;
    security_context_t fcon = NULL;
    int rc = -1;
    char *newpath = NULL;
1025
    char ebuf[1024];
1026

1027 1028 1029 1030 1031 1032
    /* Some paths are auto-generated, so let's be safe here and do
     * nothing if nothing is needed.
     */
    if (!path)
        return 0;

1033 1034
    VIR_INFO("Restoring SELinux context on '%s'", path);

1035
    if (virFileResolveLink(path, &newpath) < 0) {
1036 1037
        VIR_WARN("cannot resolve symlink %s: %s", path,
                 virStrerror(errno, ebuf, sizeof(ebuf)));
D
Daniel P. Berrange 已提交
1038
        goto err;
1039
    }
1040

1041
    if (stat(newpath, &buf) != 0) {
1042 1043
        VIR_WARN("cannot stat %s: %s", newpath,
                 virStrerror(errno, ebuf, sizeof(ebuf)));
D
Daniel P. Berrange 已提交
1044
        goto err;
1045
    }
D
Daniel P. Berrange 已提交
1046

1047
    if (getContext(mgr, newpath, buf.st_mode, &fcon) < 0) {
1048 1049 1050
        /* Any user created path likely does not have a default label,
         * which makes this an expected non error
         */
1051
        VIR_WARN("cannot lookup default selinux label for %s", newpath);
1052
        rc = 0;
1053
    } else {
1054
        rc = virSecuritySELinuxSetFilecon(mgr, newpath, fcon);
1055
    }
1056

1057
 err:
1058
    freecon(fcon);
1059 1060
    VIR_FREE(newpath);
    return rc;
1061 1062
}

1063

1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106
static int
virSecuritySELinuxSetInputLabel(virSecurityManagerPtr mgr,
                                virDomainDefPtr def,
                                virDomainInputDefPtr input)
{
    virSecurityLabelDefPtr seclabel;

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

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

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

    return 0;
}


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

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

    switch ((virDomainInputType) input->type) {
    case VIR_DOMAIN_INPUT_TYPE_PASSTHROUGH:
1107
        rc = virSecuritySELinuxRestoreFileLabel(mgr, input->source.evdev);
1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120
        break;

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

    return rc;
}


1121
static int
1122 1123 1124
virSecuritySELinuxSetTPMFileLabel(virSecurityManagerPtr mgr,
                                  virDomainDefPtr def,
                                  virDomainTPMDefPtr tpm)
1125 1126 1127 1128 1129 1130 1131 1132
{
    int rc;
    virSecurityLabelDefPtr seclabel;
    char *cancel_path;
    const char *tpmdev;

    seclabel = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
    if (seclabel == NULL)
1133
        return 0;
1134 1135 1136 1137

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

        if ((cancel_path = virTPMCreateCancelPath(tpmdev)) != NULL) {
1143 1144
            rc = virSecuritySELinuxSetFilecon(mgr,
                                              cancel_path,
1145 1146 1147
                                              seclabel->imagelabel);
            VIR_FREE(cancel_path);
            if (rc < 0) {
1148
                virSecuritySELinuxRestoreTPMFileLabelInt(mgr, def, tpm);
1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163
                return -1;
            }
        } else {
            return -1;
        }
        break;
    case VIR_DOMAIN_TPM_TYPE_LAST:
        break;
    }

    return 0;
}


static int
1164 1165 1166
virSecuritySELinuxRestoreTPMFileLabelInt(virSecurityManagerPtr mgr,
                                         virDomainDefPtr def,
                                         virDomainTPMDefPtr tpm)
1167 1168 1169 1170 1171 1172 1173 1174
{
    int rc = 0;
    virSecurityLabelDefPtr seclabel;
    char *cancel_path;
    const char *tpmdev;

    seclabel = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
    if (seclabel == NULL)
1175
        return 0;
1176 1177 1178 1179

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

        if ((cancel_path = virTPMCreateCancelPath(tpmdev)) != NULL) {
1183
            if (virSecuritySELinuxRestoreFileLabel(mgr, cancel_path) < 0)
1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195
                rc = -1;
            VIR_FREE(cancel_path);
        }
        break;
    case VIR_DOMAIN_TPM_TYPE_LAST:
        break;
    }

    return rc;
}


1196
static int
1197 1198 1199 1200
virSecuritySELinuxRestoreImageLabelInt(virSecurityManagerPtr mgr,
                                       virDomainDefPtr def,
                                       virStorageSourcePtr src,
                                       bool migrated)
1201
{
1202 1203
    virSecurityLabelDefPtr seclabel;
    virSecurityDeviceLabelDefPtr disk_seclabel;
1204 1205 1206

    if (!src->path || !virStorageSourceIsLocalStorage(src))
        return 0;
1207 1208 1209

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

1212
    disk_seclabel = virStorageSourceGetSecurityLabelDef(src,
1213
                                                        SECURITY_SELINUX_NAME);
1214
    if (!seclabel->relabel || (disk_seclabel && !disk_seclabel->relabel))
1215 1216
        return 0;

1217 1218 1219
    /* 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
1220
     * per-file attribute instead of a disk attribute. */
1221
    if (disk_seclabel && disk_seclabel->labelskip &&
1222
        !src->backingStore)
1223 1224
        return 0;

1225
    /* Don't restore labels on readonly/shared disks, because other VMs may
1226 1227 1228 1229 1230
     * 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)
1231 1232 1233
        return 0;


1234 1235 1236
    /* 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 :-) */
1237
    if (migrated) {
1238
        int rc = virFileIsSharedFS(src->path);
1239 1240 1241 1242
        if (rc < 0)
            return -1;
        if (rc == 1) {
            VIR_DEBUG("Skipping image label restore on %s because FS is shared",
1243
                      src->path);
1244 1245 1246 1247
            return 0;
        }
    }

1248
    return virSecuritySELinuxRestoreFileLabel(mgr, src->path);
1249 1250
}

1251 1252

static int
1253 1254 1255
virSecuritySELinuxRestoreDiskLabel(virSecurityManagerPtr mgr,
                                   virDomainDefPtr def,
                                   virDomainDiskDefPtr disk)
1256
{
1257 1258
    return virSecuritySELinuxRestoreImageLabelInt(mgr, def, disk->src,
                                                  false);
1259 1260 1261 1262
}


static int
1263 1264 1265
virSecuritySELinuxRestoreImageLabel(virSecurityManagerPtr mgr,
                                    virDomainDefPtr def,
                                    virStorageSourcePtr src)
1266
{
1267
    return virSecuritySELinuxRestoreImageLabelInt(mgr, def, src, false);
1268 1269 1270
}


1271
static int
1272 1273 1274 1275
virSecuritySELinuxSetImageLabelInternal(virSecurityManagerPtr mgr,
                                        virDomainDefPtr def,
                                        virStorageSourcePtr src,
                                        bool first)
1276
{
1277 1278
    virSecuritySELinuxDataPtr data = virSecurityManagerGetPrivateData(mgr);
    virSecurityLabelDefPtr secdef;
1279
    virSecurityDeviceLabelDefPtr disk_seclabel;
1280
    int ret;
1281

1282 1283 1284 1285
    if (!src->path || !virStorageSourceIsLocalStorage(src))
        return 0;

    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
1286
    if (!secdef || !secdef->relabel)
1287 1288 1289
        return 0;

    disk_seclabel = virStorageSourceGetSecurityLabelDef(src,
1290 1291
                                                        SECURITY_SELINUX_NAME);

1292
    if (disk_seclabel && !disk_seclabel->relabel)
1293 1294
        return 0;

1295
    if (disk_seclabel && disk_seclabel->relabel && disk_seclabel->label) {
1296
        ret = virSecuritySELinuxSetFilecon(mgr, src->path, disk_seclabel->label);
1297 1298
    } else if (first) {
        if (src->shared) {
1299 1300
            ret = virSecuritySELinuxSetFileconOptional(mgr,
                                                       src->path,
1301 1302
                                                       data->file_context);
        } else if (src->readonly) {
1303 1304
            ret = virSecuritySELinuxSetFileconOptional(mgr,
                                                       src->path,
1305
                                                       data->content_context);
1306
        } else if (secdef->imagelabel) {
1307 1308
            ret = virSecuritySELinuxSetFileconOptional(mgr,
                                                       src->path,
1309
                                                       secdef->imagelabel);
1310
        } else {
1311
            ret = 0;
1312 1313
        }
    } else {
1314 1315
        ret = virSecuritySELinuxSetFileconOptional(mgr,
                                                   src->path,
1316
                                                   data->content_context);
1317
    }
1318

1319
    if (ret == 1 && !disk_seclabel) {
1320 1321
        /* If we failed to set a label, but virt_use_nfs let us
         * proceed anyway, then we don't need to relabel later.  */
1322
        disk_seclabel = virSecurityDeviceLabelDefNew(SECURITY_SELINUX_NAME);
1323
        if (!disk_seclabel)
1324
            return -1;
1325
        disk_seclabel->labelskip = true;
1326
        if (VIR_APPEND_ELEMENT(src->seclabels, src->nseclabels,
1327
                               disk_seclabel) < 0) {
1328 1329 1330
            virSecurityDeviceLabelDefFree(disk_seclabel);
            return -1;
        }
1331
        ret = 0;
1332
    }
1333

1334
    return ret;
1335 1336
}

1337 1338

static int
1339 1340 1341
virSecuritySELinuxSetImageLabel(virSecurityManagerPtr mgr,
                                virDomainDefPtr def,
                                virStorageSourcePtr src)
1342
{
1343
    return virSecuritySELinuxSetImageLabelInternal(mgr, def, src, true);
1344 1345 1346
}


1347
static int
1348 1349 1350
virSecuritySELinuxSetDiskLabel(virSecurityManagerPtr mgr,
                               virDomainDefPtr def,
                               virDomainDiskDefPtr disk)
1351 1352

{
1353 1354
    bool first = true;
    virStorageSourcePtr next;
1355

1356
    for (next = disk->src; next; next = next->backingStore) {
1357
        if (virSecuritySELinuxSetImageLabelInternal(mgr, def, next, first) < 0)
1358
            return -1;
1359

1360 1361 1362 1363
        first = false;
    }

    return 0;
1364 1365
}

1366
static int
1367
virSecuritySELinuxSetHostdevLabelHelper(const char *file, void *opaque)
1368
{
1369
    virSecurityLabelDefPtr secdef;
1370 1371 1372
    virSecuritySELinuxCallbackDataPtr data = opaque;
    virSecurityManagerPtr mgr = data->mgr;
    virDomainDefPtr def = data->def;
1373

1374 1375
    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
    if (secdef == NULL)
1376
        return 0;
1377
    return virSecuritySELinuxSetFilecon(mgr, file, secdef->imagelabel);
1378 1379 1380
}

static int
1381 1382
virSecuritySELinuxSetPCILabel(virPCIDevicePtr dev ATTRIBUTE_UNUSED,
                              const char *file, void *opaque)
1383
{
1384
    return virSecuritySELinuxSetHostdevLabelHelper(file, opaque);
1385
}
1386

1387
static int
1388 1389
virSecuritySELinuxSetUSBLabel(virUSBDevicePtr dev ATTRIBUTE_UNUSED,
                              const char *file, void *opaque)
1390
{
1391
    return virSecuritySELinuxSetHostdevLabelHelper(file, opaque);
1392 1393
}

1394
static int
1395 1396
virSecuritySELinuxSetSCSILabel(virSCSIDevicePtr dev,
                               const char *file, void *opaque)
1397
{
1398
    virSecurityLabelDefPtr secdef;
1399
    virSecuritySELinuxCallbackDataPtr ptr = opaque;
1400 1401 1402 1403 1404 1405 1406 1407
    virSecurityManagerPtr mgr = ptr->mgr;
    virSecuritySELinuxDataPtr data = virSecurityManagerGetPrivateData(mgr);

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

    if (virSCSIDeviceGetShareable(dev))
1408
        return virSecuritySELinuxSetFileconOptional(mgr, file,
1409 1410
                                                    data->file_context);
    else if (virSCSIDeviceGetReadonly(dev))
1411
        return virSecuritySELinuxSetFileconOptional(mgr, file,
1412 1413
                                                    data->content_context);
    else
1414 1415
        return virSecuritySELinuxSetFileconOptional(mgr, file,
                                                    secdef->imagelabel);
1416
}
1417

1418
static int
1419 1420 1421 1422
virSecuritySELinuxSetHostdevSubsysLabel(virSecurityManagerPtr mgr,
                                        virDomainDefPtr def,
                                        virDomainHostdevDefPtr dev,
                                        const char *vroot)
1423 1424

{
1425
    virDomainHostdevSubsysUSBPtr usbsrc = &dev->source.subsys.u.usb;
1426
    virDomainHostdevSubsysPCIPtr pcisrc = &dev->source.subsys.u.pci;
1427
    virDomainHostdevSubsysSCSIPtr scsisrc = &dev->source.subsys.u.scsi;
1428 1429
    virSecuritySELinuxCallbackData data = {.mgr = mgr, .def = def};

1430 1431
    int ret = -1;

1432
    /* Like virSecuritySELinuxSetImageLabelInternal() for a networked
1433 1434
     * disk, do nothing for an iSCSI hostdev
     */
1435 1436
    if (dev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI &&
        scsisrc->protocol == VIR_DOMAIN_HOSTDEV_SCSI_PROTOCOL_TYPE_ISCSI)
1437 1438
        return 0;

1439 1440
    switch (dev->source.subsys.type) {
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB: {
1441
        virUSBDevicePtr usb;
1442

1443 1444 1445
        if (dev->missing)
            return 0;

1446 1447
        usb = virUSBDeviceNew(usbsrc->bus,
                              usbsrc->device,
1448
                              vroot);
1449 1450
        if (!usb)
            goto done;
1451

1452
        ret = virUSBDeviceFileIterate(usb, virSecuritySELinuxSetUSBLabel, &data);
1453
        virUSBDeviceFree(usb);
M
Mark McLoughlin 已提交
1454
        break;
1455 1456 1457
    }

    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI: {
1458
        virPCIDevicePtr pci =
1459 1460
            virPCIDeviceNew(pcisrc->addr.domain, pcisrc->addr.bus,
                            pcisrc->addr.slot, pcisrc->addr.function);
1461 1462 1463 1464

        if (!pci)
            goto done;

1465
        if (pcisrc->backend == VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO) {
1466
            char *vfioGroupDev = virPCIDeviceGetIOMMUGroupDev(pci);
1467

1468 1469
            if (!vfioGroupDev) {
                virPCIDeviceFree(pci);
1470
                goto done;
1471
            }
1472
            ret = virSecuritySELinuxSetPCILabel(pci, vfioGroupDev, &data);
1473 1474
            VIR_FREE(vfioGroupDev);
        } else {
1475
            ret = virPCIDeviceFileIterate(pci, virSecuritySELinuxSetPCILabel, &data);
1476
        }
1477
        virPCIDeviceFree(pci);
1478 1479 1480
        break;
    }

1481
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI: {
1482
        virDomainHostdevSubsysSCSIHostPtr scsihostsrc = &scsisrc->u.host;
1483

1484
        virSCSIDevicePtr scsi =
1485
            virSCSIDeviceNew(NULL,
1486 1487
                             scsihostsrc->adapter, scsihostsrc->bus,
                             scsihostsrc->target, scsihostsrc->unit,
1488
                             dev->readonly, dev->shareable);
1489 1490 1491 1492

        if (!scsi)
            goto done;

1493
        ret = virSCSIDeviceFileIterate(scsi,
1494
                                       virSecuritySELinuxSetSCSILabel,
1495
                                       &data);
1496 1497 1498 1499 1500
        virSCSIDeviceFree(scsi);

        break;
    }

1501 1502 1503 1504 1505
    default:
        ret = 0;
        break;
    }

1506
 done:
1507 1508 1509
    return ret;
}

1510

1511
static int
1512 1513 1514 1515
virSecuritySELinuxSetHostdevCapsLabel(virSecurityManagerPtr mgr,
                                      virDomainDefPtr def,
                                      virDomainHostdevDefPtr dev,
                                      const char *vroot)
1516 1517 1518 1519 1520 1521 1522
{
    int ret = -1;
    virSecurityLabelDefPtr secdef;
    char *path;

    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
    if (secdef == NULL)
1523
        return 0;
1524 1525 1526 1527 1528

    switch (dev->source.caps.type) {
    case VIR_DOMAIN_HOSTDEV_CAPS_TYPE_STORAGE: {
        if (vroot) {
            if (virAsprintf(&path, "%s/%s", vroot,
1529
                            dev->source.caps.u.storage.block) < 0)
1530 1531
                return -1;
        } else {
1532
            if (VIR_STRDUP(path, dev->source.caps.u.storage.block) < 0)
1533 1534
                return -1;
        }
1535
        ret = virSecuritySELinuxSetFilecon(mgr, path, secdef->imagelabel);
1536 1537 1538 1539 1540 1541 1542
        VIR_FREE(path);
        break;
    }

    case VIR_DOMAIN_HOSTDEV_CAPS_TYPE_MISC: {
        if (vroot) {
            if (virAsprintf(&path, "%s/%s", vroot,
1543
                            dev->source.caps.u.misc.chardev) < 0)
1544 1545
                return -1;
        } else {
1546
            if (VIR_STRDUP(path, dev->source.caps.u.misc.chardev) < 0)
1547 1548
                return -1;
        }
1549
        ret = virSecuritySELinuxSetFilecon(mgr, path, secdef->imagelabel);
1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562
        VIR_FREE(path);
        break;
    }

    default:
        ret = 0;
        break;
    }

    return ret;
}


1563
static int
1564 1565 1566 1567
virSecuritySELinuxSetHostdevLabel(virSecurityManagerPtr mgr,
                                  virDomainDefPtr def,
                                  virDomainHostdevDefPtr dev,
                                  const char *vroot)
1568 1569 1570 1571 1572

{
    virSecurityLabelDefPtr secdef;

    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
1573
    if (!secdef || !secdef->relabel)
1574 1575 1576 1577
        return 0;

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

1580
    case VIR_DOMAIN_HOSTDEV_MODE_CAPABILITIES:
1581
        return virSecuritySELinuxSetHostdevCapsLabel(mgr, def, dev, vroot);
1582

1583 1584 1585 1586 1587
    default:
        return 0;
    }
}

1588
static int
1589 1590 1591
virSecuritySELinuxRestorePCILabel(virPCIDevicePtr dev ATTRIBUTE_UNUSED,
                                  const char *file,
                                  void *opaque)
1592
{
1593 1594
    virSecurityManagerPtr mgr = opaque;

1595
    return virSecuritySELinuxRestoreFileLabel(mgr, file);
1596 1597 1598
}

static int
1599 1600 1601
virSecuritySELinuxRestoreUSBLabel(virUSBDevicePtr dev ATTRIBUTE_UNUSED,
                                  const char *file,
                                  void *opaque)
1602
{
1603 1604
    virSecurityManagerPtr mgr = opaque;

1605
    return virSecuritySELinuxRestoreFileLabel(mgr, file);
1606 1607
}

1608

1609
static int
1610 1611 1612
virSecuritySELinuxRestoreSCSILabel(virSCSIDevicePtr dev,
                                   const char *file,
                                   void *opaque)
1613 1614 1615
{
    virSecurityManagerPtr mgr = opaque;

1616 1617 1618 1619 1620 1621
    /* Don't restore labels on a shareable or readonly hostdev, because
     * other VMs may still be accessing.
     */
    if (virSCSIDeviceGetShareable(dev) || virSCSIDeviceGetReadonly(dev))
        return 0;

1622
    return virSecuritySELinuxRestoreFileLabel(mgr, file);
1623 1624
}

1625
static int
1626 1627 1628
virSecuritySELinuxRestoreHostdevSubsysLabel(virSecurityManagerPtr mgr,
                                            virDomainHostdevDefPtr dev,
                                            const char *vroot)
1629 1630

{
1631
    virDomainHostdevSubsysUSBPtr usbsrc = &dev->source.subsys.u.usb;
1632
    virDomainHostdevSubsysPCIPtr pcisrc = &dev->source.subsys.u.pci;
1633
    virDomainHostdevSubsysSCSIPtr scsisrc = &dev->source.subsys.u.scsi;
1634 1635
    int ret = -1;

1636
    /* Like virSecuritySELinuxRestoreImageLabelInt() for a networked
1637 1638
     * disk, do nothing for an iSCSI hostdev
     */
1639 1640
    if (dev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI &&
        scsisrc->protocol == VIR_DOMAIN_HOSTDEV_SCSI_PROTOCOL_TYPE_ISCSI)
1641 1642
        return 0;

1643 1644
    switch (dev->source.subsys.type) {
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB: {
1645
        virUSBDevicePtr usb;
1646 1647 1648

        if (dev->missing)
            return 0;
1649

1650 1651
        usb = virUSBDeviceNew(usbsrc->bus,
                              usbsrc->device,
1652
                              vroot);
1653 1654 1655
        if (!usb)
            goto done;

1656
        ret = virUSBDeviceFileIterate(usb, virSecuritySELinuxRestoreUSBLabel, mgr);
1657
        virUSBDeviceFree(usb);
1658 1659 1660 1661 1662

        break;
    }

    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI: {
1663
        virPCIDevicePtr pci =
1664 1665
            virPCIDeviceNew(pcisrc->addr.domain, pcisrc->addr.bus,
                            pcisrc->addr.slot, pcisrc->addr.function);
1666 1667 1668 1669

        if (!pci)
            goto done;

1670
        if (pcisrc->backend == VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO) {
1671
            char *vfioGroupDev = virPCIDeviceGetIOMMUGroupDev(pci);
1672

1673 1674
            if (!vfioGroupDev) {
                virPCIDeviceFree(pci);
1675
                goto done;
1676
            }
1677
            ret = virSecuritySELinuxRestorePCILabel(pci, vfioGroupDev, mgr);
1678 1679
            VIR_FREE(vfioGroupDev);
        } else {
1680
            ret = virPCIDeviceFileIterate(pci, virSecuritySELinuxRestorePCILabel, mgr);
1681
        }
1682
        virPCIDeviceFree(pci);
1683 1684 1685
        break;
    }

1686
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI: {
1687
        virDomainHostdevSubsysSCSIHostPtr scsihostsrc = &scsisrc->u.host;
1688
        virSCSIDevicePtr scsi =
1689
            virSCSIDeviceNew(NULL,
1690 1691
                             scsihostsrc->adapter, scsihostsrc->bus,
                             scsihostsrc->target, scsihostsrc->unit,
1692
                             dev->readonly, dev->shareable);
1693

J
Ján Tomko 已提交
1694 1695
        if (!scsi)
            goto done;
1696

1697
        ret = virSCSIDeviceFileIterate(scsi, virSecuritySELinuxRestoreSCSILabel, mgr);
J
Ján Tomko 已提交
1698
        virSCSIDeviceFree(scsi);
1699

J
Ján Tomko 已提交
1700 1701
        break;
    }
1702

1703 1704 1705 1706 1707
    default:
        ret = 0;
        break;
    }

1708
 done:
1709 1710 1711
    return ret;
}

1712

1713
static int
1714 1715 1716
virSecuritySELinuxRestoreHostdevCapsLabel(virSecurityManagerPtr mgr,
                                          virDomainHostdevDefPtr dev,
                                          const char *vroot)
1717 1718 1719 1720 1721 1722 1723 1724
{
    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,
1725
                            dev->source.caps.u.storage.block) < 0)
1726 1727
                return -1;
        } else {
1728
            if (VIR_STRDUP(path, dev->source.caps.u.storage.block) < 0)
1729 1730
                return -1;
        }
1731
        ret = virSecuritySELinuxRestoreFileLabel(mgr, path);
1732 1733 1734 1735 1736 1737 1738
        VIR_FREE(path);
        break;
    }

    case VIR_DOMAIN_HOSTDEV_CAPS_TYPE_MISC: {
        if (vroot) {
            if (virAsprintf(&path, "%s/%s", vroot,
1739
                            dev->source.caps.u.misc.chardev) < 0)
1740 1741
                return -1;
        } else {
1742
            if (VIR_STRDUP(path, dev->source.caps.u.misc.chardev) < 0)
1743 1744
                return -1;
        }
1745
        ret = virSecuritySELinuxRestoreFileLabel(mgr, path);
1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758
        VIR_FREE(path);
        break;
    }

    default:
        ret = 0;
        break;
    }

    return ret;
}


1759
static int
1760 1761 1762 1763
virSecuritySELinuxRestoreHostdevLabel(virSecurityManagerPtr mgr,
                                      virDomainDefPtr def,
                                      virDomainHostdevDefPtr dev,
                                      const char *vroot)
1764 1765 1766 1767 1768

{
    virSecurityLabelDefPtr secdef;

    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
1769
    if (!secdef || !secdef->relabel)
1770 1771 1772 1773
        return 0;

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

1776
    case VIR_DOMAIN_HOSTDEV_MODE_CAPABILITIES:
1777
        return virSecuritySELinuxRestoreHostdevCapsLabel(mgr, dev, vroot);
1778

1779 1780 1781 1782 1783 1784
    default:
        return 0;
    }
}


1785
static int
1786 1787 1788 1789
virSecuritySELinuxSetChardevLabel(virSecurityManagerPtr mgr,
                                  virDomainDefPtr def,
                                  virDomainChrDefPtr dev,
                                  virDomainChrSourceDefPtr dev_source)
1790 1791

{
1792 1793 1794
    virSecurityLabelDefPtr seclabel;
    virSecurityDeviceLabelDefPtr chr_seclabel = NULL;
    char *imagelabel = NULL;
1795 1796 1797
    char *in = NULL, *out = NULL;
    int ret = -1;

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

1802 1803 1804 1805
    if (dev)
        chr_seclabel = virDomainChrDefGetSecurityLabelDef(dev,
                                                          SECURITY_SELINUX_NAME);

1806
    if (chr_seclabel && !chr_seclabel->relabel)
1807 1808
        return 0;

1809 1810 1811 1812 1813 1814
    if (chr_seclabel)
        imagelabel = chr_seclabel->label;
    if (!imagelabel)
        imagelabel = seclabel->imagelabel;

    switch (dev_source->type) {
1815 1816
    case VIR_DOMAIN_CHR_TYPE_DEV:
    case VIR_DOMAIN_CHR_TYPE_FILE:
1817 1818
        ret = virSecuritySELinuxSetFilecon(mgr,
                                           dev_source->data.file.path,
1819 1820 1821 1822 1823
                                           imagelabel);
        break;

    case VIR_DOMAIN_CHR_TYPE_UNIX:
        if (!dev_source->data.nix.listen) {
1824 1825
            if (virSecuritySELinuxSetFilecon(mgr,
                                             dev_source->data.nix.path,
1826 1827 1828 1829
                                             imagelabel) < 0)
                goto done;
        }
        ret = 0;
1830 1831 1832
        break;

    case VIR_DOMAIN_CHR_TYPE_PIPE:
1833
        if ((virAsprintf(&in, "%s.in", dev_source->data.file.path) < 0) ||
1834
            (virAsprintf(&out, "%s.out", dev_source->data.file.path) < 0))
1835 1836
            goto done;
        if (virFileExists(in) && virFileExists(out)) {
1837 1838
            if ((virSecuritySELinuxSetFilecon(mgr, in, imagelabel) < 0) ||
                (virSecuritySELinuxSetFilecon(mgr, out, imagelabel) < 0)) {
1839
                goto done;
1840
            }
1841 1842
        } else if (virSecuritySELinuxSetFilecon(mgr,
                                                dev_source->data.file.path,
1843
                                                imagelabel) < 0) {
1844
            goto done;
1845 1846 1847 1848 1849 1850 1851 1852 1853
        }
        ret = 0;
        break;

    default:
        ret = 0;
        break;
    }

1854
 done:
1855 1856 1857 1858 1859 1860
    VIR_FREE(in);
    VIR_FREE(out);
    return ret;
}

static int
1861 1862 1863 1864
virSecuritySELinuxRestoreChardevLabel(virSecurityManagerPtr mgr,
                                      virDomainDefPtr def,
                                      virDomainChrDefPtr dev,
                                      virDomainChrSourceDefPtr dev_source)
1865 1866

{
1867 1868
    virSecurityLabelDefPtr seclabel;
    virSecurityDeviceLabelDefPtr chr_seclabel = NULL;
1869 1870 1871
    char *in = NULL, *out = NULL;
    int ret = -1;

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

1876 1877 1878
    if (dev)
        chr_seclabel = virDomainChrDefGetSecurityLabelDef(dev,
                                                          SECURITY_SELINUX_NAME);
1879
    if (chr_seclabel && !chr_seclabel->relabel)
1880 1881
        return 0;

1882
    switch (dev_source->type) {
1883 1884
    case VIR_DOMAIN_CHR_TYPE_DEV:
    case VIR_DOMAIN_CHR_TYPE_FILE:
1885
        if (virSecuritySELinuxRestoreFileLabel(mgr, dev_source->data.file.path) < 0)
1886 1887
            goto done;
        ret = 0;
1888
        break;
1889 1890 1891

    case VIR_DOMAIN_CHR_TYPE_UNIX:
        if (!dev_source->data.nix.listen) {
1892
            if (virSecuritySELinuxRestoreFileLabel(mgr, dev_source->data.file.path) < 0)
1893 1894 1895 1896 1897
                goto done;
        }
        ret = 0;
        break;

1898
    case VIR_DOMAIN_CHR_TYPE_PIPE:
1899
        if ((virAsprintf(&out, "%s.out", dev_source->data.file.path) < 0) ||
1900
            (virAsprintf(&in, "%s.in", dev_source->data.file.path) < 0))
1901
            goto done;
1902
        if (virFileExists(in) && virFileExists(out)) {
1903 1904
            if ((virSecuritySELinuxRestoreFileLabel(mgr, out) < 0) ||
                (virSecuritySELinuxRestoreFileLabel(mgr, in) < 0)) {
1905 1906
                goto done;
            }
1907
        } else if (virSecuritySELinuxRestoreFileLabel(mgr, dev_source->data.file.path) < 0) {
1908
            goto done;
1909
        }
1910 1911 1912 1913 1914 1915 1916 1917
        ret = 0;
        break;

    default:
        ret = 0;
        break;
    }

1918
 done:
1919 1920 1921 1922 1923 1924 1925
    VIR_FREE(in);
    VIR_FREE(out);
    return ret;
}


static int
1926 1927
virSecuritySELinuxRestoreSecurityChardevCallback(virDomainDefPtr def,
                                                 virDomainChrDefPtr dev,
1928
                                                 void *opaque)
1929
{
1930 1931
    virSecurityManagerPtr mgr = opaque;

1932 1933 1934 1935 1936
    /* 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;

1937
    return virSecuritySELinuxRestoreChardevLabel(mgr, def, dev, dev->source);
1938 1939 1940
}


E
Eric Blake 已提交
1941
static int
1942 1943
virSecuritySELinuxRestoreSecuritySmartcardCallback(virDomainDefPtr def,
                                                   virDomainSmartcardDefPtr dev,
1944
                                                   void *opaque)
E
Eric Blake 已提交
1945
{
1946
    virSecurityManagerPtr mgr = opaque;
E
Eric Blake 已提交
1947 1948 1949 1950 1951 1952 1953 1954 1955 1956
    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;
1957
        return virSecuritySELinuxRestoreFileLabel(mgr, database);
E
Eric Blake 已提交
1958 1959

    case VIR_DOMAIN_SMARTCARD_TYPE_PASSTHROUGH:
1960
        return virSecuritySELinuxRestoreChardevLabel(mgr, def, NULL, &dev->data.passthru);
E
Eric Blake 已提交
1961 1962

    default:
1963 1964 1965
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unknown smartcard type %d"),
                       dev->type);
E
Eric Blake 已提交
1966 1967 1968 1969 1970 1971 1972
        return -1;
    }

    return 0;
}


1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983
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;
}


1984
static int
1985 1986 1987
virSecuritySELinuxRestoreAllLabel(virSecurityManagerPtr mgr,
                                  virDomainDefPtr def,
                                  bool migrated)
1988
{
1989
    virSecurityLabelDefPtr secdef;
1990
    virSecuritySELinuxDataPtr data = virSecurityManagerGetPrivateData(mgr);
1991
    size_t i;
1992
    int rc = 0;
1993

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

1996 1997
    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);

1998
    if (!secdef || !secdef->relabel || data->skipAllLabel)
1999 2000
        return 0;

2001
    if (def->tpm) {
2002
        if (virSecuritySELinuxRestoreTPMFileLabelInt(mgr, def, def->tpm) < 0)
2003 2004 2005
            rc = -1;
    }

2006
    for (i = 0; i < def->nhostdevs; i++) {
2007 2008 2009 2010
        if (virSecuritySELinuxRestoreHostdevLabel(mgr,
                                                  def,
                                                  def->hostdevs[i],
                                                  NULL) < 0)
2011
            rc = -1;
2012
    }
2013 2014 2015 2016 2017 2018

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

2019
    for (i = 0; i < def->ndisks; i++) {
2020 2021
        virDomainDiskDefPtr disk = def->disks[i];

2022 2023
        if (virSecuritySELinuxRestoreImageLabelInt(mgr, def, disk->src,
                                                   migrated) < 0)
2024 2025
            rc = -1;
    }
2026

2027
    if (virDomainChrDefForeach(def,
2028
                               false,
2029
                               virSecuritySELinuxRestoreSecurityChardevCallback,
2030
                               mgr) < 0)
2031 2032
        rc = -1;

2033
    if (virDomainSmartcardDefForeach(def,
E
Eric Blake 已提交
2034
                                     false,
2035
                                     virSecuritySELinuxRestoreSecuritySmartcardCallback,
2036
                                     mgr) < 0)
E
Eric Blake 已提交
2037 2038
        rc = -1;

2039
    if (def->os.loader && def->os.loader->nvram &&
2040
        virSecuritySELinuxRestoreFileLabel(mgr, def->os.loader->nvram) < 0)
2041 2042
        rc = -1;

2043 2044 2045 2046
    return rc;
}

static int
2047 2048
virSecuritySELinuxReleaseLabel(virSecurityManagerPtr mgr,
                               virDomainDefPtr def)
2049
{
2050 2051 2052 2053
    virSecurityLabelDefPtr secdef;

    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
    if (secdef == NULL)
2054
        return 0;
2055

2056 2057 2058 2059
    if (secdef->type == VIR_DOMAIN_SECLABEL_DYNAMIC) {
        if (secdef->label != NULL) {
            context_t con = context_new(secdef->label);
            if (con) {
2060
                virSecuritySELinuxMCSRemove(mgr, context_range_get(con));
2061 2062 2063 2064 2065 2066
                context_free(con);
            }
        }
        VIR_FREE(secdef->label);
        if (!secdef->baselabel)
            VIR_FREE(secdef->model);
2067 2068 2069
    }
    VIR_FREE(secdef->imagelabel);

2070
    return 0;
2071 2072
}

2073 2074

static int
2075
virSecuritySELinuxSetSavedStateLabel(virSecurityManagerPtr mgr,
2076 2077
                                     virDomainDefPtr def,
                                     const char *savefile)
2078
{
2079 2080 2081
    virSecurityLabelDefPtr secdef;

    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
2082
    if (!secdef || !secdef->relabel)
2083 2084
        return 0;

2085
    return virSecuritySELinuxSetFilecon(mgr, savefile, secdef->imagelabel);
2086 2087 2088 2089
}


static int
2090
virSecuritySELinuxRestoreSavedStateLabel(virSecurityManagerPtr mgr,
2091 2092
                                         virDomainDefPtr def,
                                         const char *savefile)
2093
{
2094 2095 2096
    virSecurityLabelDefPtr secdef;

    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
2097
    if (!secdef || !secdef->relabel)
2098 2099
        return 0;

2100
    return virSecuritySELinuxRestoreFileLabel(mgr, savefile);
2101 2102 2103
}


2104
static int
2105 2106
virSecuritySELinuxSecurityVerify(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
                                 virDomainDefPtr def)
2107
{
2108 2109 2110 2111
    virSecurityLabelDefPtr secdef;

    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
    if (secdef == NULL)
2112
        return 0;
2113

2114
    if (STRNEQ(SECURITY_SELINUX_NAME, secdef->model)) {
2115 2116 2117 2118
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("security label driver mismatch: "
                         "'%s' model configured for domain, but "
                         "hypervisor driver is '%s'."),
2119
                       secdef->model, SECURITY_SELINUX_NAME);
2120 2121 2122
        return -1;
    }

2123 2124
    if (secdef->type == VIR_DOMAIN_SECLABEL_STATIC) {
        if (security_check_context(secdef->label) != 0) {
2125 2126
            virReportError(VIR_ERR_XML_ERROR,
                           _("Invalid security label %s"), secdef->label);
2127 2128 2129 2130 2131 2132
            return -1;
        }
    }
    return 0;
}

2133
static int
2134 2135
virSecuritySELinuxSetProcessLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
                                  virDomainDefPtr def)
2136 2137
{
    /* TODO: verify DOI */
2138 2139 2140
    virSecurityLabelDefPtr secdef;

    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
2141
    if (!secdef || !secdef->label)
2142 2143
        return 0;

2144
    VIR_DEBUG("label=%s", secdef->label);
2145
    if (STRNEQ(SECURITY_SELINUX_NAME, secdef->model)) {
2146 2147 2148 2149
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("security label driver mismatch: "
                         "'%s' model configured for domain, but "
                         "hypervisor driver is '%s'."),
2150
                       secdef->model, SECURITY_SELINUX_NAME);
2151
        if (security_getenforce() == 1)
2152
            return -1;
2153 2154
    }

M
Martin Kletzander 已提交
2155
    if (setexeccon_raw(secdef->label) == -1) {
2156
        virReportSystemError(errno,
2157 2158
                             _("unable to set security context '%s'"),
                             secdef->label);
2159
        if (security_getenforce() == 1)
2160
            return -1;
2161 2162
    }

2163 2164 2165
    return 0;
}

2166
static int
2167 2168 2169
virSecuritySELinuxSetChildProcessLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
                                       virDomainDefPtr def,
                                       virCommandPtr cmd)
2170 2171 2172 2173 2174
{
    /* TODO: verify DOI */
    virSecurityLabelDefPtr secdef;

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

    VIR_DEBUG("label=%s", secdef->label);
2179
    if (STRNEQ(SECURITY_SELINUX_NAME, secdef->model)) {
2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193
        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;
}

2194
static int
2195 2196
virSecuritySELinuxSetDaemonSocketLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
                                       virDomainDefPtr def)
2197 2198
{
    /* TODO: verify DOI */
2199
    virSecurityLabelDefPtr secdef;
2200
    security_context_t scon = NULL;
2201
    char *str = NULL;
2202 2203
    int rc = -1;

2204
    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
2205
    if (!secdef || !secdef->label)
2206 2207
        return 0;

2208
    if (STRNEQ(SECURITY_SELINUX_NAME, secdef->model)) {
2209 2210 2211 2212
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("security label driver mismatch: "
                         "'%s' model configured for domain, but "
                         "hypervisor driver is '%s'."),
2213
                       secdef->model, SECURITY_SELINUX_NAME);
2214 2215 2216
        goto done;
    }

M
Martin Kletzander 已提交
2217
    if (getcon_raw(&scon) == -1) {
2218 2219 2220 2221 2222 2223
        virReportSystemError(errno,
                             _("unable to get current process context '%s'"),
                             secdef->label);
        goto done;
    }

2224
    if (!(str = virSecuritySELinuxContextAddRange(secdef->label, scon)))
2225 2226
        goto done;

2227 2228
    VIR_DEBUG("Setting VM %s socket context %s", def->name, str);
    if (setsockcreatecon_raw(str) == -1) {
2229
        virReportSystemError(errno,
2230
                             _("unable to set socket security context '%s'"), str);
2231 2232 2233 2234
        goto done;
    }

    rc = 0;
2235
 done:
2236 2237 2238 2239

    if (security_getenforce() != 1)
        rc = 0;
    freecon(scon);
2240
    VIR_FREE(str);
2241 2242 2243
    return rc;
}

2244
static int
2245 2246
virSecuritySELinuxSetSocketLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
                                 virDomainDefPtr vm)
2247
{
2248
    virSecurityLabelDefPtr secdef;
2249 2250
    int rc = -1;

2251
    secdef = virDomainDefGetSecurityLabelDef(vm, SECURITY_SELINUX_NAME);
2252
    if (!secdef || !secdef->label)
2253 2254
        return 0;

2255
    if (STRNEQ(SECURITY_SELINUX_NAME, secdef->model)) {
2256 2257 2258 2259
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("security label driver mismatch: "
                         "'%s' model configured for domain, but "
                         "hypervisor driver is '%s'."),
2260
                       secdef->model, SECURITY_SELINUX_NAME);
2261 2262 2263 2264
        goto done;
    }

    VIR_DEBUG("Setting VM %s socket context %s",
2265
              vm->name, secdef->label);
M
Martin Kletzander 已提交
2266
    if (setsockcreatecon_raw(secdef->label) == -1) {
2267 2268 2269 2270 2271 2272 2273 2274
        virReportSystemError(errno,
                             _("unable to set socket security context '%s'"),
                             secdef->label);
        goto done;
    }

    rc = 0;

2275
 done:
2276 2277 2278 2279 2280 2281
    if (security_getenforce() != 1)
        rc = 0;

    return rc;
}

2282
static int
2283 2284
virSecuritySELinuxClearSocketLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
                                   virDomainDefPtr def)
2285 2286
{
    /* TODO: verify DOI */
2287 2288 2289
    virSecurityLabelDefPtr secdef;

    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
2290
    if (!secdef || !secdef->label)
2291 2292
        return 0;

2293
    if (STRNEQ(SECURITY_SELINUX_NAME, secdef->model)) {
2294 2295 2296 2297
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("security label driver mismatch: "
                         "'%s' model configured for domain, but "
                         "hypervisor driver is '%s'."),
2298
                       secdef->model, SECURITY_SELINUX_NAME);
2299 2300 2301 2302
        if (security_getenforce() == 1)
            return -1;
    }

M
Martin Kletzander 已提交
2303
    if (setsockcreatecon_raw(NULL) == -1) {
2304 2305 2306 2307 2308 2309 2310 2311 2312
        virReportSystemError(errno,
                             _("unable to clear socket security context '%s'"),
                             secdef->label);
        if (security_getenforce() == 1)
            return -1;
    }
    return 0;
}

2313 2314

static int
2315 2316
virSecuritySELinuxSetSecurityChardevCallback(virDomainDefPtr def,
                                             virDomainChrDefPtr dev,
2317
                                             void *opaque)
2318
{
2319 2320
    virSecurityManagerPtr mgr = opaque;

2321 2322 2323 2324 2325
    /* 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;

2326
    return virSecuritySELinuxSetChardevLabel(mgr, def, dev, dev->source);
2327 2328 2329
}


E
Eric Blake 已提交
2330
static int
2331 2332 2333
virSecuritySELinuxSetSecuritySmartcardCallback(virDomainDefPtr def,
                                               virDomainSmartcardDefPtr dev,
                                               void *opaque)
E
Eric Blake 已提交
2334 2335
{
    const char *database;
2336 2337
    virSecurityManagerPtr mgr = opaque;
    virSecuritySELinuxDataPtr data = virSecurityManagerGetPrivateData(mgr);
E
Eric Blake 已提交
2338 2339 2340 2341 2342 2343 2344 2345 2346

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

    case VIR_DOMAIN_SMARTCARD_TYPE_PASSTHROUGH:
2350 2351
        return virSecuritySELinuxSetChardevLabel(mgr, def, NULL,
                                                 &dev->data.passthru);
E
Eric Blake 已提交
2352 2353

    default:
2354 2355 2356
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unknown smartcard type %d"),
                       dev->type);
E
Eric Blake 已提交
2357 2358 2359 2360 2361 2362 2363
        return -1;
    }

    return 0;
}


2364
static int
2365 2366 2367
virSecuritySELinuxSetAllLabel(virSecurityManagerPtr mgr,
                              virDomainDefPtr def,
                              const char *stdin_path)
2368
{
2369
    size_t i;
2370 2371 2372 2373
    virSecuritySELinuxDataPtr data = virSecurityManagerGetPrivateData(mgr);
    virSecurityLabelDefPtr secdef;

    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
2374

2375
    if (!secdef || !secdef->relabel || data->skipAllLabel)
2376 2377
        return 0;

2378
    for (i = 0; i < def->ndisks; i++) {
2379
        /* XXX fixme - we need to recursively label the entire tree :-( */
E
Eric Blake 已提交
2380
        if (virDomainDiskGetType(def->disks[i]) == VIR_STORAGE_TYPE_DIR) {
2381
            VIR_WARN("Unable to relabel directory tree %s for disk %s",
2382 2383
                     virDomainDiskGetSource(def->disks[i]),
                     def->disks[i]->dst);
2384
            continue;
2385
        }
2386 2387
        if (virSecuritySELinuxSetDiskLabel(mgr,
                                           def, def->disks[i]) < 0)
2388 2389
            return -1;
    }
2390
    /* XXX fixme process  def->fss if relabel == true */
2391

2392
    for (i = 0; i < def->nhostdevs; i++) {
2393 2394 2395 2396
        if (virSecuritySELinuxSetHostdevLabel(mgr,
                                              def,
                                              def->hostdevs[i],
                                              NULL) < 0)
2397
            return -1;
2398
    }
2399 2400 2401 2402 2403 2404

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

2405
    if (def->tpm) {
2406
        if (virSecuritySELinuxSetTPMFileLabel(mgr, def, def->tpm) < 0)
2407 2408
            return -1;
    }
2409

2410
    if (virDomainChrDefForeach(def,
2411
                               true,
2412
                               virSecuritySELinuxSetSecurityChardevCallback,
2413
                               mgr) < 0)
2414 2415
        return -1;

2416
    if (virDomainSmartcardDefForeach(def,
E
Eric Blake 已提交
2417
                                     true,
2418
                                     virSecuritySELinuxSetSecuritySmartcardCallback,
2419
                                     mgr) < 0)
E
Eric Blake 已提交
2420 2421
        return -1;

M
Michal Privoznik 已提交
2422 2423
    /* This is different than kernel or initrd. The nvram store
     * is really a disk, qemu can read and write to it. */
2424
    if (def->os.loader && def->os.loader->nvram &&
M
Michal Privoznik 已提交
2425
        secdef && secdef->imagelabel &&
2426 2427
        virSecuritySELinuxSetFilecon(mgr, def->os.loader->nvram,
                                     secdef->imagelabel) < 0)
2428 2429
        return -1;

2430
    if (def->os.kernel &&
2431 2432
        virSecuritySELinuxSetFilecon(mgr, def->os.kernel,
                                     data->content_context) < 0)
2433 2434
        return -1;

2435
    if (def->os.initrd &&
2436 2437
        virSecuritySELinuxSetFilecon(mgr, def->os.initrd,
                                     data->content_context) < 0)
2438 2439
        return -1;

O
Olivia Yin 已提交
2440
    if (def->os.dtb &&
2441 2442
        virSecuritySELinuxSetFilecon(mgr, def->os.dtb,
                                     data->content_context) < 0)
O
Olivia Yin 已提交
2443 2444
        return -1;

J
Ján Tomko 已提交
2445 2446 2447 2448 2449
    if (def->os.slic_table &&
        virSecuritySELinuxSetFilecon(mgr, def->os.slic_table,
                                     data->content_context) < 0)
        return -1;

2450
    if (stdin_path &&
2451 2452
        virSecuritySELinuxSetFilecon(mgr, stdin_path,
                                     data->content_context) < 0)
2453
        return -1;
2454

2455 2456 2457
    return 0;
}

2458
static int
2459 2460 2461
virSecuritySELinuxSetImageFDLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
                                  virDomainDefPtr def,
                                  int fd)
2462
{
2463 2464 2465
    virSecurityLabelDefPtr secdef;

    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
2466
    if (!secdef || !secdef->imagelabel)
2467 2468
        return 0;

2469
    return virSecuritySELinuxFSetFilecon(fd, secdef->imagelabel);
2470 2471
}

2472
static int
2473
virSecuritySELinuxSetTapFDLabel(virSecurityManagerPtr mgr,
2474 2475 2476
                                virDomainDefPtr def,
                                int fd)
{
2477 2478
    struct stat buf;
    security_context_t fcon = NULL;
2479
    virSecurityLabelDefPtr secdef;
2480
    char *str = NULL, *proc = NULL, *fd_path = NULL;
2481
    int rc = -1;
2482 2483

    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
2484
    if (!secdef || !secdef->label)
2485 2486
        return 0;

2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497
    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;
    }

2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515
    /* 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) {
2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528
        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);
2529 2530
    VIR_FREE(fd_path);
    VIR_FREE(proc);
2531 2532
    VIR_FREE(str);
    return rc;
2533 2534
}

2535 2536 2537 2538
static char *
virSecuritySELinuxGenImageLabel(virSecurityManagerPtr mgr,
                                virDomainDefPtr def)
{
2539
    virSecurityLabelDefPtr secdef;
2540 2541 2542 2543
    virSecuritySELinuxDataPtr data = virSecurityManagerGetPrivateData(mgr);
    const char *range;
    context_t ctx = NULL;
    char *label = NULL;
2544
    char *mcs = NULL;
2545

2546 2547 2548 2549
    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
    if (secdef == NULL)
        goto cleanup;

2550 2551 2552
    if (secdef->label) {
        ctx = context_new(secdef->label);
        if (!ctx) {
2553 2554
            virReportSystemError(errno, _("unable to create selinux context for: %s"),
                                 secdef->label);
2555 2556 2557 2558
            goto cleanup;
        }
        range = context_range_get(ctx);
        if (range) {
2559
            if (VIR_STRDUP(mcs, range) < 0)
2560
                goto cleanup;
2561 2562
            if (!(label = virSecuritySELinuxGenNewContext(data->file_context,
                                                          mcs, true)))
2563 2564 2565 2566
                goto cleanup;
        }
    }

2567
 cleanup:
2568 2569 2570
    context_free(ctx);
    VIR_FREE(mcs);
    return label;
2571 2572
}

2573 2574 2575 2576
static char *
virSecuritySELinuxGetSecurityMountOptions(virSecurityManagerPtr mgr,
                                          virDomainDefPtr def)
{
2577
    char *opts = NULL;
2578 2579
    virSecurityLabelDefPtr secdef;

2580 2581 2582 2583 2584 2585 2586
    if ((secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME))) {
        if (!secdef->imagelabel)
            secdef->imagelabel = virSecuritySELinuxGenImageLabel(mgr, def);

        if (secdef->imagelabel &&
            virAsprintf(&opts,
                        ",context=\"%s\"",
2587
                        (const char*) secdef->imagelabel) < 0)
2588 2589
            return NULL;
    }
2590

2591
    if (!opts && VIR_STRDUP(opts, "") < 0)
2592
        return NULL;
2593

2594 2595
    VIR_DEBUG("imageLabel=%s opts=%s",
              secdef ? secdef->imagelabel : "(null)", opts);
2596 2597 2598
    return opts;
}

G
Guido Günther 已提交
2599
static int
2600 2601 2602
virSecuritySELinuxDomainSetPathLabel(virSecurityManagerPtr mgr,
                                     virDomainDefPtr def,
                                     const char *path)
2603 2604 2605 2606 2607 2608 2609
{
    virSecurityLabelDefPtr seclabel;

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

2610
    return virSecuritySELinuxSetFilecon(mgr, path, seclabel->imagelabel);
2611 2612
}

2613
virSecurityDriver virSecurityDriverSELinux = {
2614 2615
    .privateDataLen                     = sizeof(virSecuritySELinuxData),
    .name                               = SECURITY_SELINUX_NAME,
2616 2617 2618
    .probe                              = virSecuritySELinuxSecurityDriverProbe,
    .open                               = virSecuritySELinuxSecurityDriverOpen,
    .close                              = virSecuritySELinuxSecurityDriverClose,
2619

2620 2621
    .getModel                           = virSecuritySELinuxSecurityGetModel,
    .getDOI                             = virSecuritySELinuxSecurityGetDOI,
2622

2623
    .domainSecurityVerify               = virSecuritySELinuxSecurityVerify,
2624

2625 2626
    .domainSetSecurityDiskLabel         = virSecuritySELinuxSetDiskLabel,
    .domainRestoreSecurityDiskLabel     = virSecuritySELinuxRestoreDiskLabel,
2627

2628 2629
    .domainSetSecurityImageLabel        = virSecuritySELinuxSetImageLabel,
    .domainRestoreSecurityImageLabel    = virSecuritySELinuxRestoreImageLabel,
2630

2631 2632 2633
    .domainSetSecurityDaemonSocketLabel = virSecuritySELinuxSetDaemonSocketLabel,
    .domainSetSecuritySocketLabel       = virSecuritySELinuxSetSocketLabel,
    .domainClearSecuritySocketLabel     = virSecuritySELinuxClearSocketLabel,
2634

2635 2636 2637
    .domainGenSecurityLabel             = virSecuritySELinuxGenLabel,
    .domainReserveSecurityLabel         = virSecuritySELinuxReserveLabel,
    .domainReleaseSecurityLabel         = virSecuritySELinuxReleaseLabel,
2638

2639 2640 2641
    .domainGetSecurityProcessLabel      = virSecuritySELinuxGetProcessLabel,
    .domainSetSecurityProcessLabel      = virSecuritySELinuxSetProcessLabel,
    .domainSetSecurityChildProcessLabel = virSecuritySELinuxSetChildProcessLabel,
2642

2643 2644
    .domainSetSecurityAllLabel          = virSecuritySELinuxSetAllLabel,
    .domainRestoreSecurityAllLabel      = virSecuritySELinuxRestoreAllLabel,
2645

2646 2647
    .domainSetSecurityHostdevLabel      = virSecuritySELinuxSetHostdevLabel,
    .domainRestoreSecurityHostdevLabel  = virSecuritySELinuxRestoreHostdevLabel,
2648

2649 2650
    .domainSetSavedStateLabel           = virSecuritySELinuxSetSavedStateLabel,
    .domainRestoreSavedStateLabel       = virSecuritySELinuxRestoreSavedStateLabel,
2651

2652
    .domainSetSecurityImageFDLabel      = virSecuritySELinuxSetImageFDLabel,
2653
    .domainSetSecurityTapFDLabel        = virSecuritySELinuxSetTapFDLabel,
2654

2655
    .domainGetSecurityMountOptions      = virSecuritySELinuxGetSecurityMountOptions,
2656
    .getBaseLabel                       = virSecuritySELinuxGetBaseLabel,
2657

2658
    .domainSetPathLabel                 = virSecuritySELinuxDomainSetPathLabel,
2659
};