security_selinux.c 81.0 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
    switch ((virDomainHostdevSubsysType) dev->source.subsys.type) {
1440
    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
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI_HOST: {
        /* Fall through for now */
    }

1505
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST:
1506 1507 1508 1509
        ret = 0;
        break;
    }

1510
 done:
1511 1512 1513
    return ret;
}

1514

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

    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
    if (secdef == NULL)
1527
        return 0;
1528 1529 1530 1531 1532

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

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

    default:
        ret = 0;
        break;
    }

    return ret;
}


1567
static int
1568 1569 1570 1571
virSecuritySELinuxSetHostdevLabel(virSecurityManagerPtr mgr,
                                  virDomainDefPtr def,
                                  virDomainHostdevDefPtr dev,
                                  const char *vroot)
1572 1573 1574 1575 1576

{
    virSecurityLabelDefPtr secdef;

    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
1577
    if (!secdef || !secdef->relabel)
1578 1579 1580 1581
        return 0;

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

1584
    case VIR_DOMAIN_HOSTDEV_MODE_CAPABILITIES:
1585
        return virSecuritySELinuxSetHostdevCapsLabel(mgr, def, dev, vroot);
1586

1587 1588 1589 1590 1591
    default:
        return 0;
    }
}

1592
static int
1593 1594 1595
virSecuritySELinuxRestorePCILabel(virPCIDevicePtr dev ATTRIBUTE_UNUSED,
                                  const char *file,
                                  void *opaque)
1596
{
1597 1598
    virSecurityManagerPtr mgr = opaque;

1599
    return virSecuritySELinuxRestoreFileLabel(mgr, file);
1600 1601 1602
}

static int
1603 1604 1605
virSecuritySELinuxRestoreUSBLabel(virUSBDevicePtr dev ATTRIBUTE_UNUSED,
                                  const char *file,
                                  void *opaque)
1606
{
1607 1608
    virSecurityManagerPtr mgr = opaque;

1609
    return virSecuritySELinuxRestoreFileLabel(mgr, file);
1610 1611
}

1612

1613
static int
1614 1615 1616
virSecuritySELinuxRestoreSCSILabel(virSCSIDevicePtr dev,
                                   const char *file,
                                   void *opaque)
1617 1618 1619
{
    virSecurityManagerPtr mgr = opaque;

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

1626
    return virSecuritySELinuxRestoreFileLabel(mgr, file);
1627 1628
}

1629
static int
1630 1631 1632
virSecuritySELinuxRestoreHostdevSubsysLabel(virSecurityManagerPtr mgr,
                                            virDomainHostdevDefPtr dev,
                                            const char *vroot)
1633 1634

{
1635
    virDomainHostdevSubsysUSBPtr usbsrc = &dev->source.subsys.u.usb;
1636
    virDomainHostdevSubsysPCIPtr pcisrc = &dev->source.subsys.u.pci;
1637
    virDomainHostdevSubsysSCSIPtr scsisrc = &dev->source.subsys.u.scsi;
1638 1639
    int ret = -1;

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

1647
    switch ((virDomainHostdevSubsysType) dev->source.subsys.type) {
1648
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB: {
1649
        virUSBDevicePtr usb;
1650 1651 1652

        if (dev->missing)
            return 0;
1653

1654 1655
        usb = virUSBDeviceNew(usbsrc->bus,
                              usbsrc->device,
1656
                              vroot);
1657 1658 1659
        if (!usb)
            goto done;

1660
        ret = virUSBDeviceFileIterate(usb, virSecuritySELinuxRestoreUSBLabel, mgr);
1661
        virUSBDeviceFree(usb);
1662 1663 1664 1665 1666

        break;
    }

    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI: {
1667
        virPCIDevicePtr pci =
1668 1669
            virPCIDeviceNew(pcisrc->addr.domain, pcisrc->addr.bus,
                            pcisrc->addr.slot, pcisrc->addr.function);
1670 1671 1672 1673

        if (!pci)
            goto done;

1674
        if (pcisrc->backend == VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO) {
1675
            char *vfioGroupDev = virPCIDeviceGetIOMMUGroupDev(pci);
1676

1677 1678
            if (!vfioGroupDev) {
                virPCIDeviceFree(pci);
1679
                goto done;
1680
            }
1681
            ret = virSecuritySELinuxRestorePCILabel(pci, vfioGroupDev, mgr);
1682 1683
            VIR_FREE(vfioGroupDev);
        } else {
1684
            ret = virPCIDeviceFileIterate(pci, virSecuritySELinuxRestorePCILabel, mgr);
1685
        }
1686
        virPCIDeviceFree(pci);
1687 1688 1689
        break;
    }

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

J
Ján Tomko 已提交
1698 1699
        if (!scsi)
            goto done;
1700

1701
        ret = virSCSIDeviceFileIterate(scsi, virSecuritySELinuxRestoreSCSILabel, mgr);
J
Ján Tomko 已提交
1702
        virSCSIDeviceFree(scsi);
1703

J
Ján Tomko 已提交
1704 1705
        break;
    }
1706

1707 1708 1709 1710
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI_HOST: {
        /* Fall through for now */
    }

1711
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST:
1712 1713 1714 1715
        ret = 0;
        break;
    }

