security_selinux.c 75.8 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 61 62 63
#define MAX_CONTEXT 1024

typedef struct _virSecuritySELinuxData virSecuritySELinuxData;
typedef virSecuritySELinuxData *virSecuritySELinuxDataPtr;

typedef struct _virSecuritySELinuxCallbackData virSecuritySELinuxCallbackData;
typedef virSecuritySELinuxCallbackData *virSecuritySELinuxCallbackDataPtr;

struct _virSecuritySELinuxData {
    char *domain_context;
64
    char *alt_domain_context;
65 66
    char *file_context;
    char *content_context;
67
    virHashTablePtr mcs;
68
    bool skipAllLabel;
69 70 71
#if HAVE_SELINUX_LABEL_H
    struct selabel_handle *label_handle;
#endif
72 73 74 75 76 77 78
};

struct _virSecuritySELinuxCallbackData {
    virSecurityManagerPtr manager;
    virSecurityLabelDefPtr secdef;
};

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

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


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

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

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

103 104 105
    return 0;
}

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

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

115 116

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

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

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

        VIR_FREE(mcs);
    }

    return mcs;
}

167 168 169 170

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

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

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

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

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

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

277
    ret = 0;
278

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

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

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

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

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

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

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

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

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

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

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

397

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

408 409
    data->skipAllLabel = true;

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

419
    if (!(selinux_conf = virConfReadFile(selinux_lxc_contexts_path(), 0)))
420
        goto error;
421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445

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

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

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

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

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

454 455 456
    virConfFree(selinux_conf);
    return 0;

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


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

486 487
    data->skipAllLabel = false;

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

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

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

519

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

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

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

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

543
    return 0;
544

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

558 559

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


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

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

    data = virSecurityManagerGetPrivateData(mgr);

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

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

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

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

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

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

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

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

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

648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667
        baselabel = seclabel->baselabel;
        if (!baselabel) {
            if (def->virtType == VIR_DOMAIN_VIRT_QEMU) {
                if (data->alt_domain_context == NULL) {
                    static bool warned = false;
                    if (!warned) {
                        VIR_WARN("SELinux policy does not define a domain type for QEMU TCG. "
                                 "Guest startup may be denied due to missing 'execmem' privilege "
                                 "unless the 'virt_use_execmem' policy boolean is enabled");
                        warned = true;
                    }
                    baselabel = data->domain_context;
                } else {
                    baselabel = data->alt_domain_context;
                }
            } else {
                baselabel = data->domain_context;
            }
        }

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

672 673 674
        break;

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

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

683 684 685
        break;

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

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

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

703
    rc = 0;
704

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

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

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

727 728 729
    return rc;
}

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

741 742 743 744 745 746
    seclabel = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
    if (seclabel == NULL) {
        return -1;
    }

    if (seclabel->type == VIR_DOMAIN_SECLABEL_STATIC)
747 748
        return 0;

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

    ctx = context_new(pctx);
756
    freecon(pctx);
757
    if (!ctx)
758
        goto error;
759 760 761

    mcs = context_range_get(ctx);
    if (!mcs)
762 763
        goto error;

764
    if ((rv = virSecuritySELinuxMCSAdd(mgr, mcs)) < 0)
765
        goto error;
766

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

    context_free(ctx);

    return 0;

778
 error:
779 780 781 782 783
    context_free(ctx);
    return -1;
}


784
static int
785
virSecuritySELinuxSecurityDriverProbe(const char *virtDriver)
786
{
787
    if (is_selinux_enabled() <= 0)
788 789
        return SECURITY_DRIVER_DISABLE;

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

    return SECURITY_DRIVER_ENABLE;
798 799
}

800

801
static int
802
virSecuritySELinuxSecurityDriverOpen(virSecurityManagerPtr mgr)
803
{
804
    return virSecuritySELinuxInitialize(mgr);
805 806
}

807

808
static int
809
virSecuritySELinuxSecurityDriverClose(virSecurityManagerPtr mgr)
810
{
811 812 813 814 815
    virSecuritySELinuxDataPtr data = virSecurityManagerGetPrivateData(mgr);

    if (!data)
        return 0;

816
#if HAVE_SELINUX_LABEL_H
817 818
    if (data->label_handle)
        selabel_close(data->label_handle);
819 820
#endif

821 822
    virHashFree(data->mcs);

823
    VIR_FREE(data->domain_context);
824
    VIR_FREE(data->alt_domain_context);
825 826 827
    VIR_FREE(data->file_context);
    VIR_FREE(data->content_context);

828 829 830 831
    return 0;
}


832 833
static const char *
virSecuritySELinuxSecurityGetModel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED)
834 835 836 837
{
    return SECURITY_SELINUX_NAME;
}

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

static int
849 850 851 852
virSecuritySELinuxGetSecurityProcessLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
                                          virDomainDefPtr def ATTRIBUTE_UNUSED,
                                          pid_t pid,
                                          virSecurityLabelPtr sec)
853 854 855
{
    security_context_t ctx;

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

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

    strcpy(sec->label, (char *) ctx);
873
    freecon(ctx);
874

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

    return 0;
}

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

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

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

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

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

942
static int
943
virSecuritySELinuxSetFileconOptional(const char *path, char *tcon)
944
{
945
    return virSecuritySELinuxSetFileconHelper(path, tcon, true);
946 947 948
}

static int
949
virSecuritySELinuxSetFilecon(const char *path, char *tcon)
950
{
951
    return virSecuritySELinuxSetFileconHelper(path, tcon, false);
952 953
}

954
static int
955
virSecuritySELinuxFSetFilecon(int fd, char *tcon)
956 957 958 959 960
{
    security_context_t econ;

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

M
Martin Kletzander 已提交
961
    if (fsetfilecon_raw(fd, tcon) < 0) {
962 963
        int fsetfilecon_errno = errno;

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

1001
    return selabel_lookup_raw(data->label_handle, fcon, newpath, mode);
E
Eric Blake 已提交
1002 1003 1004 1005 1006
#else
    return matchpathcon(newpath, mode, fcon);
#endif
}

1007 1008 1009

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

1020 1021
    VIR_INFO("Restoring SELinux context on '%s'", path);

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

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

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

1044
 err:
1045
    freecon(fcon);
1046 1047
    VIR_FREE(newpath);
    return rc;
1048 1049
}

1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126

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

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

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

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

    return 0;
}


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

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

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

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

    return rc;
}


1127
static int
1128
virSecuritySELinuxRestoreSecurityImageLabelInt(virSecurityManagerPtr mgr,
1129 1130 1131
                                               virDomainDefPtr def,
                                               virDomainDiskDefPtr disk,
                                               int migrated)
