security_dac.c 36.0 KB
Newer Older
1
/*
2
 * Copyright (C) 2010-2014 Red Hat, Inc.
3 4 5 6 7 8 9 10 11 12 13 14
 *
 * 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.
 *
 * 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
 * <http://www.gnu.org/licenses/>.
17 18 19 20 21 22 23 24 25 26
 *
 * POSIX DAC security driver
 */

#include <config.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#include "security_dac.h"
27
#include "virerror.h"
28
#include "virfile.h"
29
#include "viralloc.h"
30
#include "virlog.h"
31
#include "virpci.h"
32
#include "virusb.h"
33
#include "virscsi.h"
34
#include "virstoragefile.h"
35
#include "virstring.h"
M
Martin Kletzander 已提交
36
#include "virutil.h"
37 38

#define VIR_FROM_THIS VIR_FROM_SECURITY
39 40 41

VIR_LOG_INIT("security.security_dac");

42
#define SECURITY_DAC_NAME "dac"
43 44 45 46 47 48 49

typedef struct _virSecurityDACData virSecurityDACData;
typedef virSecurityDACData *virSecurityDACDataPtr;

struct _virSecurityDACData {
    uid_t user;
    gid_t group;
50 51
    gid_t *groups;
    int ngroups;
52
    bool dynamicOwnership;
53
    char *baselabel;
54 55
};

56 57 58 59 60
/* returns -1 on error, 0 on success */
int
virSecurityDACSetUserAndGroup(virSecurityManagerPtr mgr,
                              uid_t user,
                              gid_t group)
61 62 63 64
{
    virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr);
    priv->user = user;
    priv->group = group;
65

66
    if (virAsprintf(&priv->baselabel, "+%u:+%u",
67 68 69 70 71
                    (unsigned int) user,
                    (unsigned int) group) < 0)
        return -1;

    return 0;
72 73
}

O
Osier Yang 已提交
74 75 76
void
virSecurityDACSetDynamicOwnership(virSecurityManagerPtr mgr,
                                  bool dynamicOwnership)
77 78 79 80 81
{
    virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr);
    priv->dynamicOwnership = dynamicOwnership;
}

82
/* returns 1 if label isn't found, 0 on success, -1 on error */
O
Osier Yang 已提交
83
static int
84
ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3)
O
Osier Yang 已提交
85
virSecurityDACParseIds(virDomainDefPtr def, uid_t *uidPtr, gid_t *gidPtr)
86 87 88 89
{
    virSecurityLabelDefPtr seclabel;

    if (def == NULL)
90
        return 1;
91 92

    seclabel = virDomainDefGetSecurityLabelDef(def, SECURITY_DAC_NAME);
93
    if (seclabel == NULL || seclabel->label == NULL) {
94 95
        VIR_DEBUG("DAC seclabel for domain '%s' wasn't found", def->name);
        return 1;
96 97
    }

98
    if (virParseOwnershipIds(seclabel->label, uidPtr, gidPtr) < 0)
99 100 101 102 103
        return -1;

    return 0;
}

O
Osier Yang 已提交
104
static int
105
ATTRIBUTE_NONNULL(3) ATTRIBUTE_NONNULL(4)
O
Osier Yang 已提交
106
virSecurityDACGetIds(virDomainDefPtr def, virSecurityDACDataPtr priv,
107 108
                     uid_t *uidPtr, gid_t *gidPtr,
                     gid_t **groups, int *ngroups)
109
{
110 111 112 113 114 115 116
    int ret;

    if (!def && !priv) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Failed to determine default DAC seclabel "
                         "for an unknown object"));
        return -1;
117
    }
118

119 120 121 122 123 124
    if (groups)
        *groups = priv ? priv->groups : NULL;
    if (ngroups)
        *ngroups = priv ? priv->ngroups : 0;

    if ((ret = virSecurityDACParseIds(def, uidPtr, gidPtr)) <= 0)
125 126 127 128 129 130 131 132 133
        return ret;

    if (!priv) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("DAC seclabel couldn't be determined "
                         "for domain '%s'"), def->name);
        return -1;
    }

134 135
    *uidPtr = priv->user;
    *gidPtr = priv->group;
136 137

    return 0;
138 139
}

140 141

/* returns 1 if label isn't found, 0 on success, -1 on error */
O
Osier Yang 已提交
142
static int
143
ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3)
O
Osier Yang 已提交
144 145
virSecurityDACParseImageIds(virDomainDefPtr def,
                            uid_t *uidPtr, gid_t *gidPtr)
146 147 148 149
{
    virSecurityLabelDefPtr seclabel;

    if (def == NULL)
150
        return 1;
151 152

    seclabel = virDomainDefGetSecurityLabelDef(def, SECURITY_DAC_NAME);
153
    if (seclabel == NULL || seclabel->imagelabel == NULL) {
154 155
        VIR_DEBUG("DAC imagelabel for domain '%s' wasn't found", def->name);
        return 1;
156 157
    }

158
    if (virParseOwnershipIds(seclabel->imagelabel, uidPtr, gidPtr) < 0)
159 160 161 162 163
        return -1;

    return 0;
}

