security_dac.c 35.1 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 84
static int
virSecurityDACParseIds(virDomainDefPtr def, uid_t *uidPtr, gid_t *gidPtr)
85 86 87 88 89 90
{
    uid_t uid;
    gid_t gid;
    virSecurityLabelDefPtr seclabel;

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

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

M
Martin Kletzander 已提交
99
    if (virParseOwnershipIds(seclabel->label, &uid, &gid) < 0)
100 101 102 103 104 105 106 107 108 109
        return -1;

    if (uidPtr)
        *uidPtr = uid;
    if (gidPtr)
        *gidPtr = gid;

    return 0;
}

O
Osier Yang 已提交
110 111
static int
virSecurityDACGetIds(virDomainDefPtr def, virSecurityDACDataPtr priv,
112 113
                     uid_t *uidPtr, gid_t *gidPtr,
                     gid_t **groups, int *ngroups)
114
{
115 116 117 118 119 120 121
    int ret;

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

124 125 126 127 128 129
    if (groups)
        *groups = priv ? priv->groups : NULL;
    if (ngroups)
        *ngroups = priv ? priv->ngroups : 0;

    if ((ret = virSecurityDACParseIds(def, uidPtr, gidPtr)) <= 0)
130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
        return ret;

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

    if (uidPtr)
        *uidPtr = priv->user;
    if (gidPtr)
        *gidPtr = priv->group;

    return 0;
145 146
}

147 148

/* returns 1 if label isn't found, 0 on success, -1 on error */
O
Osier Yang 已提交
149 150 151
static int
virSecurityDACParseImageIds(virDomainDefPtr def,
                            uid_t *uidPtr, gid_t *gidPtr)
152 153 154 155 156 157
{
    uid_t uid;
    gid_t gid;
    virSecurityLabelDefPtr seclabel;

    if (def == NULL)
158
        return 1;
159 160

    seclabel = virDomainDefGetSecurityLabelDef(def, SECURITY_DAC_NAME);
161
    if (seclabel == NULL || seclabel->imagelabel == NULL) {
162 163
        VIR_DEBUG("DAC imagelabel for domain '%s' wasn't found", def->name);
        return 1;
164 165
    }

M
Martin Kletzander 已提交
166
    if (virParseOwnershipIds(seclabel->imagelabel, &uid, &gid) < 0)
167 168 169 170 171 172 173 174 175 176
        return -1;

    if (uidPtr)
        *uidPtr = uid;
    if (gidPtr)
        *gidPtr = gid;

    return 0;
}

O
Osier Yang 已提交
177 178 179
static int
virSecurityDACGetImageIds(virDomainDefPtr def, virSecurityDACDataPtr priv,
                          uid_t *uidPtr, gid_t *gidPtr)
180
{
181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197
    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;
198
    }
199 200 201 202 203 204 205

    if (uidPtr)
        *uidPtr = priv->user;
    if (gidPtr)
        *gidPtr = priv->group;

    return 0;
206 207 208
}


209
static virSecurityDriverStatus
210
virSecurityDACProbe(const char *virtDriver ATTRIBUTE_UNUSED)
211 212 213 214 215 216 217 218 219 220 221
{
    return SECURITY_DRIVER_ENABLE;
}

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

static int
222
virSecurityDACClose(virSecurityManagerPtr mgr)
223
{
224 225
    virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr);
    VIR_FREE(priv->groups);
226
    VIR_FREE(priv->baselabel);
227 228 229 230
    return 0;
}


O
Osier Yang 已提交
231 232
static const char *
virSecurityDACGetModel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED)
233
{
234
    return SECURITY_DAC_NAME;
235 236
}

O
Osier Yang 已提交
237 238
static const char *
virSecurityDACGetDOI(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED)
239 240 241 242
{
    return "0";
}

243 244 245 246 247 248 249 250 251 252 253 254 255 256 257
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;
}