1132
{
1133 1134
    virSecurityLabelDefPtr seclabel;
    virSecurityDeviceLabelDefPtr disk_seclabel;
1135
    const char *src = virDomainDiskGetSource(disk);
1136 1137 1138 1139

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

1141 1142 1143
    disk_seclabel = virDomainDiskDefGetSecurityLabelDef(disk,
                                                        SECURITY_SELINUX_NAME);
    if (seclabel->norelabel || (disk_seclabel && disk_seclabel->norelabel))
1144 1145
        return 0;

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

1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164
    /* Don't restore labels on readoly/shared disks, because
     * other VMs may still be accessing these
     * Alternatively we could iterate over all running
     * domains and try to figure out if it is in use, but
     * this would not work for clustered filesystems, since
     * we can't see running VMs using the file on other nodes
     * Safest bet is thus to skip the restore step.
     */
    if (disk->readonly || disk->shared)
        return 0;

E
Eric Blake 已提交
1165
    if (!src || virDomainDiskGetType(disk) == VIR_STORAGE_TYPE_NETWORK)
1166 1167
        return 0;

1168 1169 1170 1171 1172 1173
    /* If we have a shared FS & doing migrated, we must not
     * change ownership, because that kills access on the
     * destination host which is sub-optimal for the guest
     * VM's I/O attempts :-)
     */
    if (migrated) {
1174
        int rc = virFileIsSharedFS(src);
1175 1176 1177 1178
        if (rc < 0)
            return -1;
        if (rc == 1) {
            VIR_DEBUG("Skipping image label restore on %s because FS is shared",
1179
                      src);
1180 1181 1182 1183
            return 0;
        }
    }

1184
    return virSecuritySELinuxRestoreSecurityFileLabel(mgr, src);
1185 1186
}

1187 1188

static int
1189 1190 1191
virSecuritySELinuxRestoreSecurityImageLabel(virSecurityManagerPtr mgr,
                                            virDomainDefPtr def,
                                            virDomainDiskDefPtr disk)
1192
{
1193
    return virSecuritySELinuxRestoreSecurityImageLabelInt(mgr, def, disk, 0);
1194 1195 1196
}


1197
static int
1198 1199 1200 1201
virSecuritySELinuxSetSecurityFileLabel(virDomainDiskDefPtr disk,
                                       const char *path,
                                       size_t depth,
                                       void *opaque)
1202
{
1203 1204
    int ret;
    virSecurityDeviceLabelDefPtr disk_seclabel;
1205
    virSecuritySELinuxCallbackDataPtr cbdata = opaque;
1206
    virSecurityLabelDefPtr secdef = cbdata->secdef;
1207
    virSecuritySELinuxDataPtr data = virSecurityManagerGetPrivateData(cbdata->manager);
1208

1209 1210 1211 1212
    disk_seclabel = virDomainDiskDefGetSecurityLabelDef(disk,
                                                        SECURITY_SELINUX_NAME);

    if (disk_seclabel && disk_seclabel->norelabel)
1213 1214
        return 0;

1215 1216 1217
    if (disk_seclabel && !disk_seclabel->norelabel &&
        disk_seclabel->label) {
        ret = virSecuritySELinuxSetFilecon(path, disk_seclabel->label);
1218
    } else if (depth == 0) {
1219

1220
        if (disk->shared) {
1221
            ret = virSecuritySELinuxSetFileconOptional(path, data->file_context);
1222
        } else if (disk->readonly) {
1223
            ret = virSecuritySELinuxSetFileconOptional(path, data->content_context);
1224
        } else if (secdef->imagelabel) {
1225
            ret = virSecuritySELinuxSetFileconOptional(path, secdef->imagelabel);
1226
        } else {
1227
            ret = 0;
1228 1229
        }
    } else {
1230
        ret = virSecuritySELinuxSetFileconOptional(path, data->content_context);
1231
    }
1232
    if (ret == 1 && !disk_seclabel) {
1233 1234
        /* If we failed to set a label, but virt_use_nfs let us
         * proceed anyway, then we don't need to relabel later.  */
1235
        disk_seclabel = virSecurityDeviceLabelDefNew(SECURITY_SELINUX_NAME);
1236
        if (!disk_seclabel)
1237
            return -1;
1238
        disk_seclabel->labelskip = true;
1239
        if (VIR_APPEND_ELEMENT(disk->src.seclabels, disk->src.nseclabels,
1240
                               disk_seclabel) < 0) {
1241 1242 1243
            virSecurityDeviceLabelDefFree(disk_seclabel);
            return -1;
        }
1244
        ret = 0;
1245
    }
1246
    return ret;
1247 1248
}

1249
static int
1250 1251 1252
virSecuritySELinuxSetSecurityImageLabel(virSecurityManagerPtr mgr,
                                        virDomainDefPtr def,
                                        virDomainDiskDefPtr disk)
1253 1254

{
1255 1256
    virSecuritySELinuxCallbackData cbdata;
    cbdata.manager = mgr;
1257
    cbdata.secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
1258

1259 1260
    if (cbdata.secdef == NULL)
        return -1;
1261

1262
    if (cbdata.secdef->norelabel)
1263 1264
        return 0;

E
Eric Blake 已提交
1265
    if (virDomainDiskGetType(disk) == VIR_STORAGE_TYPE_NETWORK)
1266 1267
        return 0;

1268
    return virDomainDiskDefForeachPath(disk,
1269
                                       true,
1270
                                       virSecuritySELinuxSetSecurityFileLabel,
1271
                                       &cbdata);
1272 1273
}

1274
static int
1275
virSecuritySELinuxSetSecurityHostdevLabelHelper(const char *file, void *opaque)
1276
{
1277
    virSecurityLabelDefPtr secdef;
1278
    virDomainDefPtr def = opaque;
1279

1280 1281 1282
    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
    if (secdef == NULL)
        return -1;
1283
    return virSecuritySELinuxSetFilecon(file, secdef->imagelabel);
1284 1285 1286
}

static int
1287
virSecuritySELinuxSetSecurityPCILabel(virPCIDevicePtr dev ATTRIBUTE_UNUSED,
1288
                                      const char *file, void *opaque)
1289
{
1290 1291
    return virSecuritySELinuxSetSecurityHostdevLabelHelper(file, opaque);
}
1292

1293 1294 1295 1296 1297
static int
virSecuritySELinuxSetSecurityUSBLabel(virUSBDevicePtr dev ATTRIBUTE_UNUSED,
                                      const char *file, void *opaque)
{
    return virSecuritySELinuxSetSecurityHostdevLabelHelper(file, opaque);
1298 1299
}