1716
 done:
1717 1718 1719
    return ret;
}

1720

1721
static int
1722 1723 1724
virSecuritySELinuxRestoreHostdevCapsLabel(virSecurityManagerPtr mgr,
                                          virDomainHostdevDefPtr dev,
                                          const char *vroot)
1725 1726 1727 1728 1729 1730 1731 1732
{
    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,
1733
                            dev->source.caps.u.storage.block) < 0)
1734 1735
                return -1;
        } else {
1736
            if (VIR_STRDUP(path, dev->source.caps.u.storage.block) < 0)
1737 1738
                return -1;
        }
1739
        ret = virSecuritySELinuxRestoreFileLabel(mgr, path);
1740 1741 1742 1743 1744 1745 1746
        VIR_FREE(path);
        break;
    }

    case VIR_DOMAIN_HOSTDEV_CAPS_TYPE_MISC: {
        if (vroot) {
            if (virAsprintf(&path, "%s/%s", vroot,
1747
                            dev->source.caps.u.misc.chardev) < 0)
1748 1749
                return -1;
        } else {
1750
            if (VIR_STRDUP(path, dev->source.caps.u.misc.chardev) < 0)
1751 1752
                return -1;
        }
1753
        ret = virSecuritySELinuxRestoreFileLabel(mgr, path);
1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766
        VIR_FREE(path);
        break;
    }

    default:
        ret = 0;
        break;
    }

    return ret;
}


1767
static int
1768 1769 1770 1771
virSecuritySELinuxRestoreHostdevLabel(virSecurityManagerPtr mgr,
                                      virDomainDefPtr def,
                                      virDomainHostdevDefPtr dev,
                                      const char *vroot)
1772 1773 1774 1775 1776

{
    virSecurityLabelDefPtr secdef;

    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
1777
    if (!secdef || !secdef->relabel)
1778 1779 1780 1781
        return 0;

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

1784
    case VIR_DOMAIN_HOSTDEV_MODE_CAPABILITIES:
1785
        return virSecuritySELinuxRestoreHostdevCapsLabel(mgr, dev, vroot);
1786

1787 1788 1789 1790 1791 1792
    default:
        return 0;
    }
}


1793
static int
1794 1795 1796 1797
virSecuritySELinuxSetChardevLabel(virSecurityManagerPtr mgr,
                                  virDomainDefPtr def,
                                  virDomainChrDefPtr dev,
                                  virDomainChrSourceDefPtr dev_source)
1798 1799

{
1800 1801 1802
    virSecurityLabelDefPtr seclabel;
    virSecurityDeviceLabelDefPtr chr_seclabel = NULL;
    char *imagelabel = NULL;
1803 1804 1805
    char *in = NULL, *out = NULL;
    int ret = -1;

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

1810 1811 1812 1813
    if (dev)
        chr_seclabel = virDomainChrDefGetSecurityLabelDef(dev,
                                                          SECURITY_SELINUX_NAME);

1814
    if (chr_seclabel && !chr_seclabel->relabel)
1815 1816
        return 0;

1817 1818 1819 1820 1821 1822
    if (chr_seclabel)
        imagelabel = chr_seclabel->label;
    if (!imagelabel)
        imagelabel = seclabel->imagelabel;

    switch (dev_source->type) {
1823 1824
    case VIR_DOMAIN_CHR_TYPE_DEV:
    case VIR_DOMAIN_CHR_TYPE_FILE:
1825 1826
        ret = virSecuritySELinuxSetFilecon(mgr,
                                           dev_source->data.file.path,
1827 1828 1829 1830 1831
                                           imagelabel);
        break;

    case VIR_DOMAIN_CHR_TYPE_UNIX:
        if (!dev_source->data.nix.listen) {
1832 1833
            if (virSecuritySELinuxSetFilecon(mgr,
                                             dev_source->data.nix.path,
1834 1835 1836 1837
                                             imagelabel) < 0)
                goto done;
        }
        ret = 0;
1838 1839 1840
        break;

    case VIR_DOMAIN_CHR_TYPE_PIPE:
1841
        if ((virAsprintf(&in, "%s.in", dev_source->data.file.path) < 0) ||
1842
            (virAsprintf(&out, "%s.out", dev_source->data.file.path) < 0))
1843 1844
            goto done;
        if (virFileExists(in) && virFileExists(out)) {
1845 1846
            if ((virSecuritySELinuxSetFilecon(mgr, in, imagelabel) < 0) ||
                (virSecuritySELinuxSetFilecon(mgr, out, imagelabel) < 0)) {
1847
                goto done;
1848
            }
1849 1850
        } else if (virSecuritySELinuxSetFilecon(mgr,
                                                dev_source->data.file.path,
1851
                                                imagelabel) < 0) {
1852
            goto done;
1853 1854 1855 1856 1857 1858 1859 1860 1861
        }
        ret = 0;
        break;

    default:
        ret = 0;
        break;
    }

1862
 done:
1863 1864 1865 1866 1867 1868
    VIR_FREE(in);
    VIR_FREE(out);
    return ret;
}