258
static int
259
virSecurityDACSetOwnership(const char *path, uid_t uid, gid_t gid)
260
{
261 262
    VIR_INFO("Setting DAC user and group on '%s' to '%ld:%ld'",
             path, (long) uid, (long) gid);
263 264 265 266 267 268 269 270 271 272 273 274 275

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

276
        if (chown_errno == EOPNOTSUPP || chown_errno == EINVAL) {
277 278 279
            VIR_INFO("Setting user and group to '%ld:%ld' on '%s' not "
                     "supported by filesystem",
                     (long) uid, (long) gid, path);
280
        } else if (chown_errno == EPERM) {
281 282 283
            VIR_INFO("Setting user and group to '%ld:%ld' on '%s' not "
                     "permitted",
                     (long) uid, (long) gid, path);
284
        } else if (chown_errno == EROFS) {
285 286 287
            VIR_INFO("Setting user and group to '%ld:%ld' on '%s' not "
                     "possible on readonly filesystem",
                     (long) uid, (long) gid, path);
288 289
        } else {
            virReportSystemError(chown_errno,
290 291 292
                                 _("unable to set user and group to '%ld:%ld' "
                                   "on '%s'"),
                                 (long) uid, (long) gid, path);
293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319
            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);

320
 err:
321 322 323 324 325 326 327 328 329 330 331
    VIR_FREE(newpath);
    return rc;
}


static int
virSecurityDACSetSecurityFileLabel(virDomainDiskDefPtr disk ATTRIBUTE_UNUSED,
                                   const char *path,
                                   size_t depth ATTRIBUTE_UNUSED,
                                   void *opaque)
{
332 333 334
    void **params = opaque;
    virSecurityManagerPtr mgr = params[0];
    virDomainDefPtr def = params[1];
335
    virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr);
336 337 338 339 340
    uid_t user;
    gid_t group;

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

342
    return virSecurityDACSetOwnership(path, user, group);
343 344 345 346 347
}


static int
virSecurityDACSetSecurityImageLabel(virSecurityManagerPtr mgr,
348
                                    virDomainDefPtr def,
349 350 351
                                    virDomainDiskDefPtr disk)

{
352
    void *params[2];
353 354 355 356 357
    virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr);

    if (!priv->dynamicOwnership)
        return 0;

E
Eric Blake 已提交
358
    if (virDomainDiskGetType(disk) == VIR_STORAGE_TYPE_NETWORK)
359 360
        return 0;

361 362
    params[0] = mgr;
    params[1] = def;
363 364 365
    return virDomainDiskDefForeachPath(disk,
                                       false,
                                       virSecurityDACSetSecurityFileLabel,
366
                                       params);
367 368 369 370 371
}


static int
virSecurityDACRestoreSecurityImageLabelInt(virSecurityManagerPtr mgr,
372
                                           virDomainDefPtr def ATTRIBUTE_UNUSED,
373 374 375 376
                                           virDomainDiskDefPtr disk,
                                           int migrated)
{
    virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr);
377
    const char *src = virDomainDiskGetSource(disk);
378 379 380 381

    if (!priv->dynamicOwnership)
        return 0;

E
Eric Blake 已提交
382
    if (virDomainDiskGetType(disk) == VIR_STORAGE_TYPE_NETWORK)
383 384
        return 0;