1300 1301 1302 1303 1304 1305
static int
virSecuritySELinuxSetSecuritySCSILabel(virSCSIDevicePtr dev ATTRIBUTE_UNUSED,
                                       const char *file, void *opaque)
{
    return virSecuritySELinuxSetSecurityHostdevLabelHelper(file, opaque);
}
1306

1307
static int
1308 1309 1310
virSecuritySELinuxSetSecurityHostdevSubsysLabel(virDomainDefPtr def,
                                                virDomainHostdevDefPtr dev,
                                                const char *vroot)
1311 1312 1313 1314 1315 1316

{
    int ret = -1;

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

1319 1320 1321
        if (dev->missing)
            return 0;

1322 1323 1324
        usb = virUSBDeviceNew(dev->source.subsys.u.usb.bus,
                              dev->source.subsys.u.usb.device,
                              vroot);
1325 1326
        if (!usb)
            goto done;
1327

1328 1329
        ret = virUSBDeviceFileIterate(usb, virSecuritySELinuxSetSecurityUSBLabel, def);
        virUSBDeviceFree(usb);
M
Mark McLoughlin 已提交
1330
        break;
1331 1332 1333
    }

    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI: {
1334
        virPCIDevicePtr pci =
1335 1336 1337 1338
            virPCIDeviceNew(dev->source.subsys.u.pci.addr.domain,
                            dev->source.subsys.u.pci.addr.bus,
                            dev->source.subsys.u.pci.addr.slot,
                            dev->source.subsys.u.pci.addr.function);
1339 1340 1341 1342

        if (!pci)
            goto done;

1343
        if (dev->source.subsys.u.pci.backend
1344
            == VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO) {
1345
            char *vfioGroupDev = virPCIDeviceGetIOMMUGroupDev(pci);
1346

1347 1348
            if (!vfioGroupDev) {
                virPCIDeviceFree(pci);
1349
                goto done;
1350
            }
1351 1352 1353 1354 1355
            ret = virSecuritySELinuxSetSecurityPCILabel(pci, vfioGroupDev, def);
            VIR_FREE(vfioGroupDev);
        } else {
            ret = virPCIDeviceFileIterate(pci, virSecuritySELinuxSetSecurityPCILabel, def);
        }
1356
        virPCIDeviceFree(pci);
1357 1358 1359
        break;
    }

1360 1361
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI: {
        virSCSIDevicePtr scsi =
1362 1363
            virSCSIDeviceNew(NULL,
                             dev->source.subsys.u.scsi.adapter,
1364 1365 1366
                             dev->source.subsys.u.scsi.bus,
                             dev->source.subsys.u.scsi.target,
                             dev->source.subsys.u.scsi.unit,
1367 1368
                             dev->readonly,
                             dev->shareable);
1369 1370 1371 1372 1373 1374 1375 1376 1377 1378

        if (!scsi)
            goto done;

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

        break;
    }

1379 1380 1381 1382 1383
    default:
        ret = 0;
        break;
    }

1384
 done:
1385 1386 1387
    return ret;
}

1388

1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405
static int
virSecuritySELinuxSetSecurityHostdevCapsLabel(virDomainDefPtr def,
                                              virDomainHostdevDefPtr dev,
                                              const char *vroot)
{
    int ret = -1;
    virSecurityLabelDefPtr secdef;
    char *path;

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

    switch (dev->source.caps.type) {
    case VIR_DOMAIN_HOSTDEV_CAPS_TYPE_STORAGE: {
        if (vroot) {
            if (virAsprintf(&path, "%s/%s", vroot,
1406
                            dev->source.caps.u.storage.block) < 0)
1407 1408
                return -1;
        } else {
1409
            if (VIR_STRDUP(path, dev->source.caps.u.storage.block) < 0)
1410 1411 1412 1413 1414 1415 1416 1417 1418 1419
                return -1;
        }
        ret = virSecuritySELinuxSetFilecon(path, secdef->imagelabel);
        VIR_FREE(path);
        break;
    }

    case VIR_DOMAIN_HOSTDEV_CAPS_TYPE_MISC: {
        if (vroot) {
            if (virAsprintf(&path, "%s/%s", vroot,
1420
                            dev->source.caps.u.misc.chardev) < 0)
1421 1422
                return -1;
        } else {
1423
            if (VIR_STRDUP(path, dev->source.caps.u.misc.chardev) < 0)
1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439
                return -1;
        }
        ret = virSecuritySELinuxSetFilecon(path, secdef->imagelabel);
        VIR_FREE(path);
        break;
    }

    default:
        ret = 0;
        break;
    }

    return ret;
}


1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459
static int
virSecuritySELinuxSetSecurityHostdevLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
                                          virDomainDefPtr def,
                                          virDomainHostdevDefPtr dev,
                                          const char *vroot)

{
    virSecurityLabelDefPtr secdef;

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

    if (secdef->norelabel)
        return 0;

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

1460 1461 1462
    case VIR_DOMAIN_HOSTDEV_MODE_CAPABILITIES:
        return virSecuritySELinuxSetSecurityHostdevCapsLabel(def, dev, vroot);

1463 1464 1465 1466 1467
    default:
        return 0;
    }
}

1468
static int
1469
virSecuritySELinuxRestoreSecurityPCILabel(virPCIDevicePtr dev ATTRIBUTE_UNUSED,
1470
                                          const char *file,
1471
                                          void *opaque)
1472
{
1473 1474 1475
    virSecurityManagerPtr mgr = opaque;

    return virSecuritySELinuxRestoreSecurityFileLabel(mgr, file);
1476 1477 1478
}

static int
1479
virSecuritySELinuxRestoreSecurityUSBLabel(virUSBDevicePtr dev ATTRIBUTE_UNUSED,
1480
                                          const char *file,
1481
                                          void *opaque)
1482
{
1483 1484 1485
    virSecurityManagerPtr mgr = opaque;

    return virSecuritySELinuxRestoreSecurityFileLabel(mgr, file);
1486 1487
}

1488

1489 1490 1491 1492 1493 1494 1495 1496 1497 1498
static int
virSecuritySELinuxRestoreSecuritySCSILabel(virSCSIDevicePtr dev ATTRIBUTE_UNUSED,
                                           const char *file,
                                           void *opaque)
{
    virSecurityManagerPtr mgr = opaque;

    return virSecuritySELinuxRestoreSecurityFileLabel(mgr, file);
}

1499
static int
1500 1501
virSecuritySELinuxRestoreSecurityHostdevSubsysLabel(virSecurityManagerPtr mgr,
                                                    virDomainHostdevDefPtr dev,
1502
                                                    const char *vroot)
1503 1504 1505 1506 1507 1508