static int
1869 1870 1871 1872
virSecuritySELinuxRestoreChardevLabel(virSecurityManagerPtr mgr,
                                      virDomainDefPtr def,
                                      virDomainChrDefPtr dev,
                                      virDomainChrSourceDefPtr dev_source)
1873 1874

{
1875 1876
    virSecurityLabelDefPtr seclabel;
    virSecurityDeviceLabelDefPtr chr_seclabel = NULL;
1877 1878 1879
    char *in = NULL, *out = NULL;
    int ret = -1;

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

1884 1885 1886
    if (dev)
        chr_seclabel = virDomainChrDefGetSecurityLabelDef(dev,
                                                          SECURITY_SELINUX_NAME);
1887
    if (chr_seclabel && !chr_seclabel->relabel)
1888 1889
        return 0;

1890
    switch (dev_source->type) {
1891 1892
    case VIR_DOMAIN_CHR_TYPE_DEV:
    case VIR_DOMAIN_CHR_TYPE_FILE:
1893
        if (virSecuritySELinuxRestoreFileLabel(mgr, dev_source->data.file.path) < 0)
1894 1895
            goto done;
        ret = 0;
1896
        break;
1897 1898 1899

    case VIR_DOMAIN_CHR_TYPE_UNIX:
        if (!dev_source->data.nix.listen) {
1900
            if (virSecuritySELinuxRestoreFileLabel(mgr, dev_source->data.file.path) < 0)
1901 1902 1903 1904 1905
                goto done;
        }
        ret = 0;
        break;

1906
    case VIR_DOMAIN_CHR_TYPE_PIPE:
1907
        if ((virAsprintf(&out, "%s.out", dev_source->data.file.path) < 0) ||
1908
            (virAsprintf(&in, "%s.in", dev_source->data.file.path) < 0))
1909
            goto done;
1910
        if (virFileExists(in) && virFileExists(out)) {
1911 1912
            if ((virSecuritySELinuxRestoreFileLabel(mgr, out) < 0) ||
                (virSecuritySELinuxRestoreFileLabel(mgr, in) < 0)) {
1913 1914
                goto done;
            }
1915
        } else if (virSecuritySELinuxRestoreFileLabel(mgr, dev_source->data.file.path) < 0) {
1916
            goto done;
1917
        }
1918 1919 1920 1921 1922 1923 1924 1925
        ret = 0;
        break;

    default:
        ret = 0;
        break;
    }

1926
 done:
1927 1928 1929 1930 1931 1932 1933
    VIR_FREE(in);
    VIR_FREE(out);
    return ret;
}


static int
1934 1935
virSecuritySELinuxRestoreSecurityChardevCallback(virDomainDefPtr def,
                                                 virDomainChrDefPtr dev,
1936
                                                 void *opaque)