O
Osier Yang 已提交
164
static int
165
ATTRIBUTE_NONNULL(3) ATTRIBUTE_NONNULL(4)
O
Osier Yang 已提交
166 167
virSecurityDACGetImageIds(virDomainDefPtr def, virSecurityDACDataPtr priv,
                          uid_t *uidPtr, gid_t *gidPtr)
168
{
169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185
    int ret;

    if (!def && !priv) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Failed to determine default DAC imagelabel "
                         "for an unknown object"));
        return -1;
    }

    if ((ret = virSecurityDACParseImageIds(def, uidPtr, gidPtr)) <= 0)
        return ret;

    if (!priv) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("DAC imagelabel couldn't be determined "
                         "for domain '%s'"), def->name);
        return -1;
186
    }
187

188 189
    *uidPtr = priv->user;
    *gidPtr = priv->group;
190 191

    return 0;
192 193 194
}


195
static virSecurityDriverStatus
196
virSecurityDACProbe(const char *virtDriver ATTRIBUTE_UNUSED)
197 198 199 200 201 202 203 204 205 206 207
{
    return SECURITY_DRIVER_ENABLE;
}

static int
virSecurityDACOpen(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED)
{
    return 0;
}

static int
208
virSecurityDACClose(virSecurityManagerPtr mgr)
209
{
210 211
    virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr);
    VIR_FREE(priv->groups);
212
    VIR_FREE(priv->baselabel);
213 214 215 216
    return 0;
}


O
Osier Yang 已提交
217 218
static const char *
virSecurityDACGetModel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED)
219
{
220
    return SECURITY_DAC_NAME;
221 222
}

O
Osier Yang 已提交
223 224
static const char *
virSecurityDACGetDOI(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED)
225 226 227 228
{
    return "0";
}

229 230 231 232 233 234 235 236 237 238 239 240 241 242 243
static int
virSecurityDACPreFork(virSecurityManagerPtr mgr)
{
    virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr);
    int ngroups;

    VIR_FREE(priv->groups);
    priv->ngroups = 0;
    if ((ngroups = virGetGroupList(priv->user, priv->group,
                                   &priv->groups)) < 0)
        return -1;
    priv->ngroups = ngroups;
    return 0;
}

244
static int
245
virSecurityDACSetOwnership(const char *path, uid_t uid, gid_t gid)
246
{
247 248
    VIR_INFO("Setting DAC user and group on '%s' to '%ld:%ld'",
             path, (long) uid, (long) gid);
249 250 251 252 253 254 255 256 257 258 259 260 261

    if (chown(path, uid, gid) < 0) {
        struct stat sb;
        int chown_errno = errno;

        if (stat(path, &sb) >= 0) {
            if (sb.st_uid == uid &&
                sb.st_gid == gid) {
                /* It's alright, there's nothing to change anyway. */
                return 0;
            }
        }

262
        if (chown_errno == EOPNOTSUPP || chown_errno == EINVAL) {
263 264 265
            VIR_INFO("Setting user and group to '%ld:%ld' on '%s' not "
                     "supported by filesystem",
                     (long) uid, (long) gid, path);
266
        } else if (chown_errno == EPERM) {
267 268 269
            VIR_INFO("Setting user and group to '%ld:%ld' on '%s' not "
                     "permitted",
                     (long) uid, (long) gid, path);
270
        } else if (chown_errno == EROFS) {
271 272 273
            VIR_INFO("Setting user and group to '%ld:%ld' on '%s' not "
                     "possible on readonly filesystem",
                     (long) uid, (long) gid, path);
274 275
        } else {
            virReportSystemError(chown_errno,
276 277 278
                                 _("unable to set user and group to '%ld:%ld' "
                                   "on '%s'"),
                                 (long) uid, (long) gid, path);
279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305
            return -1;
        }
    }
    return 0;
}

static int
virSecurityDACRestoreSecurityFileLabel(const char *path)
{
    struct stat buf;
    int rc = -1;
    char *newpath = NULL;

    VIR_INFO("Restoring DAC user and group on '%s'", path);

    if (virFileResolveLink(path, &newpath) < 0) {
        virReportSystemError(errno,
                             _("cannot resolve symlink %s"), path);
        goto err;
    }

    if (stat(newpath, &buf) != 0)
        goto err;

    /* XXX record previous ownership */
    rc = virSecurityDACSetOwnership(newpath, 0, 0);

306
 err:
307 308 309 310 311 312 313 314 315 316 317
    VIR_FREE(newpath);
    return rc;
}


static int
virSecurityDACSetSecurityFileLabel(virDomainDiskDefPtr disk ATTRIBUTE_UNUSED,
                                   const char *path,
                                   size_t depth ATTRIBUTE_UNUSED,
                                   void *opaque)
{
318 319 320
    void **params = opaque;
    virSecurityManagerPtr mgr = params[0];
    virDomainDefPtr def = params[1];
321
    virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr);
322 323 324 325 326
    uid_t user;
    gid_t group;

    if (virSecurityDACGetImageIds(def, priv, &user, &group))
        return -1;
327

328
    return virSecurityDACSetOwnership(path, user, group);
329 330 331 332 333
}


static int
virSecurityDACSetSecurityImageLabel(virSecurityManagerPtr mgr,
334
                                    virDomainDefPtr def,
335 336 337
                                    virDomainDiskDefPtr disk)