{
    int ret = -1;

    switch (dev->source.subsys.type) {
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB: {
1509
        virUSBDevicePtr usb;
1510 1511 1512

        if (dev->missing)
            return 0;
1513

1514 1515 1516
        usb = virUSBDeviceNew(dev->source.subsys.u.usb.bus,
                              dev->source.subsys.u.usb.device,
                              vroot);
1517 1518 1519
        if (!usb)
            goto done;

1520 1521
        ret = virUSBDeviceFileIterate(usb, virSecuritySELinuxRestoreSecurityUSBLabel, mgr);
        virUSBDeviceFree(usb);
1522 1523 1524 1525 1526

        break;
    }

    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI: {
1527
        virPCIDevicePtr pci =
1528 1529 1530 1531
            virPCIDeviceNew(dev->source.subsys.u.pci.addr.domain,
                            dev->source.subsys.u.pci.addr.bus,
                            dev->source.subsys.u.pci.addr.slot,
                            dev->source.subsys.u.pci.addr.function);
1532 1533 1534 1535

        if (!pci)
            goto done;

1536
        if (dev->source.subsys.u.pci.backend
1537
            == VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO) {
1538
            char *vfioGroupDev = virPCIDeviceGetIOMMUGroupDev(pci);
1539

1540 1541
            if (!vfioGroupDev) {
                virPCIDeviceFree(pci);
1542
                goto done;
1543
            }
1544 1545 1546 1547 1548
            ret = virSecuritySELinuxRestoreSecurityPCILabel(pci, vfioGroupDev, mgr);
            VIR_FREE(vfioGroupDev);
        } else {
            ret = virPCIDeviceFileIterate(pci, virSecuritySELinuxRestoreSecurityPCILabel, mgr);
        }
1549
        virPCIDeviceFree(pci);
1550 1551 1552
        break;
    }

1553 1554
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI: {
        virSCSIDevicePtr scsi =
1555 1556
            virSCSIDeviceNew(NULL,
                             dev->source.subsys.u.scsi.adapter,
1557 1558 1559
                             dev->source.subsys.u.scsi.bus,
                             dev->source.subsys.u.scsi.target,
                             dev->source.subsys.u.scsi.unit,
1560 1561
                             dev->readonly,
                             dev->shareable);
1562 1563 1564 1565 1566 1567 1568 1569 1570 1571

            if (!scsi)
                goto done;

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

            break;
       }

1572 1573 1574 1575 1576
    default:
        ret = 0;
        break;
    }

1577
 done:
1578 1579 1580
    return ret;
}

1581

1582
static int
1583 1584
virSecuritySELinuxRestoreSecurityHostdevCapsLabel(virSecurityManagerPtr mgr,
                                                  virDomainHostdevDefPtr dev,
1585 1586 1587 1588 1589 1590 1591 1592 1593
                                                  const char *vroot)
{
    int ret = -1;
    char *path;

    switch (dev->source.caps.type) {
    case VIR_DOMAIN_HOSTDEV_CAPS_TYPE_STORAGE: {
        if (vroot) {
            if (virAsprintf(&path, "%s/%s", vroot,
1594
                            dev->source.caps.u.storage.block) < 0)
1595 1596
                return -1;
        } else {
1597
            if (VIR_STRDUP(path, dev->source.caps.u.storage.block) < 0)
1598 1599
                return -1;
        }
1600
        ret = virSecuritySELinuxRestoreSecurityFileLabel(mgr, path);
1601 1602 1603 1604 1605 1606 1607
        VIR_FREE(path);
        break;
    }

    case VIR_DOMAIN_HOSTDEV_CAPS_TYPE_MISC: {
        if (vroot) {
            if (virAsprintf(&path, "%s/%s", vroot,
1608
                            dev->source.caps.u.misc.chardev) < 0)
1609 1610
                return -1;
        } else {
1611
            if (VIR_STRDUP(path, dev->source.caps.u.misc.chardev) < 0)
1612 1613
                return -1;
        }
1614
        ret = virSecuritySELinuxRestoreSecurityFileLabel(mgr, path);
1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627
        VIR_FREE(path);
        break;
    }

    default:
        ret = 0;
        break;
    }

    return ret;
}


1628
static int
1629
virSecuritySELinuxRestoreSecurityHostdevLabel(virSecurityManagerPtr mgr,
1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645
                                              virDomainDefPtr def,
                                              virDomainHostdevDefPtr dev,
                                              const char *vroot)

{
    virSecurityLabelDefPtr secdef;

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

    if (secdef->norelabel)
        return 0;

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

1648
    case VIR_DOMAIN_HOSTDEV_MODE_CAPABILITIES:
1649
        return virSecuritySELinuxRestoreSecurityHostdevCapsLabel(mgr, dev, vroot);
1650

1651 1652 1653 1654 1655 1656
    default:
        return 0;
    }
}


1657
static int
1658
virSecuritySELinuxSetSecurityChardevLabel(virDomainDefPtr def,
1659 1660
                                          virDomainChrDefPtr dev,
                                          virDomainChrSourceDefPtr dev_source)
1661 1662

{
1663 1664 1665
    virSecurityLabelDefPtr seclabel;
    virSecurityDeviceLabelDefPtr chr_seclabel = NULL;
    char *imagelabel = NULL;
1666 1667 1668
    char *in = NULL, *out = NULL;
    int ret = -1;

1669 1670
    seclabel = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
    if (seclabel == NULL)
1671 1672
        return -1;

1673 1674 1675 1676 1677
    if (dev)
        chr_seclabel = virDomainChrDefGetSecurityLabelDef(dev,
                                                          SECURITY_SELINUX_NAME);

    if (seclabel->norelabel || (chr_seclabel && chr_seclabel->norelabel))
1678 1679
        return 0;

1680 1681 1682 1683 1684 1685
    if (chr_seclabel)
        imagelabel = chr_seclabel->label;
    if (!imagelabel)
        imagelabel = seclabel->imagelabel;

    switch (dev_source->type) {
1686 1687
    case VIR_DOMAIN_CHR_TYPE_DEV:
    case VIR_DOMAIN_CHR_TYPE_FILE:
1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698
        ret = virSecuritySELinuxSetFilecon(dev_source->data.file.path,
                                           imagelabel);
        break;

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

    case VIR_DOMAIN_CHR_TYPE_PIPE:
1702
        if ((virAsprintf(&in, "%s.in", dev_source->data.file.path) < 0) ||
1703
            (virAsprintf(&out, "%s.out", dev_source->data.file.path) < 0))
1704 1705
            goto done;
        if (virFileExists(in) && virFileExists(out)) {
1706 1707
            if ((virSecuritySELinuxSetFilecon(in, imagelabel) < 0) ||
                (virSecuritySELinuxSetFilecon(out, imagelabel) < 0)) {
1708
                goto done;
1709
            }
1710 1711
        } else if (virSecuritySELinuxSetFilecon(dev_source->data.file.path,
                                                imagelabel) < 0) {
1712
            goto done;
1713 1714 1715 1716 1717 1718 1719 1720 1721
        }
        ret = 0;
        break;

    default:
        ret = 0;
        break;
    }

1722
 done:
1723 1724 1725 1726 1727 1728
    VIR_FREE(in);
    VIR_FREE(out);
    return ret;
}

