security_dac.c 35.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 475 476
    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: {
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 544 545 546 547
    default:
        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 596 597

{
    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: {
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 662 663 664 665
    default:
        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 687 688

    switch (dev->type) {
    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 708 709 710 711 712
        }
        ret = 0;
        break;

    default:
        ret = 0;
        break;
    }

713
 done:
714 715 716 717 718 719 720
    VIR_FREE(in);
    VIR_FREE(out);
    return ret;
}

static int
virSecurityDACRestoreChardevLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
721
                                  virDomainChrSourceDefPtr dev)
722 723 724 725 726 727 728 729 730 731 732 733
{
    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) ||
734
            (virAsprintf(&in, "%s.in", dev->data.file.path) < 0))
735
            goto done;
736 737 738
        if (virFileExists(in) && virFileExists(out)) {
            if ((virSecurityDACRestoreSecurityFileLabel(out) < 0) ||
                (virSecurityDACRestoreSecurityFileLabel(in) < 0)) {
J
Jim Fehlig 已提交
739
                goto done;
740 741 742 743
            }
        } else if (virSecurityDACRestoreSecurityFileLabel(dev->data.file.path) < 0) {
            goto done;
        }
744 745 746 747 748 749 750 751
        ret = 0;
        break;

    default:
        ret = 0;
        break;
    }

752
 done:
753 754 755 756 757 758 759 760 761 762 763 764 765
    VIR_FREE(in);
    VIR_FREE(out);
    return ret;
}


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

766
    return virSecurityDACRestoreChardevLabel(mgr, &dev->source);
767 768 769
}


770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790
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 已提交
791 792
virSecurityDACRestoreSecurityTPMFileLabel(virSecurityManagerPtr mgr,
                                          virDomainTPMDefPtr tpm)
793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808
{
    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;
}


809 810
static int
virSecurityDACRestoreSecurityAllLabel(virSecurityManagerPtr mgr,
811
                                      virDomainDefPtr def,
812 813 814
                                      int migrated)
{
    virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr);
815
    size_t i;
816 817 818 819 820 821 822
    int rc = 0;

    if (!priv->dynamicOwnership)
        return 0;


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

825
    for (i = 0; i < def->nhostdevs; i++) {
826
        if (virSecurityDACRestoreSecurityHostdevLabel(mgr,
827
                                                      def,
828 829
                                                      def->hostdevs[i],
                                                      NULL) < 0)
830 831
            rc = -1;
    }
832
    for (i = 0; i < def->ndisks; i++) {
833
        if (virSecurityDACRestoreSecurityImageLabelInt(mgr,
834 835
                                                       def,
                                                       def->disks[i],
836 837 838 839
                                                       migrated) < 0)
            rc = -1;
    }

840
    if (virDomainChrDefForeach(def,
841 842
                               false,
                               virSecurityDACRestoreChardevCallback,
843
                               mgr) < 0)
844 845
        rc = -1;

846 847 848 849 850 851
    if (def->tpm) {
        if (virSecurityDACRestoreSecurityTPMFileLabel(mgr,
                                                      def->tpm) < 0)
            rc = -1;
    }

852 853
    if (def->os.kernel &&
        virSecurityDACRestoreSecurityFileLabel(def->os.kernel) < 0)
854 855
        rc = -1;

856 857
    if (def->os.initrd &&
        virSecurityDACRestoreSecurityFileLabel(def->os.initrd) < 0)
858 859
        rc = -1;

O
Olivia Yin 已提交
860 861 862 863
    if (def->os.dtb &&
        virSecurityDACRestoreSecurityFileLabel(def->os.dtb) < 0)
        rc = -1;

864 865 866 867 868
    return rc;
}


static int
869
virSecurityDACSetChardevCallback(virDomainDefPtr def,
870 871 872 873 874
                                 virDomainChrDefPtr dev,
                                 void *opaque)
{
    virSecurityManagerPtr mgr = opaque;

875
    return virSecurityDACSetChardevLabel(mgr, def, &dev->source);
876 877 878 879 880
}


static int
virSecurityDACSetSecurityAllLabel(virSecurityManagerPtr mgr,
881
                                  virDomainDefPtr def,
882 883 884
                                  const char *stdin_path ATTRIBUTE_UNUSED)
{
    virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr);
885
    size_t i;
886 887
    uid_t user;
    gid_t group;
888 889 890 891

    if (!priv->dynamicOwnership)
        return 0;

892
    for (i = 0; i < def->ndisks; i++) {
893
        /* XXX fixme - we need to recursively label the entire tree :-( */
E
Eric Blake 已提交
894
        if (virDomainDiskGetType(def->disks[i]) == VIR_STORAGE_TYPE_DIR)
895 896
            continue;
        if (virSecurityDACSetSecurityImageLabel(mgr,
897 898
                                                def,
                                                def->disks[i]) < 0)
899 900
            return -1;
    }