385 386 387 388 389 390 391 392 393 394 395
    /* 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;

396
    if (!src)
397 398 399 400 401 402 403 404
        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) {
405
        int rc = virFileIsSharedFS(src);
406 407 408 409
        if (rc < 0)
            return -1;
        if (rc == 1) {
            VIR_DEBUG("Skipping image label restore on %s because FS is shared",
410
                      src);
411 412 413 414
            return 0;
        }
    }

415
    return virSecurityDACRestoreSecurityFileLabel(src);
416 417 418 419 420
}


static int
virSecurityDACRestoreSecurityImageLabel(virSecurityManagerPtr mgr,
421
                                        virDomainDefPtr def,
422 423
                                        virDomainDiskDefPtr disk)
{
424
    return virSecurityDACRestoreSecurityImageLabelInt(mgr, def, disk, 0);
425 426 427 428
}


static int
429 430
virSecurityDACSetSecurityHostdevLabelHelper(const char *file,
                                            void *opaque)
431
{
432 433 434
    void **params = opaque;
    virSecurityManagerPtr mgr = params[0];
    virDomainDefPtr def = params[1];
435
    virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr);
436 437
    uid_t user;
    gid_t group;
438

439
    if (virSecurityDACGetIds(def, priv, &user, &group, NULL, NULL))
440 441 442
        return -1;

    return virSecurityDACSetOwnership(file, user, group);
443 444 445
}


446 447 448 449 450 451 452 453 454
static int
virSecurityDACSetSecurityPCILabel(virPCIDevicePtr dev ATTRIBUTE_UNUSED,
                                  const char *file,
                                  void *opaque)
{
    return virSecurityDACSetSecurityHostdevLabelHelper(file, opaque);
}


455
static int
456
virSecurityDACSetSecurityUSBLabel(virUSBDevicePtr dev ATTRIBUTE_UNUSED,
457 458 459
                                  const char *file,
                                  void *opaque)
{
460 461
    return virSecurityDACSetSecurityHostdevLabelHelper(file, opaque);
}
462

463

464 465 466 467 468 469
static int
virSecurityDACSetSecuritySCSILabel(virSCSIDevicePtr dev ATTRIBUTE_UNUSED,
                                   const char *file,
                                   void *opaque)
{
    return virSecurityDACSetSecurityHostdevLabelHelper(file, opaque);
470 471 472 473 474
}


static int
virSecurityDACSetSecurityHostdevLabel(virSecurityManagerPtr mgr,
475
                                      virDomainDefPtr def,
476 477
                                      virDomainHostdevDefPtr dev,
                                      const char *vroot)
478
{
479
    void *params[] = {mgr, def};
480 481 482 483 484 485 486 487 488 489 490
    virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr);
    int ret = -1;

    if (!priv->dynamicOwnership)
        return 0;

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

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

493 494 495
        if (dev->missing)
            return 0;

496 497 498
        usb = virUSBDeviceNew(dev->source.subsys.u.usb.bus,
                              dev->source.subsys.u.usb.device,
                              vroot);
499 500 501
        if (!usb)
            goto done;

502 503 504
        ret = virUSBDeviceFileIterate(usb, virSecurityDACSetSecurityUSBLabel,
                                      params);
        virUSBDeviceFree(usb);
505 506 507 508
        break;
    }

    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI: {
509
        virPCIDevicePtr pci =
510 511 512 513
            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);
514 515 516 517

        if (!pci)
            goto done;

518
        if (dev->source.subsys.u.pci.backend
519
            == VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO) {
520
            char *vfioGroupDev = virPCIDeviceGetIOMMUGroupDev(pci);
521

522 523
            if (!vfioGroupDev) {
                virPCIDeviceFree(pci);
524
                goto done;
525
            }
526 527 528 529 530 531 532
            ret = virSecurityDACSetSecurityPCILabel(pci, vfioGroupDev, params);
            VIR_FREE(vfioGroupDev);
        } else {
            ret = virPCIDeviceFileIterate(pci, virSecurityDACSetSecurityPCILabel,
                                          params);
        }

533
        virPCIDeviceFree(pci);
534 535 536
        break;
    }

537 538
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI: {
        virSCSIDevicePtr scsi =
539 540
            virSCSIDeviceNew(NULL,
                             dev->source.subsys.u.scsi.adapter,
541 542 543
                             dev->source.subsys.u.scsi.bus,
                             dev->source.subsys.u.scsi.target,
                             dev->source.subsys.u.scsi.unit,
544 545
                             dev->readonly,
                             dev->shareable);
546 547 548 549 550 551 552 553 554 555 556

        if (!scsi)
            goto done;

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

        break;
    }

557 558 559 560 561
    default:
        ret = 0;
        break;
    }

562
 done:
563 564 565 566 567
    return ret;
}


static int
568
virSecurityDACRestoreSecurityPCILabel(virPCIDevicePtr dev ATTRIBUTE_UNUSED,
569 570 571 572 573 574 575 576
                                      const char *file,
                                      void *opaque ATTRIBUTE_UNUSED)
{
    return virSecurityDACRestoreSecurityFileLabel(file);
}


static int
577 578 579
virSecurityDACRestoreSecurityUSBLabel(virUSBDevicePtr dev ATTRIBUTE_UNUSED,
                                      const char *file,
                                      void *opaque ATTRIBUTE_UNUSED)
580 581 582 583 584
{
    return virSecurityDACRestoreSecurityFileLabel(file);
}


585 586 587 588 589 590 591 592 593
static int
virSecurityDACRestoreSecuritySCSILabel(virSCSIDevicePtr dev ATTRIBUTE_UNUSED,
                                       const char *file,
                                       void *opaque ATTRIBUTE_UNUSED)
{
    return virSecurityDACRestoreSecurityFileLabel(file);
}


594 595
static int
virSecurityDACRestoreSecurityHostdevLabel(virSecurityManagerPtr mgr,
596 597 598
                                          virDomainDefPtr def ATTRIBUTE_UNUSED,
                                          virDomainHostdevDefPtr dev,
                                          const char *vroot)
599 600 601 602 603 604 605 606 607 608 609 610 611

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

    if (!priv->dynamicOwnership)
        return 0;

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

    switch (dev->source.subsys.type) {
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB: {
612
        virUSBDevicePtr usb;
613 614 615

        if (dev->missing)
            return 0;
616

617 618 619
        usb = virUSBDeviceNew(dev->source.subsys.u.usb.bus,
                              dev->source.subsys.u.usb.device,
                              vroot);
620 621 622
        if (!usb)
            goto done;

623 624
        ret = virUSBDeviceFileIterate(usb, virSecurityDACRestoreSecurityUSBLabel, mgr);
        virUSBDeviceFree(usb);
625 626 627 628 629

        break;
    }

    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI: {
630
        virPCIDevicePtr pci =
631 632 633 634
            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);
635 636 637 638

        if (!pci)
            goto done;

639
        if (dev->source.subsys.u.pci.backend
640
            == VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO) {
641
            char *vfioGroupDev = virPCIDeviceGetIOMMUGroupDev(pci);
642

643 644
            if (!vfioGroupDev) {
                virPCIDeviceFree(pci);
645
                goto done;
646
            }
647 648 649 650 651
            ret = virSecurityDACRestoreSecurityPCILabel(pci, vfioGroupDev, mgr);
            VIR_FREE(vfioGroupDev);
        } else {
            ret = virPCIDeviceFileIterate(pci, virSecurityDACRestoreSecurityPCILabel, mgr);
        }
652
        virPCIDeviceFree(pci);
653 654 655
        break;
    }

656 657
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI: {
        virSCSIDevicePtr scsi =
658 659
            virSCSIDeviceNew(NULL,
                             dev->source.subsys.u.scsi.adapter,
660 661 662
                             dev->source.subsys.u.scsi.bus,
                             dev->source.subsys.u.scsi.target,
                             dev->source.subsys.u.scsi.unit,
663 664
                             dev->readonly,
                             dev->shareable);
665 666 667 668 669 670 671 672 673 674

        if (!scsi)
            goto done;

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

        break;
    }

675 676 677 678 679
    default:
        ret = 0;
        break;
    }

680
 done:
681 682 683 684 685 686
    return ret;
}


static int
virSecurityDACSetChardevLabel(virSecurityManagerPtr mgr,
687
                              virDomainDefPtr def,
688
                              virDomainChrSourceDefPtr dev)
689 690 691 692 693

{
    virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr);
    char *in = NULL, *out = NULL;
    int ret = -1;
694 695 696
    uid_t user;
    gid_t group;

697
    if (virSecurityDACGetIds(def, priv, &user, &group, NULL, NULL))
698
        return -1;
699 700 701 702

    switch (dev->type) {
    case VIR_DOMAIN_CHR_TYPE_DEV:
    case VIR_DOMAIN_CHR_TYPE_FILE:
703
        ret = virSecurityDACSetOwnership(dev->data.file.path, user, group);
704 705 706
        break;

    case VIR_DOMAIN_CHR_TYPE_PIPE:
707
        if ((virAsprintf(&in, "%s.in", dev->data.file.path) < 0) ||
708
            (virAsprintf(&out, "%s.out", dev->data.file.path) < 0))
709 710
            goto done;
        if (virFileExists(in) && virFileExists(out)) {
711 712
            if ((virSecurityDACSetOwnership(in, user, group) < 0) ||
                (virSecurityDACSetOwnership(out, user, group) < 0)) {
713
                goto done;
714 715
            }
        } else if (virSecurityDACSetOwnership(dev->data.file.path,
716
                                              user, group) < 0) {
717
            goto done;
718 719 720 721 722 723 724 725 726
        }
        ret = 0;
        break;

    default:
        ret = 0;
        break;
    }

727
 done:
728 729 730 731 732 733 734
    VIR_FREE(in);
    VIR_FREE(out);
    return ret;
}

static int
virSecurityDACRestoreChardevLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
735
                                  virDomainChrSourceDefPtr dev)
736 737 738 739 740 741 742 743 744 745 746 747
{
    char *in = NULL, *out = NULL;
    int ret = -1;

    switch (dev->type) {
    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) ||
748
            (virAsprintf(&in, "%s.in", dev->data.file.path) < 0))
749
            goto done;
750 751 752
        if (virFileExists(in) && virFileExists(out)) {
            if ((virSecurityDACRestoreSecurityFileLabel(out) < 0) ||
                (virSecurityDACRestoreSecurityFileLabel(in) < 0)) {
J
Jim Fehlig 已提交
753
                goto done;
754 755 756 757
            }
        } else if (virSecurityDACRestoreSecurityFileLabel(dev->data.file.path) < 0) {
            goto done;
        }
758 759 760 761 762 763 764 765
        ret = 0;
        break;

    default:
        ret = 0;
        break;
    }

766
 done:
767 768 769 770 771 772 773 774 775 776 777 778 779
    VIR_FREE(in);
    VIR_FREE(out);
    return ret;
}


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

780
    return virSecurityDACRestoreChardevLabel(mgr, &dev->source);
781 782 783
}


784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804
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 已提交
805 806
virSecurityDACRestoreSecurityTPMFileLabel(virSecurityManagerPtr mgr,
                                          virDomainTPMDefPtr tpm)
807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822
{
    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;
}


823 824
static int
virSecurityDACRestoreSecurityAllLabel(virSecurityManagerPtr mgr,
825
                                      virDomainDefPtr def,
826 827 828
                                      int migrated)
{
    virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr);
829
    size_t i;
830 831 832 833 834 835 836
    int rc = 0;

    if (!priv->dynamicOwnership)
        return 0;


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

839
    for (i = 0; i < def->nhostdevs; i++) {
840
        if (virSecurityDACRestoreSecurityHostdevLabel(mgr,
841
                                                      def,
842 843
                                                      def->hostdevs[i],
                                                      NULL) < 0)
844 845
            rc = -1;
    }
846
    for (i = 0; i < def->ndisks; i++) {
847
        if (virSecurityDACRestoreSecurityImageLabelInt(mgr,
848 849
                                                       def,
                                                       def->disks[i],
850 851 852 853
                                                       migrated) < 0)
            rc = -1;
    }

854
    if (virDomainChrDefForeach(def,
855 856
                               false,
                               virSecurityDACRestoreChardevCallback,
857
                               mgr) < 0)
858 859
        rc = -1;

860 861 862 863 864 865
    if (def->tpm) {
        if (virSecurityDACRestoreSecurityTPMFileLabel(mgr,
                                                      def->tpm) < 0)
            rc = -1;
    }

866 867
    if (def->os.kernel &&
        virSecurityDACRestoreSecurityFileLabel(def->os.kernel) < 0)
868 869
        rc = -1;

870 871
    if (def->os.initrd &&
        virSecurityDACRestoreSecurityFileLabel(def->os.initrd) < 0)
872 873
        rc = -1;

O
Olivia Yin 已提交
874 875 876 877
    if (def->os.dtb &&
        virSecurityDACRestoreSecurityFileLabel(def->os.dtb) < 0)
        rc = -1;

878 879 880 881 882
    return rc;
}


static int
883
virSecurityDACSetChardevCallback(virDomainDefPtr def,
884 885 886 887 888
                                 virDomainChrDefPtr dev,
                                 void *opaque)
{
    virSecurityManagerPtr mgr = opaque;

889
    return virSecurityDACSetChardevLabel(mgr, def, &dev->source);
890 891 892 893 894
}


static int
virSecurityDACSetSecurityAllLabel(virSecurityManagerPtr mgr,
895
                                  virDomainDefPtr def,
896 897 898
                                  const char *stdin_path ATTRIBUTE_UNUSED)
{
    virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr);
899
    size_t i;
900 901
    uid_t user;
    gid_t group;
902 903 904 905

    if (!priv->dynamicOwnership)
        return 0;

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

923
    if (virDomainChrDefForeach(def,
924 925
                               true,
                               virSecurityDACSetChardevCallback,
926
                               mgr) < 0)
927 928
        return -1;

929 930 931 932 933 934 935
    if (def->tpm) {
        if (virSecurityDACSetSecurityTPMFileLabel(mgr,
                                                  def,
                                                  def->tpm) < 0)
            return -1;
    }

936 937 938
    if (virSecurityDACGetImageIds(def, priv, &user, &group))
        return -1;

939
    if (def->os.kernel &&
940
        virSecurityDACSetOwnership(def->os.kernel, user, group) < 0)
941 942
        return -1;

943
    if (def->os.initrd &&
944
        virSecurityDACSetOwnership(def->os.initrd, user, group) < 0)
945 946
        return -1;

O
Olivia Yin 已提交
947 948 949 950
    if (def->os.dtb &&
        virSecurityDACSetOwnership(def->os.dtb, user, group) < 0)
        return -1;

951 952 953 954 955 956
    return 0;
}


static int
virSecurityDACSetSavedStateLabel(virSecurityManagerPtr mgr,
957
                                 virDomainDefPtr def,
958 959
                                 const char *savefile)
{
960 961
    uid_t user;
    gid_t group;
962 963
    virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr);

964 965 966 967
    if (virSecurityDACGetImageIds(def, priv, &user, &group))
        return -1;

    return virSecurityDACSetOwnership(savefile, user, group);
968 969 970 971 972
}


static int
virSecurityDACRestoreSavedStateLabel(virSecurityManagerPtr mgr,
973
                                     virDomainDefPtr def ATTRIBUTE_UNUSED,
974 975 976 977 978 979 980 981 982 983 984 985 986
                                     const char *savefile)
{
    virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr);

    if (!priv->dynamicOwnership)
        return 0;

    return virSecurityDACRestoreSecurityFileLabel(savefile);
}


static int
virSecurityDACSetProcessLabel(virSecurityManagerPtr mgr,
987
                              virDomainDefPtr def)
988
{
989 990
    uid_t user;
    gid_t group;
991 992
    gid_t *groups;
    int ngroups;
993
    virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr);
994

995
    if (virSecurityDACGetIds(def, priv, &user, &group, &groups, &ngroups))
996
        return -1;
997

998 999
    VIR_DEBUG("Dropping privileges of DEF to %u:%u, %d supplemental groups",
              (unsigned int) user, (unsigned int) group, ngroups);
1000

1001
    if (virSetUIDGID(user, group, groups, ngroups) < 0)
1002 1003 1004
        return -1;

    return 0;
1005 1006 1007
}


1008 1009
static int
virSecurityDACSetChildProcessLabel(virSecurityManagerPtr mgr,
1010
                                   virDomainDefPtr def,
1011 1012 1013 1014 1015 1016
                                   virCommandPtr cmd)
{
    uid_t user;
    gid_t group;
    virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr);

1017
    if (virSecurityDACGetIds(def, priv, &user, &group, NULL, NULL))
1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028
        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;
}


1029 1030 1031 1032 1033 1034 1035 1036
static int
virSecurityDACVerify(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
                     virDomainDefPtr def ATTRIBUTE_UNUSED)
{
    return 0;
}

static int
1037 1038
virSecurityDACGenLabel(virSecurityManagerPtr mgr,
                       virDomainDefPtr def)
1039
{
1040 1041 1042 1043 1044
    int rc = -1;
    virSecurityLabelDefPtr seclabel;
    virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr);

    seclabel = virDomainDefGetSecurityLabelDef(def, SECURITY_DAC_NAME);
1045
    if (seclabel == NULL)
1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063
        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;
    }

1064
    switch (seclabel->type) {
1065 1066 1067 1068 1069 1070 1071 1072 1073
    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:
1074
        if (virAsprintf(&seclabel->label, "+%u:+%u",
1075
                        (unsigned int) priv->user,
1076
                        (unsigned int) priv->group) < 0)
1077 1078 1079 1080 1081 1082 1083 1084 1085 1086
            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 */