1937
{
1938 1939
    virSecurityManagerPtr mgr = opaque;

1940 1941 1942 1943 1944
    /* 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;

1945
    return virSecuritySELinuxRestoreChardevLabel(mgr, def, dev, dev->source);
1946 1947 1948
}


E
Eric Blake 已提交
1949
static int
1950 1951
virSecuritySELinuxRestoreSecuritySmartcardCallback(virDomainDefPtr def,
                                                   virDomainSmartcardDefPtr dev,
1952
                                                   void *opaque)
E
Eric Blake 已提交
1953
{
1954
    virSecurityManagerPtr mgr = opaque;
E
Eric Blake 已提交
1955 1956 1957 1958 1959 1960 1961 1962 1963 1964
    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;
1965
        return virSecuritySELinuxRestoreFileLabel(mgr, database);
E
Eric Blake 已提交
1966 1967

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

    default:
1971 1972 1973
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unknown smartcard type %d"),
                       dev->type);
E
Eric Blake 已提交
1974 1975 1976 1977 1978 1979 1980
        return -1;
    }

    return 0;
}


1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991
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;
}


1992
static int
1993 1994 1995
virSecuritySELinuxRestoreAllLabel(virSecurityManagerPtr mgr,
                                  virDomainDefPtr def,
                                  bool migrated)
1996
{
1997
    virSecurityLabelDefPtr secdef;
1998
    virSecuritySELinuxDataPtr data = virSecurityManagerGetPrivateData(mgr);
1999
    size_t i;
2000
    int rc = 0;
2001

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

2004 2005
    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);

2006
    if (!secdef || !secdef->relabel || data->skipAllLabel)
2007 2008
        return 0;

2009
    if (def->tpm) {
2010
        if (virSecuritySELinuxRestoreTPMFileLabelInt(mgr, def, def->tpm) < 0)
2011 2012 2013
            rc = -1;
    }

2014
    for (i = 0; i < def->nhostdevs; i++) {
2015 2016 2017 2018
        if (virSecuritySELinuxRestoreHostdevLabel(mgr,
                                                  def,
                                                  def->hostdevs[i],
                                                  NULL) < 0)
2019
            rc = -1;
2020
    }
2021 2022 2023 2024 2025 2026

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

2027
    for (i = 0; i < def->ndisks; i++) {
2028 2029
        virDomainDiskDefPtr disk = def->disks[i];

2030 2031
        if (virSecuritySELinuxRestoreImageLabelInt(mgr, def, disk->src,
                                                   migrated) < 0)
2032 2033
            rc = -1;
    }
2034

2035
    if (virDomainChrDefForeach(def,
2036
                               false,
2037
                               virSecuritySELinuxRestoreSecurityChardevCallback,
2038
                               mgr) < 0)
2039 2040
        rc = -1;

2041
    if (virDomainSmartcardDefForeach(def,
E
Eric Blake 已提交
2042
                                     false,
2043
                                     virSecuritySELinuxRestoreSecuritySmartcardCallback,
2044
                                     mgr) < 0)
E
Eric Blake 已提交
2045 2046
        rc = -1;

2047
    if (def->os.loader && def->os.loader->nvram &&
2048
        virSecuritySELinuxRestoreFileLabel(mgr, def->os.loader->nvram) < 0)
2049 2050
        rc = -1;

2051 2052 2053 2054
    return rc;
}

static int
2055 2056
virSecuritySELinuxReleaseLabel(virSecurityManagerPtr mgr,
                               virDomainDefPtr def)
2057
{
2058 2059 2060 2061
    virSecurityLabelDefPtr secdef;

    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
    if (secdef == NULL)
2062
        return 0;
2063

2064 2065 2066 2067
    if (secdef->type == VIR_DOMAIN_SECLABEL_DYNAMIC) {
        if (secdef->label != NULL) {
            context_t con = context_new(secdef->label);
            if (con) {
2068
                virSecuritySELinuxMCSRemove(mgr, context_range_get(con));
2069 2070 2071 2072 2073 2074
                context_free(con);
            }
        }
        VIR_FREE(secdef->label);
        if (!secdef->baselabel)
            VIR_FREE(secdef->model);
2075 2076 2077
    }
    VIR_FREE(secdef->imagelabel);

2078
    return 0;
2079 2080
}

2081 2082

static int
2083
virSecuritySELinuxSetSavedStateLabel(virSecurityManagerPtr mgr,
2084 2085
                                     virDomainDefPtr def,
                                     const char *savefile)
2086
{
2087 2088 2089
    virSecurityLabelDefPtr secdef;

    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
2090
    if (!secdef || !secdef->relabel)
2091 2092
        return 0;

2093
    return virSecuritySELinuxSetFilecon(mgr, savefile, secdef->imagelabel);
2094 2095 2096 2097
}


static int
2098
virSecuritySELinuxRestoreSavedStateLabel(virSecurityManagerPtr mgr,
2099 2100
                                         virDomainDefPtr def,
                                         const char *savefile)
2101
{
2102 2103 2104
    virSecurityLabelDefPtr secdef;

    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
2105
    if (!secdef || !secdef->relabel)
2106 2107
        return 0;

2108
    return virSecuritySELinuxRestoreFileLabel(mgr, savefile);
2109 2110 2111
}


2112
static int
2113 2114
virSecuritySELinuxSecurityVerify(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
                                 virDomainDefPtr def)
2115
{
2116 2117 2118 2119
    virSecurityLabelDefPtr secdef;

    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
    if (secdef == NULL)
2120
        return 0;
2121

2122
    if (STRNEQ(SECURITY_SELINUX_NAME, secdef->model)) {
2123 2124 2125 2126
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("security label driver mismatch: "
                         "'%s' model configured for domain, but "
                         "hypervisor driver is '%s'."),
2127
                       secdef->model, SECURITY_SELINUX_NAME);
2128 2129 2130
        return -1;
    }

2131 2132
    if (secdef->type == VIR_DOMAIN_SECLABEL_STATIC) {
        if (security_check_context(secdef->label) != 0) {
2133 2134
            virReportError(VIR_ERR_XML_ERROR,
                           _("Invalid security label %s"), secdef->label);
2135 2136 2137 2138 2139 2140
            return -1;
        }
    }
    return 0;
}

2141
static int
2142 2143
virSecuritySELinuxSetProcessLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
                                  virDomainDefPtr def)
2144 2145
{
    /* TODO: verify DOI */
2146 2147 2148
    virSecurityLabelDefPtr secdef;

    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
2149
    if (!secdef || !secdef->label)
2150 2151
        return 0;

2152
    VIR_DEBUG("label=%s", secdef->label);
2153
    if (STRNEQ(SECURITY_SELINUX_NAME, secdef->model)) {
2154 2155 2156 2157
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("security label driver mismatch: "
                         "'%s' model configured for domain, but "
                         "hypervisor driver is '%s'."),
2158
                       secdef->model, SECURITY_SELINUX_NAME);
2159
        if (security_getenforce() == 1)
2160
            return -1;
2161 2162
    }