901
    for (i = 0; i < def->nhostdevs; i++) {
902
        if (virSecurityDACSetSecurityHostdevLabel(mgr,
903
                                                  def,
904 905
                                                  def->hostdevs[i],
                                                  NULL) < 0)
906 907 908
            return -1;
    }

909
    if (virDomainChrDefForeach(def,
910 911
                               true,
                               virSecurityDACSetChardevCallback,
912
                               mgr) < 0)
913 914
        return -1;

915 916 917 918 919 920 921
    if (def->tpm) {
        if (virSecurityDACSetSecurityTPMFileLabel(mgr,
                                                  def,
                                                  def->tpm) < 0)
            return -1;
    }

922 923 924
    if (virSecurityDACGetImageIds(def, priv, &user, &group))
        return -1;

925
    if (def->os.kernel &&
926
        virSecurityDACSetOwnership(def->os.kernel, user, group) < 0)
927 928
        return -1;

929
    if (def->os.initrd &&
930
        virSecurityDACSetOwnership(def->os.initrd, user, group) < 0)
931 932
        return -1;

O
Olivia Yin 已提交
933 934 935 936
    if (def->os.dtb &&
        virSecurityDACSetOwnership(def->os.dtb, user, group) < 0)
        return -1;

937 938 939 940 941 942
    return 0;
}


static int
virSecurityDACSetSavedStateLabel(virSecurityManagerPtr mgr,
943
                                 virDomainDefPtr def,
944 945
                                 const char *savefile)
{
946 947
    uid_t user;
    gid_t group;
948 949
    virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr);

950 951 952 953
    if (virSecurityDACGetImageIds(def, priv, &user, &group))
        return -1;

    return virSecurityDACSetOwnership(savefile, user, group);
954 955 956 957 958
}


static int
virSecurityDACRestoreSavedStateLabel(virSecurityManagerPtr mgr,
959
                                     virDomainDefPtr def ATTRIBUTE_UNUSED,
960 961 962 963 964 965 966 967 968 969 970 971 972
                                     const char *savefile)
{
    virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr);

    if (!priv->dynamicOwnership)
        return 0;

    return virSecurityDACRestoreSecurityFileLabel(savefile);
}


static int
virSecurityDACSetProcessLabel(virSecurityManagerPtr mgr,
973
                              virDomainDefPtr def)
974
{
975 976
    uid_t user;
    gid_t group;
977 978
    gid_t *groups;
    int ngroups;
979
    virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr);
980

981
    if (virSecurityDACGetIds(def, priv, &user, &group, &groups, &ngroups))
982
        return -1;
983

984 985
    VIR_DEBUG("Dropping privileges of DEF to %u:%u, %d supplemental groups",
              (unsigned int) user, (unsigned int) group, ngroups);
986

987
    if (virSetUIDGID(user, group, groups, ngroups) < 0)
988 989 990
        return -1;

    return 0;
991 992 993
}


994 995
static int
virSecurityDACSetChildProcessLabel(virSecurityManagerPtr mgr,
996
                                   virDomainDefPtr def,
997 998 999 1000 1001 1002
                                   virCommandPtr cmd)
{
    uid_t user;
    gid_t group;
    virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr);

1003
    if (virSecurityDACGetIds(def, priv, &user, &group, NULL, NULL))
1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014
        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;
}


1015 1016 1017 1018 1019 1020 1021 1022
static int
virSecurityDACVerify(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
                     virDomainDefPtr def ATTRIBUTE_UNUSED)
{
    return 0;
}

static int
1023 1024
virSecurityDACGenLabel(virSecurityManagerPtr mgr,
                       virDomainDefPtr def)
1025
{
1026 1027 1028 1029 1030
    int rc = -1;
    virSecurityLabelDefPtr seclabel;
    virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr);

    seclabel = virDomainDefGetSecurityLabelDef(def, SECURITY_DAC_NAME);
1031
    if (seclabel == NULL)
1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049
        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;
    }

1050
    switch (seclabel->type) {
1051 1052 1053 1054 1055 1056 1057 1058 1059
    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:
1060
        if (virAsprintf(&seclabel->label, "+%u:+%u",
1061
                        (unsigned int) priv->user,
1062
                        (unsigned int) priv->group) < 0)
1063 1064 1065 1066 1067 1068 1069 1070 1071 1072
            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 */
1073
        return 0;
1074 1075 1076 1077 1078 1079 1080
    default:
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected security label type '%s'"),
                       virDomainSeclabelTypeToString(seclabel->type));
        return rc;
    }

1081 1082 1083 1084
    if (!seclabel->norelabel && !seclabel->imagelabel &&
        VIR_STRDUP(seclabel->imagelabel, seclabel->label) < 0) {
        VIR_FREE(seclabel->label);
        return rc;
1085 1086
    }

1087 1088 1089 1090 1091
    return 0;
}

static int
virSecurityDACReleaseLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
1092
                           virDomainDefPtr def ATTRIBUTE_UNUSED)
1093 1094 1095 1096 1097 1098
{
    return 0;
}