1087
        return 0;
1088 1089 1090 1091 1092 1093 1094
    default:
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected security label type '%s'"),
                       virDomainSeclabelTypeToString(seclabel->type));
        return rc;
    }

1095 1096 1097 1098
    if (!seclabel->norelabel && !seclabel->imagelabel &&
        VIR_STRDUP(seclabel->imagelabel, seclabel->label) < 0) {
        VIR_FREE(seclabel->label);
        return rc;
1099 1100
    }

1101 1102 1103 1104 1105
    return 0;
}

static int
virSecurityDACReleaseLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
1106
                           virDomainDefPtr def ATTRIBUTE_UNUSED)
1107 1108 1109 1110 1111 1112
{
    return 0;
}

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

static int
virSecurityDACGetProcessLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
1121
                              virDomainDefPtr def,
1122
                              pid_t pid ATTRIBUTE_UNUSED,
1123
                              virSecurityLabelPtr seclabel)
1124
{
1125 1126 1127 1128 1129 1130 1131
    virSecurityLabelDefPtr secdef =
        virDomainDefGetSecurityLabelDef(def, SECURITY_DAC_NAME);

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

    if (secdef->label)
1132 1133
        ignore_value(virStrcpy(seclabel->label, secdef->label,
                               VIR_SECURITY_LABEL_BUFLEN));
1134

1135 1136 1137 1138
    return 0;
}