{
338
    void *params[2];
339 340 341 342 343
    virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr);

    if (!priv->dynamicOwnership)
        return 0;

E
Eric Blake 已提交
344
    if (virDomainDiskGetType(disk) == VIR_STORAGE_TYPE_NETWORK)
345 346
        return 0;

347 348
    params[0] = mgr;
    params[1] = def;
349 350 351
    return virDomainDiskDefForeachPath(disk,
                                       false,
                                       virSecurityDACSetSecurityFileLabel,
352
                                       params);
353 354 355 356 357
}


static int
virSecurityDACRestoreSecurityImageLabelInt(virSecurityManagerPtr mgr,
358
                                           virDomainDefPtr def ATTRIBUTE_UNUSED,
359 360 361 362
                                           virDomainDiskDefPtr disk,
                                           int migrated)
{
    virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr);
363
    const char *src = virDomainDiskGetSource(disk);
364 365 366 367

    if (!priv->dynamicOwnership)
        return 0;

E
Eric Blake 已提交
368
    if (virDomainDiskGetType(disk) == VIR_STORAGE_TYPE_NETWORK)
369 370
        return 0;

371 372 373 374 375 376 377 378 379 380 381
    /* 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;

382
    if (!src)
383 384 385 386 387 388 389 390
        return 0;

    /* 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) {
391
        int rc = virFileIsSharedFS(src);
392 393 394 395
        if (rc < 0)
            return -1;
        if (rc == 1) {
            VIR_DEBUG("Skipping image label restore on %s because FS is shared",
396
                      src);
397 398 399 400
            return 0;
        }
    }

401
    return virSecurityDACRestoreSecurityFileLabel(src);
402 403 404 405 406
}


static int
virSecurityDACRestoreSecurityImageLabel(virSecurityManagerPtr mgr,
407
                                        virDomainDefPtr def,
408 409
                                        virDomainDiskDefPtr disk)
{
410
    return virSecurityDACRestoreSecurityImageLabelInt(mgr, def, disk, 0);
411 412 413 414
}


static int
415 416
virSecurityDACSetSecurityHostdevLabelHelper(const char *file,
                                            void *opaque)
417
{
418 419 420
    void **params = opaque;
    virSecurityManagerPtr mgr = params[0];
    virDomainDefPtr def = params[1];
421
    virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr);
422 423
    uid_t user;
    gid_t group;
424

425
    if (virSecurityDACGetIds(def, priv, &user, &group, NULL, NULL))
426 427 428
        return -1;

    return virSecurityDACSetOwnership(file, user, group);
429 430 431
}


432 433 434 435 436 437 438 439 440
static int
virSecurityDACSetSecurityPCILabel(virPCIDevicePtr dev ATTRIBUTE_UNUSED,
                                  const char *file,
                                  void *opaque)
{
    return virSecurityDACSetSecurityHostdevLabelHelper(file, opaque);
}


441
static int
442
virSecurityDACSetSecurityUSBLabel(virUSBDevicePtr dev ATTRIBUTE_UNUSED,
443 444 445
                                  const char *file,
                                  void *opaque)
{
446 447
    return virSecurityDACSetSecurityHostdevLabelHelper(file, opaque);
}
448

449

450 451 452 453 454 455
static int
virSecurityDACSetSecuritySCSILabel(virSCSIDevicePtr dev ATTRIBUTE_UNUSED,
                                   const char *file,
                                   void *opaque)
{
    return virSecurityDACSetSecurityHostdevLabelHelper(file, opaque);
456 457 458 459 460
}


static int
virSecurityDACSetSecurityHostdevLabel(virSecurityManagerPtr mgr,
461
                                      virDomainDefPtr def,
462 463
                                      virDomainHostdevDefPtr dev,
                                      const char *vroot)
464
{
465
    void *params[] = {mgr, def};
466 467 468 469 470 471 472 473 474
    virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr);
    int ret = -1;

    if (!priv->dynamicOwnership)
        return 0;

    if (dev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
        return 0;

475
    switch ((enum virDomainHostdevSubsysType) dev->source.subsys.type) {
476
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB: {
477
        virUSBDevicePtr usb;
478

479 480 481
        if (dev->missing)
            return 0;

482 483 484
        usb = virUSBDeviceNew(dev->source.subsys.u.usb.bus,
                              dev->source.subsys.u.usb.device,
                              vroot);
485 486 487
        if (!usb)
            goto done;

488 489 490
        ret = virUSBDeviceFileIterate(usb, virSecurityDACSetSecurityUSBLabel,
                                      params);
        virUSBDeviceFree(usb);
491 492 493 494
        break;
    }

    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI: {
495
        virPCIDevicePtr pci =
496 497 498 499
            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);
500 501 502 503

        if (!pci)
            goto done;

504
        if (dev->source.subsys.u.pci.backend
505
            == VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO) {
506
            char *vfioGroupDev = virPCIDeviceGetIOMMUGroupDev(pci);
507

508 509
            if (!vfioGroupDev) {
                virPCIDeviceFree(pci);
510
                goto done;
511
            }
512 513 514 515 516 517 518
            ret = virSecurityDACSetSecurityPCILabel(pci, vfioGroupDev, params);
            VIR_FREE(vfioGroupDev);
        } else {
            ret = virPCIDeviceFileIterate(pci, virSecurityDACSetSecurityPCILabel,
                                          params);
        }

519
        virPCIDeviceFree(pci);
520 521 522
        break;
    }

523 524
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI: {
        virSCSIDevicePtr scsi =
525 526
            virSCSIDeviceNew(NULL,
                             dev->source.subsys.u.scsi.adapter,
527 528 529
                             dev->source.subsys.u.scsi.bus,
                             dev->source.subsys.u.scsi.target,
                             dev->source.subsys.u.scsi.unit,
530 531
                             dev->readonly,
                             dev->shareable);
532 533 534 535 536 537 538 539 540 541 542

        if (!scsi)
            goto done;

        ret = virSCSIDeviceFileIterate(scsi, virSecurityDACSetSecuritySCSILabel,
                                       params);
        virSCSIDeviceFree(scsi);

        break;
    }

543
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST:
544 545 546 547
        ret = 0;
        break;
    }

548
 done:
549 550 551 552 553
    return ret;
}


static int
554
virSecurityDACRestoreSecurityPCILabel(virPCIDevicePtr dev ATTRIBUTE_UNUSED,
555 556 557 558 559 560 561 562
                                      const char *file,
                                      void *opaque ATTRIBUTE_UNUSED)
{
    return virSecurityDACRestoreSecurityFileLabel(file);
}


static int
563 564 565
virSecurityDACRestoreSecurityUSBLabel(virUSBDevicePtr dev ATTRIBUTE_UNUSED,
                                      const char *file,
                                      void *opaque ATTRIBUTE_UNUSED)
566 567 568 569 570
{
    return virSecurityDACRestoreSecurityFileLabel(file);
}


571 572 573 574 575 576 577 578 579
static int
virSecurityDACRestoreSecuritySCSILabel(virSCSIDevicePtr dev ATTRIBUTE_UNUSED,
                                       const char *file,
                                       void *opaque ATTRIBUTE_UNUSED)
{
    return virSecurityDACRestoreSecurityFileLabel(file);
}


580 581
static int
virSecurityDACRestoreSecurityHostdevLabel(virSecurityManagerPtr mgr,
582 583 584
                                          virDomainDefPtr def ATTRIBUTE_UNUSED,
                                          virDomainHostdevDefPtr dev,
                                          const char *vroot)
585 586 587 588 589 590 591 592 593 594 595

{
    virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr);
    int ret = -1;

    if (!priv->dynamicOwnership)
        return 0;

    if (dev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
        return 0;

596
    switch ((enum virDomainHostdevSubsysType) dev->source.subsys.type) {
597
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB: {
598
        virUSBDevicePtr usb;
599 600 601

        if (dev->missing)
            return 0;
602

603 604 605
        usb = virUSBDeviceNew(dev->source.subsys.u.usb.bus,
                              dev->source.subsys.u.usb.device,
                              vroot);
606 607 608
        if (!usb)
            goto done;

609 610
        ret = virUSBDeviceFileIterate(usb, virSecurityDACRestoreSecurityUSBLabel, mgr);
        virUSBDeviceFree(usb);
611 612 613 614 615

        break;
    }

    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI: {
616
        virPCIDevicePtr pci =
617 618 619 620
            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);
621 622 623 624

        if (!pci)
            goto done;

625
        if (dev->source.subsys.u.pci.backend
626
            == VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO) {
627
            char *vfioGroupDev = virPCIDeviceGetIOMMUGroupDev(pci);
628

629 630
            if (!vfioGroupDev) {
                virPCIDeviceFree(pci);
631
                goto done;
632
            }
633 634 635 636 637
            ret = virSecurityDACRestoreSecurityPCILabel(pci, vfioGroupDev, mgr);
            VIR_FREE(vfioGroupDev);
        } else {
            ret = virPCIDeviceFileIterate(pci, virSecurityDACRestoreSecurityPCILabel, mgr);
        }
638
        virPCIDeviceFree(pci);
639 640 641
        break;
    }

642 643
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI: {
        virSCSIDevicePtr scsi =
644 645
            virSCSIDeviceNew(NULL,
                             dev->source.subsys.u.scsi.adapter,
646 647 648
                             dev->source.subsys.u.scsi.bus,
                             dev->source.subsys.u.scsi.target,
                             dev->source.subsys.u.scsi.unit,
649 650
                             dev->readonly,
                             dev->shareable);
651 652 653 654 655 656 657 658 659 660

        if (!scsi)
            goto done;

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

        break;
    }

661
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST:
662 663 664 665
        ret = 0;
        break;
    }

666
 done:
667 668 669 670 671 672
    return ret;
}


static int
virSecurityDACSetChardevLabel(virSecurityManagerPtr mgr,
673
                              virDomainDefPtr def,
674
                              virDomainChrSourceDefPtr dev)
675 676 677 678 679

{
    virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr);
    char *in = NULL, *out = NULL;
    int ret = -1;
680 681 682
    uid_t user;
    gid_t group;

683
    if (virSecurityDACGetIds(def, priv, &user, &group, NULL, NULL))
684
        return -1;
685

686
    switch ((enum virDomainChrType) dev->type) {
687 688
    case VIR_DOMAIN_CHR_TYPE_DEV:
    case VIR_DOMAIN_CHR_TYPE_FILE:
689
        ret = virSecurityDACSetOwnership(dev->data.file.path, user, group);
690 691 692
        break;

    case VIR_DOMAIN_CHR_TYPE_PIPE:
693
        if ((virAsprintf(&in, "%s.in", dev->data.file.path) < 0) ||
694
            (virAsprintf(&out, "%s.out", dev->data.file.path) < 0))
695 696
            goto done;
        if (virFileExists(in) && virFileExists(out)) {
697 698
            if ((virSecurityDACSetOwnership(in, user, group) < 0) ||
                (virSecurityDACSetOwnership(out, user, group) < 0)) {
699
                goto done;
700 701
            }
        } else if (virSecurityDACSetOwnership(dev->data.file.path,
702
                                              user, group) < 0) {
703
            goto done;
704 705 706 707
        }
        ret = 0;
        break;

708 709 710 711 712 713 714 715 716 717 718
    case VIR_DOMAIN_CHR_TYPE_SPICEPORT:
    case VIR_DOMAIN_CHR_TYPE_NULL:
    case VIR_DOMAIN_CHR_TYPE_VC:
    case VIR_DOMAIN_CHR_TYPE_PTY:
    case VIR_DOMAIN_CHR_TYPE_STDIO:
    case VIR_DOMAIN_CHR_TYPE_UDP:
    case VIR_DOMAIN_CHR_TYPE_TCP:
    case VIR_DOMAIN_CHR_TYPE_UNIX:
    case VIR_DOMAIN_CHR_TYPE_SPICEVMC:
    case VIR_DOMAIN_CHR_TYPE_NMDM:
    case VIR_DOMAIN_CHR_TYPE_LAST:
719 720 721 722
        ret = 0;
        break;
    }

723
 done:
724 725 726 727 728 729 730
    VIR_FREE(in);
    VIR_FREE(out);
    return ret;
}

static int
virSecurityDACRestoreChardevLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
731
                                  virDomainChrSourceDefPtr dev)
732 733 734 735
{
    char *in = NULL, *out = NULL;
    int ret = -1;

736
    switch ((enum virDomainChrType) dev->type) {
737 738 739 740 741 742 743
    case VIR_DOMAIN_CHR_TYPE_DEV:
    case VIR_DOMAIN_CHR_TYPE_FILE:
        ret = virSecurityDACRestoreSecurityFileLabel(dev->data.file.path);
        break;

    case VIR_DOMAIN_CHR_TYPE_PIPE:
        if ((virAsprintf(&out, "%s.out", dev->data.file.path) < 0) ||
744
            (virAsprintf(&in, "%s.in", dev->data.file.path) < 0))
745
            goto done;
746 747 748
        if (virFileExists(in) && virFileExists(out)) {
            if ((virSecurityDACRestoreSecurityFileLabel(out) < 0) ||
                (virSecurityDACRestoreSecurityFileLabel(in) < 0)) {
J
Jim Fehlig 已提交
749
                goto done;
750 751 752 753
            }
        } else if (virSecurityDACRestoreSecurityFileLabel(dev->data.file.path) < 0) {
            goto done;
        }
754 755 756
        ret = 0;
        break;

757 758 759 760 761 762 763 764 765 766 767
    case VIR_DOMAIN_CHR_TYPE_NULL:
    case VIR_DOMAIN_CHR_TYPE_VC:
    case VIR_DOMAIN_CHR_TYPE_PTY:
    case VIR_DOMAIN_CHR_TYPE_STDIO:
    case VIR_DOMAIN_CHR_TYPE_UDP:
    case VIR_DOMAIN_CHR_TYPE_TCP:
    case VIR_DOMAIN_CHR_TYPE_UNIX:
    case VIR_DOMAIN_CHR_TYPE_SPICEVMC:
    case VIR_DOMAIN_CHR_TYPE_SPICEPORT:
    case VIR_DOMAIN_CHR_TYPE_NMDM:
    case VIR_DOMAIN_CHR_TYPE_LAST:
768 769 770 771
        ret = 0;
        break;
    }

772
 done:
773 774 775 776 777 778 779 780 781 782 783 784 785
    VIR_FREE(in);
    VIR_FREE(out);
    return ret;
}


static int
virSecurityDACRestoreChardevCallback(virDomainDefPtr def ATTRIBUTE_UNUSED,
                                     virDomainChrDefPtr dev,
                                     void *opaque)
{
    virSecurityManagerPtr mgr = opaque;

786
    return virSecurityDACRestoreChardevLabel(mgr, &dev->source);
787 788 789
}


790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810
static int
virSecurityDACSetSecurityTPMFileLabel(virSecurityManagerPtr mgr,
                                      virDomainDefPtr def,
                                      virDomainTPMDefPtr tpm)
{
    int ret = 0;

    switch (tpm->type) {
    case VIR_DOMAIN_TPM_TYPE_PASSTHROUGH:
        ret = virSecurityDACSetChardevLabel(mgr, def,
                                            &tpm->data.passthrough.source);
        break;
    case VIR_DOMAIN_TPM_TYPE_LAST:
        break;
    }

    return ret;
}


static int
O
Osier Yang 已提交
811 812
virSecurityDACRestoreSecurityTPMFileLabel(virSecurityManagerPtr mgr,
                                          virDomainTPMDefPtr tpm)
813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828
{
    int ret = 0;

    switch (tpm->type) {
    case VIR_DOMAIN_TPM_TYPE_PASSTHROUGH:
        ret = virSecurityDACRestoreChardevLabel(mgr,
                                          &tpm->data.passthrough.source);
        break;
    case VIR_DOMAIN_TPM_TYPE_LAST:
        break;
    }

    return ret;
}


829 830
static int
virSecurityDACRestoreSecurityAllLabel(virSecurityManagerPtr mgr,
831
                                      virDomainDefPtr def,
832 833 834
                                      int migrated)
{
    virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr);
835
    size_t i;
836 837 838 839 840 841 842
    int rc = 0;

    if (!priv->dynamicOwnership)
        return 0;


    VIR_DEBUG("Restoring security label on %s migrated=%d",
843
              def->name, migrated);
844

845
    for (i = 0; i < def->nhostdevs; i++) {
846
        if (virSecurityDACRestoreSecurityHostdevLabel(mgr,
847
                                                      def,
848 849
                                                      def->hostdevs[i],
                                                      NULL) < 0)
850 851
            rc = -1;
    }
852
    for (i = 0; i < def->ndisks; i++) {
853
        if (virSecurityDACRestoreSecurityImageLabelInt(mgr,
854 855
                                                       def,
                                                       def->disks[i],
856 857 858 859
                                                       migrated) < 0)
            rc = -1;
    }

860
    if (virDomainChrDefForeach(def,
861 862
                               false,
                               virSecurityDACRestoreChardevCallback,
863
                               mgr) < 0)
864 865
        rc = -1;

866 867 868 869 870 871
    if (def->tpm) {
        if (virSecurityDACRestoreSecurityTPMFileLabel(mgr,
                                                      def->tpm) < 0)
            rc = -1;
    }

872 873
    if (def->os.kernel &&
        virSecurityDACRestoreSecurityFileLabel(def->os.kernel) < 0)
874 875
        rc = -1;

876 877
    if (def->os.initrd &&
        virSecurityDACRestoreSecurityFileLabel(def->os.initrd) < 0)
878 879
        rc = -1;

O
Olivia Yin 已提交
880 881 882 883
    if (def->os.dtb &&
        virSecurityDACRestoreSecurityFileLabel(def->os.dtb) < 0)
        rc = -1;

884 885 886 887 888
    return rc;
}


static int
889
virSecurityDACSetChardevCallback(virDomainDefPtr def,
890 891 892 893 894
                                 virDomainChrDefPtr dev,
                                 void *opaque)
{
    virSecurityManagerPtr mgr = opaque;

895
    return virSecurityDACSetChardevLabel(mgr, def, &dev->source);
896 897 898 899 900
}


static int
virSecurityDACSetSecurityAllLabel(virSecurityManagerPtr mgr,
901
                                  virDomainDefPtr def,
902 903 904
                                  const char *stdin_path ATTRIBUTE_UNUSED)
{
    virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr);
905
    size_t i;
906 907
    uid_t user;
    gid_t group;
908 909 910 911

    if (!priv->dynamicOwnership)
        return 0;

912
    for (i = 0; i < def->ndisks; i++) {
913
        /* XXX fixme - we need to recursively label the entire tree :-( */