M
Martin Kletzander 已提交
2163
    if (setexeccon_raw(secdef->label) == -1) {
2164
        virReportSystemError(errno,
2165 2166
                             _("unable to set security context '%s'"),
                             secdef->label);
2167
        if (security_getenforce() == 1)
2168
            return -1;
2169 2170
    }

2171 2172 2173
    return 0;
}

2174
static int
2175 2176 2177
virSecuritySELinuxSetChildProcessLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
                                       virDomainDefPtr def,
                                       virCommandPtr cmd)
2178 2179 2180 2181 2182
{
    /* TODO: verify DOI */
    virSecurityLabelDefPtr secdef;

    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
2183
    if (!secdef || !secdef->label)
2184 2185 2186
        return 0;

    VIR_DEBUG("label=%s", secdef->label);
2187
    if (STRNEQ(SECURITY_SELINUX_NAME, secdef->model)) {
2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201
        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;
}

2202
static int
2203 2204
virSecuritySELinuxSetDaemonSocketLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
                                       virDomainDefPtr def)
2205 2206
{
    /* TODO: verify DOI */
2207
    virSecurityLabelDefPtr secdef;
2208
    security_context_t scon = NULL;
2209
    char *str = NULL;
2210 2211
    int rc = -1;

2212
    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
2213
    if (!secdef || !secdef->label)
2214 2215
        return 0;

2216
    if (STRNEQ(SECURITY_SELINUX_NAME, secdef->model)) {
2217 2218 2219 2220
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("security label driver mismatch: "
                         "'%s' model configured for domain, but "
                         "hypervisor driver is '%s'."),
2221
                       secdef->model, SECURITY_SELINUX_NAME);
2222 2223 2224
        goto done;
    }

M
Martin Kletzander 已提交
2225
    if (getcon_raw(&scon) == -1) {
2226 2227 2228 2229 2230 2231
        virReportSystemError(errno,
                             _("unable to get current process context '%s'"),
                             secdef->label);
        goto done;
    }

2232
    if (!(str = virSecuritySELinuxContextAddRange(secdef->label, scon)))
2233 2234
        goto done;

2235 2236
    VIR_DEBUG("Setting VM %s socket context %s", def->name, str);
    if (setsockcreatecon_raw(str) == -1) {
2237
        virReportSystemError(errno,
2238
                             _("unable to set socket security context '%s'"), str);
2239 2240 2241 2242
        goto done;
    }

    rc = 0;
2243
 done:
2244 2245 2246 2247

    if (security_getenforce() != 1)
        rc = 0;
    freecon(scon);
2248
    VIR_FREE(str);
2249 2250 2251
    return rc;
}

2252
static int
2253 2254
virSecuritySELinuxSetSocketLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
                                 virDomainDefPtr vm)