static int
1729 1730
virSecuritySELinuxRestoreSecurityChardevLabel(virSecurityManagerPtr mgr,
                                              virDomainDefPtr def,
1731 1732
                                              virDomainChrDefPtr dev,
                                              virDomainChrSourceDefPtr dev_source)
1733 1734

{
1735 1736
    virSecurityLabelDefPtr seclabel;
    virSecurityDeviceLabelDefPtr chr_seclabel = NULL;
1737 1738 1739
    char *in = NULL, *out = NULL;
    int ret = -1;

1740 1741
    seclabel = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
    if (seclabel == NULL)
1742 1743
        return -1;

1744 1745 1746 1747
    if (dev)
        chr_seclabel = virDomainChrDefGetSecurityLabelDef(dev,
                                                          SECURITY_SELINUX_NAME);
    if (seclabel->norelabel || (chr_seclabel && chr_seclabel->norelabel))
1748 1749
        return 0;

1750
    switch (dev_source->type) {
1751 1752
    case VIR_DOMAIN_CHR_TYPE_DEV:
    case VIR_DOMAIN_CHR_TYPE_FILE:
1753
        if (virSecuritySELinuxRestoreSecurityFileLabel(mgr, dev_source->data.file.path) < 0)
1754 1755
            goto done;
        ret = 0;
1756
        break;
1757 1758 1759

    case VIR_DOMAIN_CHR_TYPE_UNIX:
        if (!dev_source->data.nix.listen) {
1760
            if (virSecuritySELinuxRestoreSecurityFileLabel(mgr, dev_source->data.file.path) < 0)
1761 1762 1763 1764 1765
                goto done;
        }
        ret = 0;
        break;

1766
    case VIR_DOMAIN_CHR_TYPE_PIPE:
1767
        if ((virAsprintf(&out, "%s.out", dev_source->data.file.path) < 0) ||
1768
            (virAsprintf(&in, "%s.in", dev_source->data.file.path) < 0))
1769
            goto done;
1770
        if (virFileExists(in) && virFileExists(out)) {
1771 1772
            if ((virSecuritySELinuxRestoreSecurityFileLabel(mgr, out) < 0) ||
                (virSecuritySELinuxRestoreSecurityFileLabel(mgr, in) < 0)) {
1773 1774
                goto done;
            }
1775
        } else if (virSecuritySELinuxRestoreSecurityFileLabel(mgr, dev_source->data.file.path) < 0) {
1776
            goto done;
1777
        }
1778 1779 1780 1781 1782 1783 1784 1785
        ret = 0;
        break;

    default:
        ret = 0;
        break;
    }

1786
 done:
1787 1788 1789 1790 1791 1792 1793
    VIR_FREE(in);
    VIR_FREE(out);
    return ret;
}


static int
1794 1795
virSecuritySELinuxRestoreSecurityChardevCallback(virDomainDefPtr def,
                                                 virDomainChrDefPtr dev,
1796
                                                 void *opaque)