E
Eric Blake 已提交
914
        if (virDomainDiskGetType(def->disks[i]) == VIR_STORAGE_TYPE_DIR)
915 916
            continue;
        if (virSecurityDACSetSecurityImageLabel(mgr,
917 918
                                                def,
                                                def->disks[i]) < 0)
919 920
            return -1;
    }
921
    for (i = 0; i < def->nhostdevs; i++) {
922
        if (virSecurityDACSetSecurityHostdevLabel(mgr,
923
                                                  def,
924 925
                                                  def->hostdevs[i],
                                                  NULL) < 0)
926 927 928
            return -1;
    }

929
    if (virDomainChrDefForeach(def,
930 931
                               true,
                               virSecurityDACSetChardevCallback,
932
                               mgr) < 0)
933 934
        return -1;

935 936 937 938 939 940 941
    if (def->tpm) {
        if (virSecurityDACSetSecurityTPMFileLabel(mgr,
                                                  def,
                                                  def->tpm) < 0)
            return -1;
    }

942 943 944
    if (virSecurityDACGetImageIds(def, priv, &user, &group))
        return -1;

945
    if (def->os.kernel &&
946
        virSecurityDACSetOwnership(def->os.kernel, user, group) < 0)
947 948
        return -1;

949
    if (def->os.initrd &&
950
        virSecurityDACSetOwnership(def->os.initrd, user, group) < 0)