static int
1139
virSecurityDACSetDaemonSocketLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
1140
                                   virDomainDefPtr vm ATTRIBUTE_UNUSED)
1141 1142 1143 1144 1145
{
    return 0;
}


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


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

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

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

O
Osier Yang 已提交
1177 1178 1179 1180
static char *
virSecurityDACGetMountOptions(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
                              virDomainDefPtr vm ATTRIBUTE_UNUSED)
{
1181 1182 1183
    return NULL;
}

1184 1185 1186 1187 1188 1189 1190 1191
static const char *
virSecurityDACGetBaseLabel(virSecurityManagerPtr mgr,
                           int virt ATTRIBUTE_UNUSED)
{
    virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr);
    return priv->baselabel;
}

1192
virSecurityDriver virSecurityDriverDAC = {
1193
    .privateDataLen                     = sizeof(virSecurityDACData),
1194
    .name                               = SECURITY_DAC_NAME,
1195 1196 1197
    .probe                              = virSecurityDACProbe,
    .open                               = virSecurityDACOpen,
    .close                              = virSecurityDACClose,
1198

1199 1200
    .getModel                           = virSecurityDACGetModel,
    .getDOI                             = virSecurityDACGetDOI,
1201

1202 1203
    .preFork                            = virSecurityDACPreFork,

1204
    .domainSecurityVerify               = virSecurityDACVerify,
1205

1206 1207
    .domainSetSecurityImageLabel        = virSecurityDACSetSecurityImageLabel,
    .domainRestoreSecurityImageLabel    = virSecurityDACRestoreSecurityImageLabel,
1208

1209 1210 1211
    .domainSetSecurityDaemonSocketLabel = virSecurityDACSetDaemonSocketLabel,
    .domainSetSecuritySocketLabel       = virSecurityDACSetSocketLabel,
    .domainClearSecuritySocketLabel     = virSecurityDACClearSocketLabel,
1212

1213 1214 1215
    .domainGenSecurityLabel             = virSecurityDACGenLabel,
    .domainReserveSecurityLabel         = virSecurityDACReserveLabel,
    .domainReleaseSecurityLabel         = virSecurityDACReleaseLabel,
1216

1217 1218
    .domainGetSecurityProcessLabel      = virSecurityDACGetProcessLabel,
    .domainSetSecurityProcessLabel      = virSecurityDACSetProcessLabel,
1219
    .domainSetSecurityChildProcessLabel = virSecurityDACSetChildProcessLabel,
1220

1221 1222
    .domainSetSecurityAllLabel          = virSecurityDACSetSecurityAllLabel,
    .domainRestoreSecurityAllLabel      = virSecurityDACRestoreSecurityAllLabel,
1223

1224 1225
    .domainSetSecurityHostdevLabel      = virSecurityDACSetSecurityHostdevLabel,
    .domainRestoreSecurityHostdevLabel  = virSecurityDACRestoreSecurityHostdevLabel,
1226

1227 1228
    .domainSetSavedStateLabel           = virSecurityDACSetSavedStateLabel,
    .domainRestoreSavedStateLabel       = virSecurityDACRestoreSavedStateLabel,
1229

1230
    .domainSetSecurityImageFDLabel      = virSecurityDACSetImageFDLabel,
1231
    .domainSetSecurityTapFDLabel        = virSecurityDACSetTapFDLabel,
1232

1233
    .domainGetSecurityMountOptions      = virSecurityDACGetMountOptions,
1234 1235

    .getBaseLabel                       = virSecurityDACGetBaseLabel,
1236
};