1797
{
1798 1799
    virSecurityManagerPtr mgr = opaque;

1800 1801 1802 1803 1804
    /* 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;

1805
    return virSecuritySELinuxRestoreSecurityChardevLabel(mgr, def, dev,
1806
                                                         &dev->source);
1807 1808 1809
}


E
Eric Blake 已提交
1810
static int
1811 1812
virSecuritySELinuxRestoreSecuritySmartcardCallback(virDomainDefPtr def,
                                                   virDomainSmartcardDefPtr dev,
1813
                                                   void *opaque)
E
Eric Blake 已提交
1814
{
1815
    virSecurityManagerPtr mgr = opaque;
E
Eric Blake 已提交
1816 1817 1818 1819 1820 1821 1822 1823 1824 1825
    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;
1826
        return virSecuritySELinuxRestoreSecurityFileLabel(mgr, database);
E
Eric Blake 已提交
1827 1828

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

    default:
1832 1833 1834
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unknown smartcard type %d"),
                       dev->type);
E
Eric Blake 已提交
1835 1836 1837 1838 1839 1840 1841
        return -1;
    }

    return 0;
}


1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852
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;
}


1853
static int
1854
virSecuritySELinuxRestoreSecurityAllLabel(virSecurityManagerPtr mgr,
1855 1856
                                          virDomainDefPtr def,
                                          int migrated ATTRIBUTE_UNUSED)
1857
{
1858
    virSecurityLabelDefPtr secdef;
1859
    virSecuritySELinuxDataPtr data = virSecurityManagerGetPrivateData(mgr);
1860
    size_t i;
1861
    int rc = 0;
1862

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

1865 1866 1867 1868
    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
    if (secdef == NULL)
        return -1;

1869
    if (secdef->norelabel || data->skipAllLabel)
1870 1871
        return 0;

1872 1873 1874 1875 1876 1877
    if (def->tpm) {
        if (virSecuritySELinuxRestoreSecurityTPMFileLabelInt(mgr, def,
                                                             def->tpm) < 0)
            rc = -1;
    }

1878
    for (i = 0; i < def->nhostdevs; i++) {
1879 1880
        if (virSecuritySELinuxRestoreSecurityHostdevLabel(mgr,
                                                          def,
1881 1882
                                                          def->hostdevs[i],
                                                          NULL) < 0)
1883
            rc = -1;
1884
    }
1885
    for (i = 0; i < def->ndisks; i++) {
1886 1887 1888 1889
        if (virSecuritySELinuxRestoreSecurityImageLabelInt(mgr,
                                                           def,
                                                           def->disks[i],
                                                           migrated) < 0)
1890 1891
            rc = -1;
    }
1892

1893
    if (virDomainChrDefForeach(def,
1894
                               false,
1895
                               virSecuritySELinuxRestoreSecurityChardevCallback,
1896
                               mgr) < 0)
1897 1898
        rc = -1;

1899
    if (virDomainSmartcardDefForeach(def,
E
Eric Blake 已提交
1900
                                     false,
1901
                                     virSecuritySELinuxRestoreSecuritySmartcardCallback,
1902
                                     mgr) < 0)
E
Eric Blake 已提交
1903 1904
        rc = -1;

1905
    if (def->os.kernel &&
1906
        virSecuritySELinuxRestoreSecurityFileLabel(mgr, def->os.kernel) < 0)
1907 1908
        rc = -1;

1909
    if (def->os.initrd &&
1910
        virSecuritySELinuxRestoreSecurityFileLabel(mgr, def->os.initrd) < 0)
1911 1912
        rc = -1;

O
Olivia Yin 已提交
1913 1914 1915 1916
    if (def->os.dtb &&
        virSecuritySELinuxRestoreSecurityFileLabel(mgr, def->os.dtb) < 0)
        rc = -1;

1917 1918 1919 1920
    return rc;
}

static int
1921
virSecuritySELinuxReleaseSecurityLabel(virSecurityManagerPtr mgr,
1922
                                       virDomainDefPtr def)
1923
{
1924 1925 1926 1927 1928
    virSecurityLabelDefPtr secdef;

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

1930 1931 1932 1933
    if (secdef->type == VIR_DOMAIN_SECLABEL_DYNAMIC) {
        if (secdef->label != NULL) {
            context_t con = context_new(secdef->label);
            if (con) {
1934
                virSecuritySELinuxMCSRemove(mgr, context_range_get(con));
1935 1936 1937 1938 1939 1940
                context_free(con);
            }
        }
        VIR_FREE(secdef->label);
        if (!secdef->baselabel)
            VIR_FREE(secdef->model);
1941 1942 1943
    }
    VIR_FREE(secdef->imagelabel);

1944
    return 0;
1945 1946
}

1947 1948

static int
1949 1950 1951
virSecuritySELinuxSetSavedStateLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
                                     virDomainDefPtr def,
                                     const char *savefile)
1952
{
1953 1954 1955 1956 1957
    virSecurityLabelDefPtr secdef;

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

1959
    if (secdef->norelabel)
1960 1961
        return 0;

1962
    return virSecuritySELinuxSetFilecon(savefile, secdef->imagelabel);
1963 1964 1965 1966
}


static int
1967
virSecuritySELinuxRestoreSavedStateLabel(virSecurityManagerPtr mgr,
1968 1969
                                         virDomainDefPtr def,
                                         const char *savefile)
1970
{
1971 1972 1973 1974 1975
    virSecurityLabelDefPtr secdef;

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

1977
    if (secdef->norelabel)
1978 1979
        return 0;

1980
    return virSecuritySELinuxRestoreSecurityFileLabel(mgr, savefile);
1981 1982 1983
}


1984
static int
1985 1986
virSecuritySELinuxSecurityVerify(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
                                 virDomainDefPtr def)
1987
{
1988 1989 1990 1991 1992 1993
    virSecurityLabelDefPtr secdef;

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

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

2003 2004
    if (secdef->type == VIR_DOMAIN_SECLABEL_STATIC) {
        if (security_check_context(secdef->label) != 0) {
2005 2006
            virReportError(VIR_ERR_XML_ERROR,
                           _("Invalid security label %s"), secdef->label);
2007 2008 2009 2010 2011 2012
            return -1;
        }
    }
    return 0;
}

2013
static int
2014
virSecuritySELinuxSetSecurityProcessLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
2015
                                          virDomainDefPtr def)
2016 2017
{
    /* TODO: verify DOI */
2018 2019 2020 2021 2022
    virSecurityLabelDefPtr secdef;

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

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

2027
    VIR_DEBUG("label=%s", secdef->label);
2028
    if (!STREQ(SECURITY_SELINUX_NAME, secdef->model)) {
2029 2030 2031 2032
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("security label driver mismatch: "
                         "'%s' model configured for domain, but "
                         "hypervisor driver is '%s'."),
2033
                       secdef->model, SECURITY_SELINUX_NAME);
2034
        if (security_getenforce() == 1)
2035
            return -1;
2036 2037
    }

M
Martin Kletzander 已提交
2038
    if (setexeccon_raw(secdef->label) == -1) {
2039
        virReportSystemError(errno,
2040 2041
                             _("unable to set security context '%s'"),
                             secdef->label);
2042
        if (security_getenforce() == 1)
2043
            return -1;
2044 2045
    }

2046 2047 2048
    return 0;
}

2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079
static int
virSecuritySELinuxSetSecurityChildProcessLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
                                               virDomainDefPtr def,
                                               virCommandPtr cmd)
{
    /* TODO: verify DOI */
    virSecurityLabelDefPtr secdef;

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

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

    VIR_DEBUG("label=%s", secdef->label);
    if (!STREQ(SECURITY_SELINUX_NAME, secdef->model)) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("security label driver mismatch: "
                         "'%s' model configured for domain, but "
                         "hypervisor driver is '%s'."),
                       secdef->model, SECURITY_SELINUX_NAME);
        if (security_getenforce() == 1)
            return -1;
    }

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

2080
static int
2081
virSecuritySELinuxSetSecurityDaemonSocketLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
2082
                                               virDomainDefPtr def)
2083 2084
{
    /* TODO: verify DOI */
2085
    virSecurityLabelDefPtr secdef;
2086
    security_context_t scon = NULL;
2087
    char *str = NULL;
2088 2089
    int rc = -1;

2090 2091 2092 2093 2094
    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
    if (secdef == NULL)
        return -1;

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

2097
    if (!STREQ(SECURITY_SELINUX_NAME, secdef->model)) {
2098 2099 2100 2101
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("security label driver mismatch: "
                         "'%s' model configured for domain, but "
                         "hypervisor driver is '%s'."),
2102
                       secdef->model, SECURITY_SELINUX_NAME);
2103 2104 2105
        goto done;
    }

M
Martin Kletzander 已提交
2106
    if (getcon_raw(&scon) == -1) {
2107 2108 2109 2110 2111 2112
        virReportSystemError(errno,
                             _("unable to get current process context '%s'"),
                             secdef->label);
        goto done;
    }

2113
    if (!(str = virSecuritySELinuxContextAddRange(secdef->label, scon)))
2114 2115
        goto done;

2116 2117
    VIR_DEBUG("Setting VM %s socket context %s", def->name, str);
    if (setsockcreatecon_raw(str) == -1) {
2118
        virReportSystemError(errno,
2119
                             _("unable to set socket security context '%s'"), str);
2120 2121 2122 2123
        goto done;
    }

    rc = 0;
2124
 done:
2125 2126 2127 2128

    if (security_getenforce() != 1)
        rc = 0;
    freecon(scon);
2129
    VIR_FREE(str);
2130 2131 2132
    return rc;
}