951 952
        return -1;

O
Olivia Yin 已提交
953 954 955 956
    if (def->os.dtb &&
        virSecurityDACSetOwnership(def->os.dtb, user, group) < 0)
        return -1;

957 958 959 960 961 962
    return 0;
}


static int
virSecurityDACSetSavedStateLabel(virSecurityManagerPtr mgr,
963
                                 virDomainDefPtr def,
964 965
                                 const char *savefile)
{
966 967
    uid_t user;
    gid_t group;
968 969
    virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr);

970 971 972 973
    if (virSecurityDACGetImageIds(def, priv, &user, &group))
        return -1;

    return virSecurityDACSetOwnership(savefile, user, group);
974 975 976 977 978
}


static int
virSecurityDACRestoreSavedStateLabel(virSecurityManagerPtr mgr,
979
                                     virDomainDefPtr def ATTRIBUTE_UNUSED,
980 981 982 983 984 985 986 987 988 989 990 991 992
                                     const char *savefile)
{
    virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr);

    if (!priv->dynamicOwnership)
        return 0;

    return virSecurityDACRestoreSecurityFileLabel(savefile);
}


static int
virSecurityDACSetProcessLabel(virSecurityManagerPtr mgr,
993
                              virDomainDefPtr def)
994
{
995 996
    uid_t user;
    gid_t group;
997 998
    gid_t *groups;
    int ngroups;
999
    virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr);
