2 * Copyright (C) 2010-2011 Red Hat, Inc.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 * POSIX DAC security driver
22 #include <sys/types.h>
26 #include "security_dac.h"
27 #include "virterror_internal.h"
33 #include "storage_file.h"
35 #define VIR_FROM_THIS VIR_FROM_SECURITY
37 typedef struct _virSecurityDACData virSecurityDACData;
38 typedef virSecurityDACData *virSecurityDACDataPtr;
40 struct _virSecurityDACData {
43 bool dynamicOwnership;
46 void virSecurityDACSetUser(virSecurityManagerPtr mgr,
49 virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr);
53 void virSecurityDACSetGroup(virSecurityManagerPtr mgr,
56 virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr);
60 void virSecurityDACSetDynamicOwnership(virSecurityManagerPtr mgr,
61 bool dynamicOwnership)
63 virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr);
64 priv->dynamicOwnership = dynamicOwnership;
67 static virSecurityDriverStatus
68 virSecurityDACProbe(void)
70 return SECURITY_DRIVER_ENABLE;
74 virSecurityDACOpen(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED)
80 virSecurityDACClose(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED)
86 static const char * virSecurityDACGetModel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED)
91 static const char * virSecurityDACGetDOI(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED)
97 virSecurityDACSetOwnership(const char *path, int uid, int gid)
99 VIR_INFO("Setting DAC user and group on '%s' to '%d:%d'", path, uid, gid);
101 if (chown(path, uid, gid) < 0) {
103 int chown_errno = errno;
105 if (stat(path, &sb) >= 0) {
106 if (sb.st_uid == uid &&
108 /* It's alright, there's nothing to change anyway. */
113 if (chown_errno == EOPNOTSUPP || chown_errno == EINVAL) {
114 VIR_INFO("Setting user and group to '%d:%d' on '%s' not supported by filesystem",
116 } else if (chown_errno == EPERM) {
117 VIR_INFO("Setting user and group to '%d:%d' on '%s' not permitted",
119 } else if (chown_errno == EROFS) {
120 VIR_INFO("Setting user and group to '%d:%d' on '%s' not possible on readonly filesystem",
123 virReportSystemError(chown_errno,
124 _("unable to set user and group to '%d:%d' on '%s'"),
133 virSecurityDACRestoreSecurityFileLabel(const char *path)
137 char *newpath = NULL;
139 VIR_INFO("Restoring DAC user and group on '%s'", path);
141 if (virFileResolveLink(path, &newpath) < 0) {
142 virReportSystemError(errno,
143 _("cannot resolve symlink %s"), path);
147 if (stat(newpath, &buf) != 0)
150 /* XXX record previous ownership */
151 rc = virSecurityDACSetOwnership(newpath, 0, 0);
160 virSecurityDACSetSecurityFileLabel(virDomainDiskDefPtr disk ATTRIBUTE_UNUSED,
162 size_t depth ATTRIBUTE_UNUSED,
165 virSecurityManagerPtr mgr = opaque;
166 virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr);
168 return virSecurityDACSetOwnership(path, priv->user, priv->group);
173 virSecurityDACSetSecurityImageLabel(virSecurityManagerPtr mgr,
174 virDomainObjPtr vm ATTRIBUTE_UNUSED,
175 virDomainDiskDefPtr disk)
178 virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr);
180 if (!priv->dynamicOwnership)
183 return virDomainDiskDefForeachPath(disk,
184 virSecurityManagerGetAllowDiskFormatProbing(mgr),
186 virSecurityDACSetSecurityFileLabel,
192 virSecurityDACRestoreSecurityImageLabelInt(virSecurityManagerPtr mgr,
193 virDomainObjPtr vm ATTRIBUTE_UNUSED,
194 virDomainDiskDefPtr disk,
197 virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr);
199 if (!priv->dynamicOwnership)
202 /* Don't restore labels on readoly/shared disks, because
203 * other VMs may still be accessing these
204 * Alternatively we could iterate over all running
205 * domains and try to figure out if it is in use, but
206 * this would not work for clustered filesystems, since
207 * we can't see running VMs using the file on other nodes
208 * Safest bet is thus to skip the restore step.
210 if (disk->readonly || disk->shared)
216 /* If we have a shared FS & doing migrated, we must not
217 * change ownership, because that kills access on the
218 * destination host which is sub-optimal for the guest
219 * VM's I/O attempts :-)
222 int rc = virStorageFileIsSharedFS(disk->src);
226 VIR_DEBUG("Skipping image label restore on %s because FS is shared",
232 return virSecurityDACRestoreSecurityFileLabel(disk->src);
237 virSecurityDACRestoreSecurityImageLabel(virSecurityManagerPtr mgr,
239 virDomainDiskDefPtr disk)
241 return virSecurityDACRestoreSecurityImageLabelInt(mgr, vm, disk, 0);
246 virSecurityDACSetSecurityPCILabel(pciDevice *dev ATTRIBUTE_UNUSED,
250 virSecurityManagerPtr mgr = opaque;
251 virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr);
253 return virSecurityDACSetOwnership(file, priv->user, priv->group);
258 virSecurityDACSetSecurityUSBLabel(usbDevice *dev ATTRIBUTE_UNUSED,
262 virSecurityManagerPtr mgr = opaque;
263 virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr);
265 return virSecurityDACSetOwnership(file, priv->user, priv->group);
270 virSecurityDACSetSecurityHostdevLabel(virSecurityManagerPtr mgr,
271 virDomainObjPtr vm ATTRIBUTE_UNUSED,
272 virDomainHostdevDefPtr dev)
274 virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr);
277 if (!priv->dynamicOwnership)
280 if (dev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
283 switch (dev->source.subsys.type) {
284 case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB: {
285 usbDevice *usb = usbGetDevice(dev->source.subsys.u.usb.bus,
286 dev->source.subsys.u.usb.device);
291 ret = usbDeviceFileIterate(usb, virSecurityDACSetSecurityUSBLabel, mgr);
296 case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI: {
297 pciDevice *pci = pciGetDevice(dev->source.subsys.u.pci.domain,
298 dev->source.subsys.u.pci.bus,
299 dev->source.subsys.u.pci.slot,
300 dev->source.subsys.u.pci.function);
305 ret = pciDeviceFileIterate(pci, virSecurityDACSetSecurityPCILabel, mgr);
322 virSecurityDACRestoreSecurityPCILabel(pciDevice *dev ATTRIBUTE_UNUSED,
324 void *opaque ATTRIBUTE_UNUSED)
326 return virSecurityDACRestoreSecurityFileLabel(file);
331 virSecurityDACRestoreSecurityUSBLabel(usbDevice *dev ATTRIBUTE_UNUSED,
333 void *opaque ATTRIBUTE_UNUSED)
335 return virSecurityDACRestoreSecurityFileLabel(file);
340 virSecurityDACRestoreSecurityHostdevLabel(virSecurityManagerPtr mgr,
341 virDomainObjPtr vm ATTRIBUTE_UNUSED,
342 virDomainHostdevDefPtr dev)
345 virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr);
348 if (!priv->dynamicOwnership)
351 if (dev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
354 switch (dev->source.subsys.type) {
355 case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB: {
356 usbDevice *usb = usbGetDevice(dev->source.subsys.u.usb.bus,
357 dev->source.subsys.u.usb.device);
362 ret = usbDeviceFileIterate(usb, virSecurityDACRestoreSecurityUSBLabel, mgr);
368 case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI: {
369 pciDevice *pci = pciGetDevice(dev->source.subsys.u.pci.domain,
370 dev->source.subsys.u.pci.bus,
371 dev->source.subsys.u.pci.slot,
372 dev->source.subsys.u.pci.function);
377 ret = pciDeviceFileIterate(pci, virSecurityDACRestoreSecurityPCILabel, mgr);
394 virSecurityDACSetChardevLabel(virSecurityManagerPtr mgr,
395 virDomainChrSourceDefPtr dev)
398 virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr);
399 char *in = NULL, *out = NULL;
403 case VIR_DOMAIN_CHR_TYPE_DEV:
404 case VIR_DOMAIN_CHR_TYPE_FILE:
405 ret = virSecurityDACSetOwnership(dev->data.file.path, priv->user, priv->group);
408 case VIR_DOMAIN_CHR_TYPE_PIPE:
409 if (virFileExists(dev->data.file.path)) {
410 if (virSecurityDACSetOwnership(dev->data.file.path, priv->user, priv->group) < 0)
413 if ((virAsprintf(&in, "%s.in", dev->data.file.path) < 0) ||
414 (virAsprintf(&out, "%s.out", dev->data.file.path) < 0)) {
418 if ((virSecurityDACSetOwnership(in, priv->user, priv->group) < 0) ||
419 (virSecurityDACSetOwnership(out, priv->user, priv->group) < 0))
437 virSecurityDACRestoreChardevLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
438 virDomainChrSourceDefPtr dev)
440 char *in = NULL, *out = NULL;
444 case VIR_DOMAIN_CHR_TYPE_DEV:
445 case VIR_DOMAIN_CHR_TYPE_FILE:
446 ret = virSecurityDACRestoreSecurityFileLabel(dev->data.file.path);
449 case VIR_DOMAIN_CHR_TYPE_PIPE:
450 if ((virAsprintf(&out, "%s.out", dev->data.file.path) < 0) ||
451 (virAsprintf(&in, "%s.in", dev->data.file.path) < 0)) {
455 if ((virSecurityDACRestoreSecurityFileLabel(out) < 0) ||
456 (virSecurityDACRestoreSecurityFileLabel(in) < 0))
474 virSecurityDACRestoreChardevCallback(virDomainDefPtr def ATTRIBUTE_UNUSED,
475 virDomainChrDefPtr dev,
478 virSecurityManagerPtr mgr = opaque;
480 return virSecurityDACRestoreChardevLabel(mgr, &dev->source);
485 virSecurityDACRestoreSecurityAllLabel(virSecurityManagerPtr mgr,
489 virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr);
493 if (!priv->dynamicOwnership)
497 VIR_DEBUG("Restoring security label on %s migrated=%d",
498 vm->def->name, migrated);
500 for (i = 0 ; i < vm->def->nhostdevs ; i++) {
501 if (virSecurityDACRestoreSecurityHostdevLabel(mgr,
503 vm->def->hostdevs[i]) < 0)
506 for (i = 0 ; i < vm->def->ndisks ; i++) {
507 if (virSecurityDACRestoreSecurityImageLabelInt(mgr,
514 if (virDomainChrDefForeach(vm->def,
516 virSecurityDACRestoreChardevCallback,
520 if (vm->def->os.kernel &&
521 virSecurityDACRestoreSecurityFileLabel(vm->def->os.kernel) < 0)
524 if (vm->def->os.initrd &&
525 virSecurityDACRestoreSecurityFileLabel(vm->def->os.initrd) < 0)
533 virSecurityDACSetChardevCallback(virDomainDefPtr def ATTRIBUTE_UNUSED,
534 virDomainChrDefPtr dev,
537 virSecurityManagerPtr mgr = opaque;
539 return virSecurityDACSetChardevLabel(mgr, &dev->source);
544 virSecurityDACSetSecurityAllLabel(virSecurityManagerPtr mgr,
546 const char *stdin_path ATTRIBUTE_UNUSED)
548 virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr);
551 if (!priv->dynamicOwnership)
554 for (i = 0 ; i < vm->def->ndisks ; i++) {
555 /* XXX fixme - we need to recursively label the entire tree :-( */
556 if (vm->def->disks[i]->type == VIR_DOMAIN_DISK_TYPE_DIR)
558 if (virSecurityDACSetSecurityImageLabel(mgr,
560 vm->def->disks[i]) < 0)
563 for (i = 0 ; i < vm->def->nhostdevs ; i++) {
564 if (virSecurityDACSetSecurityHostdevLabel(mgr,
566 vm->def->hostdevs[i]) < 0)
570 if (virDomainChrDefForeach(vm->def,
572 virSecurityDACSetChardevCallback,
576 if (vm->def->os.kernel &&
577 virSecurityDACSetOwnership(vm->def->os.kernel,
582 if (vm->def->os.initrd &&
583 virSecurityDACSetOwnership(vm->def->os.initrd,
593 virSecurityDACSetSavedStateLabel(virSecurityManagerPtr mgr,
594 virDomainObjPtr vm ATTRIBUTE_UNUSED,
595 const char *savefile)
597 virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr);
599 return virSecurityDACSetOwnership(savefile, priv->user, priv->group);
604 virSecurityDACRestoreSavedStateLabel(virSecurityManagerPtr mgr,
605 virDomainObjPtr vm ATTRIBUTE_UNUSED,
606 const char *savefile)
608 virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr);
610 if (!priv->dynamicOwnership)
613 return virSecurityDACRestoreSecurityFileLabel(savefile);
618 virSecurityDACSetProcessLabel(virSecurityManagerPtr mgr,
619 virDomainObjPtr vm ATTRIBUTE_UNUSED)
621 virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr);
623 VIR_DEBUG("Dropping privileges of VM to %u:%u",
624 (unsigned int) priv->user, (unsigned int) priv->group);
626 if (virSetUIDGID(priv->user, priv->group) < 0)
634 virSecurityDACVerify(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
635 virDomainDefPtr def ATTRIBUTE_UNUSED)
641 virSecurityDACGenLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
642 virDomainObjPtr vm ATTRIBUTE_UNUSED)
648 virSecurityDACReleaseLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
649 virDomainObjPtr vm ATTRIBUTE_UNUSED)
655 virSecurityDACReserveLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
656 virDomainObjPtr vm ATTRIBUTE_UNUSED)
662 virSecurityDACGetProcessLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
663 virDomainObjPtr vm ATTRIBUTE_UNUSED,
664 virSecurityLabelPtr seclabel ATTRIBUTE_UNUSED)
670 virSecurityDACSetSocketLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
671 virDomainObjPtr vm ATTRIBUTE_UNUSED)
678 virSecurityDACClearSocketLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
679 virDomainObjPtr vm ATTRIBUTE_UNUSED)
685 virSecurityDACSetImageFDLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
686 virDomainObjPtr vm ATTRIBUTE_UNUSED,
687 int fd ATTRIBUTE_UNUSED)
693 virSecurityDACSetProcessFDLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
694 virDomainObjPtr vm ATTRIBUTE_UNUSED,
695 int fd ATTRIBUTE_UNUSED)
701 virSecurityDriver virSecurityDriverDAC = {
702 sizeof(virSecurityDACData),
709 virSecurityDACGetModel,
710 virSecurityDACGetDOI,
712 virSecurityDACVerify,
714 virSecurityDACSetSecurityImageLabel,
715 virSecurityDACRestoreSecurityImageLabel,
717 virSecurityDACSetSocketLabel,
718 virSecurityDACClearSocketLabel,
720 virSecurityDACGenLabel,
721 virSecurityDACReserveLabel,
722 virSecurityDACReleaseLabel,
724 virSecurityDACGetProcessLabel,
725 virSecurityDACSetProcessLabel,
727 virSecurityDACSetSecurityAllLabel,
728 virSecurityDACRestoreSecurityAllLabel,
730 virSecurityDACSetSecurityHostdevLabel,
731 virSecurityDACRestoreSecurityHostdevLabel,
733 virSecurityDACSetSavedStateLabel,
734 virSecurityDACRestoreSavedStateLabel,
736 virSecurityDACSetImageFDLabel,
737 virSecurityDACSetProcessFDLabel,