2133
static int
2134
virSecuritySELinuxSetSecuritySocketLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
2135
                                         virDomainDefPtr vm)
2136
{
2137
    virSecurityLabelDefPtr secdef;
2138 2139
    int rc = -1;

2140 2141 2142 2143
    secdef = virDomainDefGetSecurityLabelDef(vm, SECURITY_SELINUX_NAME);
    if (secdef == NULL)
        return -1;

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

2147
    if (!STREQ(SECURITY_SELINUX_NAME, secdef->model)) {
2148 2149 2150 2151
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("security label driver mismatch: "
                         "'%s' model configured for domain, but "
                         "hypervisor driver is '%s'."),
2152
                       secdef->model, SECURITY_SELINUX_NAME);
2153 2154 2155 2156
        goto done;
    }

    VIR_DEBUG("Setting VM %s socket context %s",
2157
              vm->name, secdef->label);
M
Martin Kletzander 已提交
2158
    if (setsockcreatecon_raw(secdef->label) == -1) {
2159 2160 2161 2162 2163 2164 2165 2166
        virReportSystemError(errno,
                             _("unable to set socket security context '%s'"),
                             secdef->label);
        goto done;
    }

    rc = 0;

2167
 done:
2168 2169 2170 2171 2172 2173
    if (security_getenforce() != 1)
        rc = 0;

    return rc;
}

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

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

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

2188
    if (!STREQ(SECURITY_SELINUX_NAME, secdef->model)) {
2189 2190 2191 2192
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("security label driver mismatch: "
                         "'%s' model configured for domain, but "
                         "hypervisor driver is '%s'."),
2193
                       secdef->model, SECURITY_SELINUX_NAME);
2194 2195 2196 2197
        if (security_getenforce() == 1)
            return -1;
    }

M
Martin Kletzander 已提交
2198
    if (setsockcreatecon_raw(NULL) == -1) {
2199 2200 2201 2202 2203 2204 2205 2206 2207
        virReportSystemError(errno,
                             _("unable to clear socket security context '%s'"),
                             secdef->label);
        if (security_getenforce() == 1)
            return -1;
    }
    return 0;
}

2208 2209

static int
2210 2211 2212
virSecuritySELinuxSetSecurityChardevCallback(virDomainDefPtr def,
                                             virDomainChrDefPtr dev,
                                             void *opaque ATTRIBUTE_UNUSED)
2213
{
2214 2215 2216 2217 2218
    /* 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;

2219
    return virSecuritySELinuxSetSecurityChardevLabel(def, dev, &dev->source);
2220 2221 2222
}


E
Eric Blake 已提交
2223
static int
2224 2225 2226
virSecuritySELinuxSetSecuritySmartcardCallback(virDomainDefPtr def,
                                               virDomainSmartcardDefPtr dev,
                                               void *opaque)
E
Eric Blake 已提交
2227 2228
{
    const char *database;
2229 2230
    virSecurityManagerPtr mgr = opaque;
    virSecuritySELinuxDataPtr data = virSecurityManagerGetPrivateData(mgr);
E
Eric Blake 已提交
2231 2232 2233 2234 2235 2236 2237 2238 2239

    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;
2240
        return virSecuritySELinuxSetFilecon(database, data->content_context);
E
Eric Blake 已提交
2241 2242

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

    default:
2246 2247 2248
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unknown smartcard type %d"),
                       dev->type);
E
Eric Blake 已提交
2249 2250 2251 2252 2253 2254 2255
        return -1;
    }

    return 0;
}


2256
static int
2257 2258 2259
virSecuritySELinuxSetSecurityAllLabel(virSecurityManagerPtr mgr,
                                      virDomainDefPtr def,
                                      const char *stdin_path)
2260
{
2261
    size_t i;
2262 2263 2264 2265 2266 2267
    virSecuritySELinuxDataPtr data = virSecurityManagerGetPrivateData(mgr);
    virSecurityLabelDefPtr secdef;

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

2269
    if (secdef->norelabel || data->skipAllLabel)
2270 2271
        return 0;

2272
    for (i = 0; i < def->ndisks; i++) {
2273
        /* XXX fixme - we need to recursively label the entire tree :-( */
E
Eric Blake 已提交
2274
        if (virDomainDiskGetType(def->disks[i]) == VIR_STORAGE_TYPE_DIR) {
2275
            VIR_WARN("Unable to relabel directory tree %s for disk %s",
2276 2277
                     virDomainDiskGetSource(def->disks[i]),
                     def->disks[i]->dst);
2278
            continue;
2279
        }
2280
        if (virSecuritySELinuxSetSecurityImageLabel(mgr,
2281
                                         def, def->disks[i]) < 0)
2282 2283
            return -1;
    }
2284
    /* XXX fixme process  def->fss if relabel == true */
2285

2286
    for (i = 0; i < def->nhostdevs; i++) {
2287
        if (virSecuritySELinuxSetSecurityHostdevLabel(mgr,
2288 2289 2290
                                                      def,
                                                      def->hostdevs[i],
                                                      NULL) < 0)
2291
            return -1;
2292
    }
2293 2294 2295 2296 2297
    if (def->tpm) {
        if (virSecuritySELinuxSetSecurityTPMFileLabel(mgr, def,
                                                      def->tpm) < 0)
            return -1;
    }
2298

2299
    if (virDomainChrDefForeach(def,
2300
                               true,
2301
                               virSecuritySELinuxSetSecurityChardevCallback,
2302
                               NULL) < 0)
2303 2304
        return -1;

2305
    if (virDomainSmartcardDefForeach(def,
E
Eric Blake 已提交
2306
                                     true,
2307
                                     virSecuritySELinuxSetSecuritySmartcardCallback,
2308
                                     mgr) < 0)
E
Eric Blake 已提交
2309 2310
        return -1;

2311
    if (def->os.kernel &&
2312
        virSecuritySELinuxSetFilecon(def->os.kernel, data->content_context) < 0)
2313 2314
        return -1;

2315
    if (def->os.initrd &&
2316
        virSecuritySELinuxSetFilecon(def->os.initrd, data->content_context) < 0)
2317 2318
        return -1;

O
Olivia Yin 已提交
2319 2320 2321 2322
    if (def->os.dtb &&
        virSecuritySELinuxSetFilecon(def->os.dtb, data->content_context) < 0)
        return -1;

2323
    if (stdin_path) {
2324
        if (virSecuritySELinuxSetFilecon(stdin_path, data->content_context) < 0 &&
2325
            virFileIsSharedFSType(stdin_path, VIR_FILE_SHFS_NFS) != 1)
2326 2327
            return -1;
    }
2328

2329 2330 2331
    return 0;
}