1000

1001
    if (virSecurityDACGetIds(def, priv, &user, &group, &groups, &ngroups))
1002
        return -1;
1003

1004 1005
    VIR_DEBUG("Dropping privileges of DEF to %u:%u, %d supplemental groups",
              (unsigned int) user, (unsigned int) group, ngroups);
1006

1007
    if (virSetUIDGID(user, group, groups, ngroups) < 0)
1008 1009 1010
        return -1;

    return 0;
1011 1012 1013
}


1014 1015
static int
virSecurityDACSetChildProcessLabel(virSecurityManagerPtr mgr,
1016
                                   virDomainDefPtr def,
1017 1018 1019 1020 1021 1022
                                   virCommandPtr cmd)
{
    uid_t user;
    gid_t group;
    virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr);

1023
    if (virSecurityDACGetIds(def, priv, &user, &group, NULL, NULL))
1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034
        return -1;

    VIR_DEBUG("Setting child to drop privileges of DEF to %u:%u",
              (unsigned int) user, (unsigned int) group);

    virCommandSetUID(cmd, user);
    virCommandSetGID(cmd, group);
    return 0;
}


1035 1036 1037 1038 1039 1040 1041 1042
static int
virSecurityDACVerify(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
                     virDomainDefPtr def ATTRIBUTE_UNUSED)
{
    return 0;
}