static int
virSecurityDACReserveLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
1099 1100
                           virDomainDefPtr def ATTRIBUTE_UNUSED,
                           pid_t pid ATTRIBUTE_UNUSED)
1101 1102 1103 1104 1105 1106
{
    return 0;
}

static int
virSecurityDACGetProcessLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
1107
                              virDomainDefPtr def,
1108
                              pid_t pid ATTRIBUTE_UNUSED,
1109
                              virSecurityLabelPtr seclabel)
1110
{
1111 1112 1113 1114 1115 1116 1117
    virSecurityLabelDefPtr secdef =
        virDomainDefGetSecurityLabelDef(def, SECURITY_DAC_NAME);

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

    if (secdef->label)
1118 1119
        ignore_value(virStrcpy(seclabel->label, secdef->label,
                               VIR_SECURITY_LABEL_BUFLEN));
1120

1121 1122 1123 1124
    return 0;
}

static int
1125
virSecurityDACSetDaemonSocketLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
1126
                                   virDomainDefPtr vm ATTRIBUTE_UNUSED)
1127 1128 1129 1130 1131
{
    return 0;
}


1132 1133
static int
virSecurityDACSetSocketLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
1134
                             virDomainDefPtr def ATTRIBUTE_UNUSED)
1135 1136 1137 1138 1139
{
    return 0;
}


1140 1141
static int
virSecurityDACClearSocketLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
1142
                               virDomainDefPtr def ATTRIBUTE_UNUSED)
1143 1144 1145 1146
{
    return 0;
}

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

1155 1156 1157 1158 1159 1160 1161 1162
static int
virSecurityDACSetTapFDLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
                            virDomainDefPtr def ATTRIBUTE_UNUSED,
                            int fd ATTRIBUTE_UNUSED)
{
    return 0;
}

O
Osier Yang 已提交
1163 1164 1165 1166
static char *
virSecurityDACGetMountOptions(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
                              virDomainDefPtr vm ATTRIBUTE_UNUSED)
{
1167 1168 1169
    return NULL;
}

1170 1171 1172 1173 1174 1175 1176 1177
static const char *
virSecurityDACGetBaseLabel(virSecurityManagerPtr mgr,
                           int virt ATTRIBUTE_UNUSED)
{
    virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr);
    return priv->baselabel;
}

1178
virSecurityDriver virSecurityDriverDAC = {
1179
    .privateDataLen                     = sizeof(virSecurityDACData),
1180
    .name                               = SECURITY_DAC_NAME,
1181 1182 1183
    .probe                              = virSecurityDACProbe,
    .open                               = virSecurityDACOpen,
    .close                              = virSecurityDACClose,
1184

1185 1186
    .getModel                           = virSecurityDACGetModel,
    .getDOI                             = virSecurityDACGetDOI,
1187

1188 1189
    .preFork                            = virSecurityDACPreFork,

1190
    .domainSecurityVerify               = virSecurityDACVerify,
1191

1192 1193
    .domainSetSecurityImageLabel        = virSecurityDACSetSecurityImageLabel,
    .domainRestoreSecurityImageLabel    = virSecurityDACRestoreSecurityImageLabel,
1194

1195 1196 1197
    .domainSetSecurityDaemonSocketLabel = virSecurityDACSetDaemonSocketLabel,
    .domainSetSecuritySocketLabel       = virSecurityDACSetSocketLabel,
    .domainClearSecuritySocketLabel     = virSecurityDACClearSocketLabel,
1198

1199 1200 1201
    .domainGenSecurityLabel             = virSecurityDACGenLabel,
    .domainReserveSecurityLabel         = virSecurityDACReserveLabel,
    .domainReleaseSecurityLabel         = virSecurityDACReleaseLabel,
1202

1203 1204
    .domainGetSecurityProcessLabel      = virSecurityDACGetProcessLabel,
    .domainSetSecurityProcessLabel      = virSecurityDACSetProcessLabel,
1205
    .domainSetSecurityChildProcessLabel = virSecurityDACSetChildProcessLabel,
1206

1207 1208
    .domainSetSecurityAllLabel          = virSecurityDACSetSecurityAllLabel,
    .domainRestoreSecurityAllLabel      = virSecurityDACRestoreSecurityAllLabel,
1209

1210 1211
    .domainSetSecurityHostdevLabel      = virSecurityDACSetSecurityHostdevLabel,
    .domainRestoreSecurityHostdevLabel  = virSecurityDACRestoreSecurityHostdevLabel,
1212

1213 1214
    .domainSetSavedStateLabel           = virSecurityDACSetSavedStateLabel,
    .domainRestoreSavedStateLabel       = virSecurityDACRestoreSavedStateLabel,
1215

1216
    .domainSetSecurityImageFDLabel      = virSecurityDACSetImageFDLabel,
1217
    .domainSetSecurityTapFDLabel        = virSecurityDACSetTapFDLabel,
1218

1219
    .domainGetSecurityMountOptions      = virSecurityDACGetMountOptions,
1220 1221

    .getBaseLabel                       = virSecurityDACGetBaseLabel,
1222
};