2255
{
2256
    virSecurityLabelDefPtr secdef;
2257 2258
    int rc = -1;

2259
    secdef = virDomainDefGetSecurityLabelDef(vm, SECURITY_SELINUX_NAME);
2260
    if (!secdef || !secdef->label)
2261 2262
        return 0;

2263
    if (STRNEQ(SECURITY_SELINUX_NAME, secdef->model)) {
2264 2265 2266 2267
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("security label driver mismatch: "
                         "'%s' model configured for domain, but "
                         "hypervisor driver is '%s'."),
2268
                       secdef->model, SECURITY_SELINUX_NAME);
2269 2270 2271 2272
        goto done;
    }

    VIR_DEBUG("Setting VM %s socket context %s",
2273
              vm->name, secdef->label);
M
Martin Kletzander 已提交
2274
    if (setsockcreatecon_raw(secdef->label) == -1) {
2275 2276 2277 2278 2279 2280 2281 2282
        virReportSystemError(errno,
                             _("unable to set socket security context '%s'"),
                             secdef->label);
        goto done;
    }

    rc = 0;

2283
 done:
2284 2285 2286 2287 2288 2289
    if (security_getenforce() != 1)
        rc = 0;

    return rc;
}

2290
static int
2291 2292
virSecuritySELinuxClearSocketLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
                                   virDomainDefPtr def)
2293 2294
{
    /* TODO: verify DOI */
2295 2296 2297
    virSecurityLabelDefPtr secdef;

    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
2298
    if (!secdef || !secdef->label)
2299 2300
        return 0;

2301
    if (STRNEQ(SECURITY_SELINUX_NAME, secdef->model)) {
2302 2303 2304 2305
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("security label driver mismatch: "
                         "'%s' model configured for domain, but "
                         "hypervisor driver is '%s'."),
2306
                       secdef->model, SECURITY_SELINUX_NAME);
2307 2308 2309 2310
        if (security_getenforce() == 1)
            return -1;
    }

M
Martin Kletzander 已提交
2311
    if (setsockcreatecon_raw(NULL) == -1) {
2312 2313 2314 2315 2316 2317 2318 2319 2320
        virReportSystemError(errno,
                             _("unable to clear socket security context '%s'"),
                             secdef->label);
        if (security_getenforce() == 1)
            return -1;
    }
    return 0;
}

2321 2322

static int
2323 2324
virSecuritySELinuxSetSecurityChardevCallback(virDomainDefPtr def,
                                             virDomainChrDefPtr dev,
2325
                                             void *opaque)
2326
{
2327 2328
    virSecurityManagerPtr mgr = opaque;

2329 2330 2331 2332 2333
    /* 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;

2334
    return virSecuritySELinuxSetChardevLabel(mgr, def, dev, dev->source);
2335 2336 2337
}


E
Eric Blake 已提交
2338
static int
2339 2340 2341
virSecuritySELinuxSetSecuritySmartcardCallback(virDomainDefPtr def,
                                               virDomainSmartcardDefPtr dev,
                                               void *opaque)
E
Eric Blake 已提交
2342 2343
{
    const char *database;
2344 2345
    virSecurityManagerPtr mgr = opaque;
    virSecuritySELinuxDataPtr data = virSecurityManagerGetPrivateData(mgr);
E
Eric Blake 已提交
2346 2347 2348 2349 2350 2351 2352 2353 2354

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

    case VIR_DOMAIN_SMARTCARD_TYPE_PASSTHROUGH:
2358
        return virSecuritySELinuxSetChardevLabel(mgr, def, NULL,
2359
                                                 dev->data.passthru);
E
Eric Blake 已提交
2360 2361

    default:
2362 2363 2364
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unknown smartcard type %d"),
                       dev->type);
E
Eric Blake 已提交
2365 2366 2367 2368 2369 2370 2371
        return -1;
    }

    return 0;
}


2372
static int
2373 2374 2375
virSecuritySELinuxSetAllLabel(virSecurityManagerPtr mgr,
                              virDomainDefPtr def,
                              const char *stdin_path)
2376
{
2377
    size_t i;
2378 2379 2380 2381
    virSecuritySELinuxDataPtr data = virSecurityManagerGetPrivateData(mgr);
    virSecurityLabelDefPtr secdef;

    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
2382

2383
    if (!secdef || !secdef->relabel || data->skipAllLabel)
2384 2385
        return 0;

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

2400
    for (i = 0; i < def->nhostdevs; i++) {
2401 2402 2403 2404
        if (virSecuritySELinuxSetHostdevLabel(mgr,
                                              def,
                                              def->hostdevs[i],
                                              NULL) < 0)
2405
            return -1;
2406
    }
2407 2408 2409 2410 2411 2412

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

2413
    if (def->tpm) {
2414
        if (virSecuritySELinuxSetTPMFileLabel(mgr, def, def->tpm) < 0)
2415 2416
            return -1;
    }
2417

2418
    if (virDomainChrDefForeach(def,
2419
                               true,
2420
                               virSecuritySELinuxSetSecurityChardevCallback,
2421
                               mgr) < 0)
2422 2423
        return -1;

2424
    if (virDomainSmartcardDefForeach(def,
E
Eric Blake 已提交
2425
                                     true,
2426
                                     virSecuritySELinuxSetSecuritySmartcardCallback,
2427
                                     mgr) < 0)
E
Eric Blake 已提交
2428 2429
        return -1;

M
Michal Privoznik 已提交
2430 2431
    /* This is different than kernel or initrd. The nvram store
     * is really a disk, qemu can read and write to it. */
2432
    if (def->os.loader && def->os.loader->nvram &&
M
Michal Privoznik 已提交
2433
        secdef && secdef->imagelabel &&
2434 2435
        virSecuritySELinuxSetFilecon(mgr, def->os.loader->nvram,
                                     secdef->imagelabel) < 0)
2436 2437
        return -1;

2438
    if (def->os.kernel &&
2439 2440
        virSecuritySELinuxSetFilecon(mgr, def->os.kernel,
                                     data->content_context) < 0)
2441 2442
        return -1;

2443
    if (def->os.initrd &&
2444 2445
        virSecuritySELinuxSetFilecon(mgr, def->os.initrd,
                                     data->content_context) < 0)
2446 2447
        return -1;

O
Olivia Yin 已提交
2448
    if (def->os.dtb &&
2449 2450
        virSecuritySELinuxSetFilecon(mgr, def->os.dtb,
                                     data->content_context) < 0)
O
Olivia Yin 已提交
2451 2452
        return -1;

J
Ján Tomko 已提交
2453 2454 2455 2456 2457
    if (def->os.slic_table &&
        virSecuritySELinuxSetFilecon(mgr, def->os.slic_table,
                                     data->content_context) < 0)
        return -1;

2458
    if (stdin_path &&
2459 2460
        virSecuritySELinuxSetFilecon(mgr, stdin_path,
                                     data->content_context) < 0)
2461
        return -1;
2462

2463 2464 2465
    return 0;
}