static int
1043 1044
virSecurityDACGenLabel(virSecurityManagerPtr mgr,
                       virDomainDefPtr def)
1045
{
1046 1047 1048 1049 1050
    int rc = -1;
    virSecurityLabelDefPtr seclabel;
    virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr);

    seclabel = virDomainDefGetSecurityLabelDef(def, SECURITY_DAC_NAME);
1051
    if (seclabel == NULL)
1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069
        return rc;

    if (seclabel->imagelabel) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("security image label already "
                         "defined for VM"));
        return rc;
    }

    if (seclabel->model
        && STRNEQ(seclabel->model, SECURITY_DAC_NAME)) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("security label model %s is not supported "
                         "with selinux"),
                       seclabel->model);
            return rc;
    }

1070
    switch ((virDomainSeclabelType) seclabel->type) {
1071 1072 1073 1074 1075 1076 1077 1078 1079
    case VIR_DOMAIN_SECLABEL_STATIC:
        if (seclabel->label == NULL) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("missing label for static security "
                             "driver in domain %s"), def->name);
            return rc;
        }
        break;
    case VIR_DOMAIN_SECLABEL_DYNAMIC:
1080
        if (virAsprintf(&seclabel->label, "+%u:+%u",
1081
                        (unsigned int) priv->user,
1082
                        (unsigned int) priv->group) < 0)
1083 1084 1085 1086 1087 1088 1089 1090 1091 1092
            return rc;
        if (seclabel->label == NULL) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("cannot generate dac user and group id "
                             "for domain %s"), def->name);
            return rc;
        }
        break;
    case VIR_DOMAIN_SECLABEL_NONE:
        /* no op */
1093
        return 0;
1094 1095
    case VIR_DOMAIN_SECLABEL_DEFAULT:
    case VIR_DOMAIN_SECLABEL_LAST:
1096 1097 1098 1099 1100 1101
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected security label type '%s'"),
                       virDomainSeclabelTypeToString(seclabel->type));
        return rc;
    }

1102 1103 1104 1105
    if (!seclabel->norelabel && !seclabel->imagelabel &&
        VIR_STRDUP(seclabel->imagelabel, seclabel->label) < 0) {
        VIR_FREE(seclabel->label);
        return rc;
1106 1107
    }

1108 1109 1110 1111 1112
    return 0;
}

static int
virSecurityDACReleaseLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
1113
                           virDomainDefPtr def ATTRIBUTE_UNUSED)
1114 1115 1116 1117 1118 1119
{
    return 0;
}

static int
virSecurityDACReserveLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
1120 1121
                           virDomainDefPtr def ATTRIBUTE_UNUSED,
                           pid_t pid ATTRIBUTE_UNUSED)