2332
static int
2333 2334 2335
virSecuritySELinuxSetImageFDLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
                                  virDomainDefPtr def,
                                  int fd)
2336
{
2337 2338 2339 2340 2341
    virSecurityLabelDefPtr secdef;

    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
    if (secdef == NULL)
        return -1;
2342 2343 2344 2345

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

2346
    return virSecuritySELinuxFSetFilecon(fd, secdef->imagelabel);
2347 2348
}

2349
static int
2350
virSecuritySELinuxSetTapFDLabel(virSecurityManagerPtr mgr,
2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377
                                virDomainDefPtr def,
                                int fd)
{
    struct stat buf;
    security_context_t fcon = NULL;
    virSecurityLabelDefPtr secdef;
    char *str = NULL;
    int rc = -1;

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

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

    if (fstat(fd, &buf) < 0) {
        virReportSystemError(errno, _("cannot stat tap fd %d"), fd);
        goto cleanup;
    }

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

2378
    if (getContext(mgr, "/dev/tap.*", buf.st_mode, &fcon) < 0) {
2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389
        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);
    }

2390
 cleanup:
2391 2392 2393 2394 2395
    freecon(fcon);
    VIR_FREE(str);
    return rc;
}

2396 2397 2398 2399
static char *
virSecuritySELinuxGenImageLabel(virSecurityManagerPtr mgr,
                                virDomainDefPtr def)
{
2400
    virSecurityLabelDefPtr secdef;
2401 2402 2403 2404
    virSecuritySELinuxDataPtr data = virSecurityManagerGetPrivateData(mgr);
    const char *range;
    context_t ctx = NULL;
    char *label = NULL;
2405
    char *mcs = NULL;
2406

2407 2408 2409 2410
    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
    if (secdef == NULL)
        goto cleanup;

2411 2412 2413
    if (secdef->label) {
        ctx = context_new(secdef->label);
        if (!ctx) {
2414 2415
            virReportSystemError(errno, _("unable to create selinux context for: %s"),
                                 secdef->label);
2416 2417 2418 2419
            goto cleanup;
        }
        range = context_range_get(ctx);
        if (range) {
2420
            if (VIR_STRDUP(mcs, range) < 0)
2421
                goto cleanup;
2422 2423
            if (!(label = virSecuritySELinuxGenNewContext(data->file_context,
                                                          mcs, true)))
2424 2425 2426 2427
                goto cleanup;
        }
    }

2428
 cleanup:
2429 2430 2431
    context_free(ctx);
    VIR_FREE(mcs);
    return label;
2432 2433
}

2434 2435 2436 2437
static char *
virSecuritySELinuxGetSecurityMountOptions(virSecurityManagerPtr mgr,
                                          virDomainDefPtr def)
{
2438
    char *opts = NULL;
2439 2440
    virSecurityLabelDefPtr secdef;

2441 2442 2443 2444 2445 2446 2447
    if ((secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME))) {
        if (!secdef->imagelabel)
            secdef->imagelabel = virSecuritySELinuxGenImageLabel(mgr, def);

        if (secdef->imagelabel &&
            virAsprintf(&opts,
                        ",context=\"%s\"",
2448
                        (const char*) secdef->imagelabel) < 0)
2449 2450
            return NULL;
    }
2451

2452
    if (!opts && VIR_STRDUP(opts, "") < 0)
2453
        return NULL;
2454

2455 2456
    VIR_DEBUG("imageLabel=%s opts=%s",
              secdef ? secdef->imagelabel : "(null)", opts);
2457 2458 2459
    return opts;
}

2460
virSecurityDriver virSecurityDriverSELinux = {
2461 2462
    .privateDataLen                     = sizeof(virSecuritySELinuxData),
    .name                               = SECURITY_SELINUX_NAME,
2463 2464 2465
    .probe                              = virSecuritySELinuxSecurityDriverProbe,
    .open                               = virSecuritySELinuxSecurityDriverOpen,
    .close                              = virSecuritySELinuxSecurityDriverClose,
2466

2467 2468
    .getModel                           = virSecuritySELinuxSecurityGetModel,
    .getDOI                             = virSecuritySELinuxSecurityGetDOI,
2469

2470
    .domainSecurityVerify               = virSecuritySELinuxSecurityVerify,
2471

2472 2473
    .domainSetSecurityImageLabel        = virSecuritySELinuxSetSecurityImageLabel,
    .domainRestoreSecurityImageLabel    = virSecuritySELinuxRestoreSecurityImageLabel,
2474

2475 2476 2477
    .domainSetSecurityDaemonSocketLabel = virSecuritySELinuxSetSecurityDaemonSocketLabel,
    .domainSetSecuritySocketLabel       = virSecuritySELinuxSetSecuritySocketLabel,
    .domainClearSecuritySocketLabel     = virSecuritySELinuxClearSecuritySocketLabel,
2478

2479 2480 2481
    .domainGenSecurityLabel             = virSecuritySELinuxGenSecurityLabel,
    .domainReserveSecurityLabel         = virSecuritySELinuxReserveSecurityLabel,
    .domainReleaseSecurityLabel         = virSecuritySELinuxReleaseSecurityLabel,
2482

2483 2484
    .domainGetSecurityProcessLabel      = virSecuritySELinuxGetSecurityProcessLabel,
    .domainSetSecurityProcessLabel      = virSecuritySELinuxSetSecurityProcessLabel,
2485
    .domainSetSecurityChildProcessLabel = virSecuritySELinuxSetSecurityChildProcessLabel,
2486

2487 2488
    .domainSetSecurityAllLabel          = virSecuritySELinuxSetSecurityAllLabel,
    .domainRestoreSecurityAllLabel      = virSecuritySELinuxRestoreSecurityAllLabel,
2489

2490 2491
    .domainSetSecurityHostdevLabel      = virSecuritySELinuxSetSecurityHostdevLabel,
    .domainRestoreSecurityHostdevLabel  = virSecuritySELinuxRestoreSecurityHostdevLabel,
2492

2493 2494
    .domainSetSavedStateLabel           = virSecuritySELinuxSetSavedStateLabel,
    .domainRestoreSavedStateLabel       = virSecuritySELinuxRestoreSavedStateLabel,
2495

2496
    .domainSetSecurityImageFDLabel      = virSecuritySELinuxSetImageFDLabel,
2497
    .domainSetSecurityTapFDLabel        = virSecuritySELinuxSetTapFDLabel,
2498

2499
    .domainGetSecurityMountOptions      = virSecuritySELinuxGetSecurityMountOptions,
2500
    .getBaseLabel                       = virSecuritySELinuxGetBaseLabel,
2501
};