2466
static int
2467 2468 2469
virSecuritySELinuxSetImageFDLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
                                  virDomainDefPtr def,
                                  int fd)
2470
{
2471 2472 2473
    virSecurityLabelDefPtr secdef;

    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
2474
    if (!secdef || !secdef->imagelabel)
2475 2476
        return 0;

2477
    return virSecuritySELinuxFSetFilecon(fd, secdef->imagelabel);
2478 2479
}

2480
static int
2481
virSecuritySELinuxSetTapFDLabel(virSecurityManagerPtr mgr,
2482 2483 2484
                                virDomainDefPtr def,
                                int fd)
{
2485 2486
    struct stat buf;
    security_context_t fcon = NULL;
2487
    virSecurityLabelDefPtr secdef;
2488
    char *str = NULL, *proc = NULL, *fd_path = NULL;
2489
    int rc = -1;
2490 2491

    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
2492
    if (!secdef || !secdef->label)
2493 2494
        return 0;

2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505
    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;
    }

2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523
    /* 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) {
2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536
        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);
2537 2538
    VIR_FREE(fd_path);
    VIR_FREE(proc);
2539 2540
    VIR_FREE(str);
    return rc;
2541 2542
}

2543 2544 2545 2546
static char *
virSecuritySELinuxGenImageLabel(virSecurityManagerPtr mgr,
                                virDomainDefPtr def)
{
2547
    virSecurityLabelDefPtr secdef;
2548 2549 2550 2551
    virSecuritySELinuxDataPtr data = virSecurityManagerGetPrivateData(mgr);
    const char *range;
    context_t ctx = NULL;
    char *label = NULL;
2552
    char *mcs = NULL;
2553

2554 2555 2556 2557
    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
    if (secdef == NULL)
        goto cleanup;

2558 2559 2560
    if (secdef->label) {
        ctx = context_new(secdef->label);
        if (!ctx) {
2561 2562
            virReportSystemError(errno, _("unable to create selinux context for: %s"),
                                 secdef->label);
2563 2564 2565 2566
            goto cleanup;
        }
        range = context_range_get(ctx);
        if (range) {
2567
            if (VIR_STRDUP(mcs, range) < 0)
2568
                goto cleanup;
2569 2570
            if (!(label = virSecuritySELinuxGenNewContext(data->file_context,
                                                          mcs, true)))
2571 2572 2573 2574
                goto cleanup;
        }
    }

2575
 cleanup:
2576 2577 2578
    context_free(ctx);
    VIR_FREE(mcs);
    return label;
2579 2580
}

2581 2582 2583 2584
static char *
virSecuritySELinuxGetSecurityMountOptions(virSecurityManagerPtr mgr,
                                          virDomainDefPtr def)
{
2585
    char *opts = NULL;
2586 2587
    virSecurityLabelDefPtr secdef;

2588 2589 2590 2591 2592 2593 2594
    if ((secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME))) {
        if (!secdef->imagelabel)
            secdef->imagelabel = virSecuritySELinuxGenImageLabel(mgr, def);

        if (secdef->imagelabel &&
            virAsprintf(&opts,
                        ",context=\"%s\"",
2595
                        (const char*) secdef->imagelabel) < 0)
2596 2597
            return NULL;
    }
2598

2599
    if (!opts && VIR_STRDUP(opts, "") < 0)
2600
        return NULL;
2601

2602 2603
    VIR_DEBUG("imageLabel=%s opts=%s",
              secdef ? secdef->imagelabel : "(null)", opts);
2604 2605 2606
    return opts;
}

G
Guido Günther 已提交
2607
static int
2608 2609 2610
virSecuritySELinuxDomainSetPathLabel(virSecurityManagerPtr mgr,
                                     virDomainDefPtr def,
                                     const char *path)
2611 2612 2613 2614 2615 2616 2617
{
    virSecurityLabelDefPtr seclabel;

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

2618
    return virSecuritySELinuxSetFilecon(mgr, path, seclabel->imagelabel);
2619 2620
}

2621
virSecurityDriver virSecurityDriverSELinux = {
2622 2623
    .privateDataLen                     = sizeof(virSecuritySELinuxData),
    .name                               = SECURITY_SELINUX_NAME,
2624 2625 2626
    .probe                              = virSecuritySELinuxSecurityDriverProbe,
    .open                               = virSecuritySELinuxSecurityDriverOpen,
    .close                              = virSecuritySELinuxSecurityDriverClose,
2627

2628 2629
    .getModel                           = virSecuritySELinuxSecurityGetModel,
    .getDOI                             = virSecuritySELinuxSecurityGetDOI,
2630

2631
    .domainSecurityVerify               = virSecuritySELinuxSecurityVerify,
2632

2633 2634
    .domainSetSecurityDiskLabel         = virSecuritySELinuxSetDiskLabel,
    .domainRestoreSecurityDiskLabel     = virSecuritySELinuxRestoreDiskLabel,
2635

2636 2637
    .domainSetSecurityImageLabel        = virSecuritySELinuxSetImageLabel,
    .domainRestoreSecurityImageLabel    = virSecuritySELinuxRestoreImageLabel,
2638

2639 2640 2641
    .domainSetSecurityDaemonSocketLabel = virSecuritySELinuxSetDaemonSocketLabel,
    .domainSetSecuritySocketLabel       = virSecuritySELinuxSetSocketLabel,
    .domainClearSecuritySocketLabel     = virSecuritySELinuxClearSocketLabel,
2642

2643 2644 2645
    .domainGenSecurityLabel             = virSecuritySELinuxGenLabel,
    .domainReserveSecurityLabel         = virSecuritySELinuxReserveLabel,
    .domainReleaseSecurityLabel         = virSecuritySELinuxReleaseLabel,
2646

2647 2648 2649
    .domainGetSecurityProcessLabel      = virSecuritySELinuxGetProcessLabel,
    .domainSetSecurityProcessLabel      = virSecuritySELinuxSetProcessLabel,
    .domainSetSecurityChildProcessLabel = virSecuritySELinuxSetChildProcessLabel,
2650

2651 2652
    .domainSetSecurityAllLabel          = virSecuritySELinuxSetAllLabel,
    .domainRestoreSecurityAllLabel      = virSecuritySELinuxRestoreAllLabel,
2653

2654 2655
    .domainSetSecurityHostdevLabel      = virSecuritySELinuxSetHostdevLabel,
    .domainRestoreSecurityHostdevLabel  = virSecuritySELinuxRestoreHostdevLabel,
2656

2657 2658
    .domainSetSavedStateLabel           = virSecuritySELinuxSetSavedStateLabel,
    .domainRestoreSavedStateLabel       = virSecuritySELinuxRestoreSavedStateLabel,
2659

2660
    .domainSetSecurityImageFDLabel      = virSecuritySELinuxSetImageFDLabel,
2661
    .domainSetSecurityTapFDLabel        = virSecuritySELinuxSetTapFDLabel,
2662

2663
    .domainGetSecurityMountOptions      = virSecuritySELinuxGetSecurityMountOptions,
2664
    .getBaseLabel                       = virSecuritySELinuxGetBaseLabel,
2665

2666
    .domainSetPathLabel                 = virSecuritySELinuxDomainSetPathLabel,
2667
};