1122 1123 1124 1125 1126 1127
{
    return 0;
}

static int
virSecurityDACGetProcessLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
1128
                              virDomainDefPtr def,
1129
                              pid_t pid ATTRIBUTE_UNUSED,
1130
                              virSecurityLabelPtr seclabel)
1131
{
1132 1133 1134 1135 1136 1137 1138
    virSecurityLabelDefPtr secdef =
        virDomainDefGetSecurityLabelDef(def, SECURITY_DAC_NAME);

    if (!secdef || !seclabel)
        return -1;

    if (secdef->label)
1139 1140
        ignore_value(virStrcpy(seclabel->label, secdef->label,
                               VIR_SECURITY_LABEL_BUFLEN));
1141

1142 1143 1144 1145
    return 0;
}

static int
1146
virSecurityDACSetDaemonSocketLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
1147
                                   virDomainDefPtr vm ATTRIBUTE_UNUSED)
1148 1149 1150 1151 1152
{
    return 0;
}


1153 1154
static int
virSecurityDACSetSocketLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
1155
                             virDomainDefPtr def ATTRIBUTE_UNUSED)
1156 1157 1158 1159 1160
{
    return 0;
}


1161 1162
static int
virSecurityDACClearSocketLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
1163
                               virDomainDefPtr def ATTRIBUTE_UNUSED)
1164 1165 1166 1167
{
    return 0;
}

1168
static int
1169
virSecurityDACSetImageFDLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
1170
                              virDomainDefPtr def ATTRIBUTE_UNUSED,
1171
                              int fd ATTRIBUTE_UNUSED)
1172 1173 1174 1175
{
    return 0;
}

1176 1177 1178 1179 1180 1181 1182 1183
static int
virSecurityDACSetTapFDLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
                            virDomainDefPtr def ATTRIBUTE_UNUSED,
                            int fd ATTRIBUTE_UNUSED)
{
    return 0;
}

O
Osier Yang 已提交
1184 1185 1186 1187
static char *
virSecurityDACGetMountOptions(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
                              virDomainDefPtr vm ATTRIBUTE_UNUSED)
{
1188 1189 1190
    return NULL;
}

1191 1192 1193 1194 1195 1196 1197 1198
static const char *
virSecurityDACGetBaseLabel(virSecurityManagerPtr mgr,
                           int virt ATTRIBUTE_UNUSED)
{
    virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr);
    return priv->baselabel;
}

1199
virSecurityDriver virSecurityDriverDAC = {
1200
    .privateDataLen                     = sizeof(virSecurityDACData),
1201
    .name                               = SECURITY_DAC_NAME,
1202 1203 1204
    .probe                              = virSecurityDACProbe,
    .open                               = virSecurityDACOpen,
    .close                              = virSecurityDACClose,
1205

1206 1207
    .getModel                           = virSecurityDACGetModel,
    .getDOI                             = virSecurityDACGetDOI,
1208

1209 1210
    .preFork                            = virSecurityDACPreFork,

1211
    .domainSecurityVerify               = virSecurityDACVerify,
1212

1213 1214
    .domainSetSecurityImageLabel        = virSecurityDACSetSecurityImageLabel,
    .domainRestoreSecurityImageLabel    = virSecurityDACRestoreSecurityImageLabel,
1215

1216 1217 1218
    .domainSetSecurityDaemonSocketLabel = virSecurityDACSetDaemonSocketLabel,
    .domainSetSecuritySocketLabel       = virSecurityDACSetSocketLabel,
    .domainClearSecuritySocketLabel     = virSecurityDACClearSocketLabel,
1219

1220 1221 1222
    .domainGenSecurityLabel             = virSecurityDACGenLabel,
    .domainReserveSecurityLabel         = virSecurityDACReserveLabel,
    .domainReleaseSecurityLabel         = virSecurityDACReleaseLabel,
1223

1224 1225
    .domainGetSecurityProcessLabel      = virSecurityDACGetProcessLabel,
    .domainSetSecurityProcessLabel      = virSecurityDACSetProcessLabel,
1226
    .domainSetSecurityChildProcessLabel = virSecurityDACSetChildProcessLabel,
1227

1228 1229
    .domainSetSecurityAllLabel          = virSecurityDACSetSecurityAllLabel,
    .domainRestoreSecurityAllLabel      = virSecurityDACRestoreSecurityAllLabel,
1230

1231 1232
    .domainSetSecurityHostdevLabel      = virSecurityDACSetSecurityHostdevLabel,
    .domainRestoreSecurityHostdevLabel  = virSecurityDACRestoreSecurityHostdevLabel,
1233

1234 1235
    .domainSetSavedStateLabel           = virSecurityDACSetSavedStateLabel,
    .domainRestoreSavedStateLabel       = virSecurityDACRestoreSavedStateLabel,
1236

1237
    .domainSetSecurityImageFDLabel      = virSecurityDACSetImageFDLabel,
1238
    .domainSetSecurityTapFDLabel        = virSecurityDACSetTapFDLabel,
1239

1240
    .domainGetSecurityMountOptions      = virSecurityDACGetMountOptions,
1241 1242

    .getBaseLabel                       = virSecurityDACGetBaseLabel,
1243
};