security_dac.c 35.1 KB
Newer Older
1
/*
2
 * Copyright (C) 2010-2013 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 320 321 322 323 324 325 326 327 328 329 330 331
            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);

err:
    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;

358 359 360
    if (disk->type == VIR_DOMAIN_DISK_TYPE_NETWORK)
        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 377 378 379 380
                                           virDomainDiskDefPtr disk,
                                           int migrated)
{
    virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr);

    if (!priv->dynamicOwnership)
        return 0;

381 382 383
    if (disk->type == VIR_DOMAIN_DISK_TYPE_NETWORK)
        return 0;

384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419
    /* 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;

    if (!disk->src)
        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) {
        int rc = virStorageFileIsSharedFS(disk->src);
        if (rc < 0)
            return -1;
        if (rc == 1) {
            VIR_DEBUG("Skipping image label restore on %s because FS is shared",
                      disk->src);
            return 0;
        }
    }

    return virSecurityDACRestoreSecurityFileLabel(disk->src);
}


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


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

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

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


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


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

462

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


static int
virSecurityDACSetSecurityHostdevLabel(virSecurityManagerPtr mgr,
474
                                      virDomainDefPtr def,
475 476
                                      virDomainHostdevDefPtr dev,
                                      const char *vroot)
477
{
478
    void *params[] = {mgr, def};
479 480 481 482 483 484 485 486 487 488 489
    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: {
490
        virUSBDevicePtr usb;
491

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

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

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

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

        if (!pci)
            goto done;

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

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

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

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

        if (!scsi)
            goto done;

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

        break;
    }

556 557 558 559 560 561 562 563 564 565 566
    default:
        ret = 0;
        break;
    }

done:
    return ret;
}


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


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


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


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

{
    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: {
611
        virUSBDevicePtr usb;
612 613 614

        if (dev->missing)
            return 0;
615

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

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

        break;
    }

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

        if (!pci)
            goto done;

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

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

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

        if (!scsi)
            goto done;

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

        break;
    }

674 675 676 677 678 679 680 681 682 683 684 685
    default:
        ret = 0;
        break;
    }

done:
    return ret;
}


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

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

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

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

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

    default:
        ret = 0;
        break;
    }

done:
    VIR_FREE(in);
    VIR_FREE(out);
    return ret;
}

static int
virSecurityDACRestoreChardevLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
734
                                  virDomainChrSourceDefPtr dev)
735 736 737 738 739 740 741 742 743 744 745 746
{
    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) ||
747
            (virAsprintf(&in, "%s.in", dev->data.file.path) < 0))
748
            goto done;
749 750 751
        if (virFileExists(in) && virFileExists(out)) {
            if ((virSecurityDACRestoreSecurityFileLabel(out) < 0) ||
                (virSecurityDACRestoreSecurityFileLabel(in) < 0)) {
752
            goto done;
753 754 755 756
            }
        } else if (virSecurityDACRestoreSecurityFileLabel(dev->data.file.path) < 0) {
            goto done;
        }
757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778
        ret = 0;
        break;

    default:
        ret = 0;
        break;
    }

done:
    VIR_FREE(in);
    VIR_FREE(out);
    return ret;
}


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

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


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


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

    if (!priv->dynamicOwnership)
        return 0;


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

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

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

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

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

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

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

877 878 879 880 881 882 883 884 885 886 887
    return rc;
}


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

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


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

    if (!priv->dynamicOwnership)
        return 0;

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

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

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

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

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

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

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

950 951 952 953 954 955
    return 0;
}


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

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

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


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

    if (!priv->dynamicOwnership)
        return 0;

    return virSecurityDACRestoreSecurityFileLabel(savefile);
}


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

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

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

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

    return 0;
1004 1005 1006
}


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

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


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

static int
1036 1037
virSecurityDACGenLabel(virSecurityManagerPtr mgr,
                       virDomainDefPtr def)
1038
{
1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063
    int rc = -1;
    virSecurityLabelDefPtr seclabel;
    virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr);

    seclabel = virDomainDefGetSecurityLabelDef(def, SECURITY_DAC_NAME);
    if (seclabel == NULL) {
        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 1122
                              virDomainDefPtr def ATTRIBUTE_UNUSED,
                              pid_t pid ATTRIBUTE_UNUSED,
1123 1124
                              virSecurityLabelPtr seclabel ATTRIBUTE_UNUSED)
{
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
};