From d89608f994025aef9809bcb224e2d71f35fb85e9 Mon Sep 17 00:00:00 2001 From: Laine Stump Date: Sun, 23 Jan 2011 16:02:42 -0500 Subject: [PATCH] Add a function to the security driver API that sets the label of an open fd. A need was found to set the SELinux context label on an open fd (a pipe, as a matter of fact). This patch adds a function to the security driver API that will set the label on an open fd to secdef.label. For all drivers other than the SELinux driver, it's a NOP. For the SElinux driver, it calls fsetfilecon(). If the return is a failure, it only returns error up to the caller if 1) the desired label is different from the existing label, 2) the destination fd is of a type that supports setting the selinux context, and 3) selinux is in enforcing mode. Otherwise it will return success. This follows the pattern of the existing function SELinuxSetFilecon(). --- src/libvirt_private.syms | 1 + src/security/security_apparmor.c | 10 ++++++ src/security/security_dac.c | 10 ++++++ src/security/security_driver.h | 6 +++- src/security/security_manager.c | 11 +++++++ src/security/security_manager.h | 3 ++ src/security/security_nop.c | 9 ++++++ src/security/security_selinux.c | 54 ++++++++++++++++++++++++++++++++ src/security/security_stack.c | 18 +++++++++++ 9 files changed, 121 insertions(+), 1 deletion(-) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index f60489ccb6..c7e4772250 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -723,6 +723,7 @@ virSecurityManagerRestoreAllLabel; virSecurityManagerRestoreHostdevLabel; virSecurityManagerRestoreSavedStateLabel; virSecurityManagerSetAllLabel; +virSecurityManagerSetFDLabel; virSecurityManagerSetImageLabel; virSecurityManagerSetHostdevLabel; virSecurityManagerSetProcessLabel; diff --git a/src/security/security_apparmor.c b/src/security/security_apparmor.c index d82ba73f65..7dc01acbb9 100644 --- a/src/security/security_apparmor.c +++ b/src/security/security_apparmor.c @@ -798,6 +798,14 @@ AppArmorRestoreSavedStateLabel(virSecurityManagerPtr mgr, return reload_profile(mgr, vm, NULL, false); } +static int +AppArmorSetFDLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED, + virDomainObjPtr vm ATTRIBUTE_UNUSED, + int fd ATTRIBUTE_UNUSED) +{ + return 0; +} + virSecurityDriver virAppArmorSecurityDriver = { 0, SECURITY_APPARMOR_NAME, @@ -831,4 +839,6 @@ virSecurityDriver virAppArmorSecurityDriver = { AppArmorSetSavedStateLabel, AppArmorRestoreSavedStateLabel, + + AppArmorSetFDLabel, }; diff --git a/src/security/security_dac.c b/src/security/security_dac.c index 0f24034995..52353a3abb 100644 --- a/src/security/security_dac.c +++ b/src/security/security_dac.c @@ -675,6 +675,14 @@ virSecurityDACClearSocketLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED, return 0; } +static int +virSecurityDACSetFDLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED, + virDomainObjPtr vm ATTRIBUTE_UNUSED, + int fd ATTRIBUTE_UNUSED) +{ + return 0; +} + virSecurityDriver virSecurityDriverDAC = { sizeof(virSecurityDACData), @@ -710,4 +718,6 @@ virSecurityDriver virSecurityDriverDAC = { virSecurityDACSetSavedStateLabel, virSecurityDACRestoreSavedStateLabel, + + virSecurityDACSetFDLabel, }; diff --git a/src/security/security_driver.h b/src/security/security_driver.h index e5a8d41ffd..42dfcb8383 100644 --- a/src/security/security_driver.h +++ b/src/security/security_driver.h @@ -79,7 +79,9 @@ typedef int (*virSecurityDomainSetProcessLabel) (virSecurityManagerPtr mgr, virDomainObjPtr vm); typedef int (*virSecurityDomainSecurityVerify) (virSecurityManagerPtr mgr, virDomainDefPtr def); - +typedef int (*virSecurityDomainSetFDLabel) (virSecurityManagerPtr mgr, + virDomainObjPtr vm, + int fd); struct _virSecurityDriver { size_t privateDataLen; @@ -114,6 +116,8 @@ struct _virSecurityDriver { virSecurityDomainSetSavedStateLabel domainSetSavedStateLabel; virSecurityDomainRestoreSavedStateLabel domainRestoreSavedStateLabel; + + virSecurityDomainSetFDLabel domainSetSecurityFDLabel; }; virSecurityDriverPtr virSecurityDriverLookup(const char *name); diff --git a/src/security/security_manager.c b/src/security/security_manager.c index 6406161cfa..0246dd88bd 100644 --- a/src/security/security_manager.c +++ b/src/security/security_manager.c @@ -323,3 +323,14 @@ int virSecurityManagerVerify(virSecurityManagerPtr mgr, virSecurityReportError(VIR_ERR_NO_SUPPORT, __FUNCTION__); return -1; } + +int virSecurityManagerSetFDLabel(virSecurityManagerPtr mgr, + virDomainObjPtr vm, + int fd) +{ + if (mgr->drv->domainSetSecurityFDLabel) + return mgr->drv->domainSetSecurityFDLabel(mgr, vm, fd); + + virSecurityReportError(VIR_ERR_NO_SUPPORT, __FUNCTION__); + return -1; +} diff --git a/src/security/security_manager.h b/src/security/security_manager.h index 189b6b4d5d..3f88801870 100644 --- a/src/security/security_manager.h +++ b/src/security/security_manager.h @@ -91,5 +91,8 @@ int virSecurityManagerSetProcessLabel(virSecurityManagerPtr mgr, virDomainObjPtr vm); int virSecurityManagerVerify(virSecurityManagerPtr mgr, virDomainDefPtr def); +int virSecurityManagerSetFDLabel(virSecurityManagerPtr mgr, + virDomainObjPtr vm, + int fd); #endif /* VIR_SECURITY_MANAGER_H__ */ diff --git a/src/security/security_nop.c b/src/security/security_nop.c index 6d7cb47419..24d36fe1f5 100644 --- a/src/security/security_nop.c +++ b/src/security/security_nop.c @@ -149,6 +149,13 @@ static int virSecurityDomainVerifyNop(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED return 0; } +static int virSecurityDomainSetFDLabelNop(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED, + virDomainObjPtr sec ATTRIBUTE_UNUSED, + int fd ATTRIBUTE_UNUSED) +{ + return 0; +} + virSecurityDriver virSecurityDriverNop = { 0, "none", @@ -182,4 +189,6 @@ virSecurityDriver virSecurityDriverNop = { virSecurityDomainSetSavedStateLabelNop, virSecurityDomainRestoreSavedStateLabelNop, + + virSecurityDomainSetFDLabelNop, }; diff --git a/src/security/security_selinux.c b/src/security/security_selinux.c index 7b71fd9fdc..24609bc2e8 100644 --- a/src/security/security_selinux.c +++ b/src/security/security_selinux.c @@ -371,6 +371,45 @@ SELinuxSetFilecon(const char *path, char *tcon) return 0; } +static int +SELinuxFSetFilecon(int fd, char *tcon) +{ + security_context_t econ; + + VIR_INFO("Setting SELinux context on fd %d to '%s'", fd, tcon); + + if (fsetfilecon(fd, tcon) < 0) { + int fsetfilecon_errno = errno; + + if (fgetfilecon(fd, &econ) >= 0) { + if (STREQ(tcon, econ)) { + freecon(econ); + /* It's alright, there's nothing to change anyway. */ + return 0; + } + freecon(econ); + } + + /* if the error complaint is related to an image hosted on + * an nfs mount, or a usbfs/sysfs filesystem not supporting + * labelling, then just ignore it & hope for the best. + * The user hopefully set one of the necessary SELinux + * virt_use_{nfs,usb,pci} boolean tunables to allow it... + */ + if (fsetfilecon_errno != EOPNOTSUPP) { + virReportSystemError(fsetfilecon_errno, + _("unable to set security context '%s' on fd %d"), + tcon, fd); + if (security_getenforce() == 1) + return -1; + } else { + VIR_INFO("Setting security context '%s' on fd %d not supported", + tcon, fd); + } + } + return 0; +} + /* Set fcon to the appropriate label for path and mode, or return -1. */ static int getContext(const char *newpath, mode_t mode, security_context_t *fcon) @@ -1087,6 +1126,19 @@ SELinuxSetSecurityAllLabel(virSecurityManagerPtr mgr, return 0; } +static int +SELinuxSetFDLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED, + virDomainObjPtr vm, + int fd) +{ + const virSecurityLabelDefPtr secdef = &vm->def->seclabel; + + if (secdef->imagelabel == NULL) + return 0; + + return SELinuxFSetFilecon(fd, secdef->imagelabel); +} + virSecurityDriver virSecurityDriverSELinux = { 0, SECURITY_SELINUX_NAME, @@ -1120,4 +1172,6 @@ virSecurityDriver virSecurityDriverSELinux = { SELinuxSetSavedStateLabel, SELinuxRestoreSavedStateLabel, + + SELinuxSetFDLabel, }; diff --git a/src/security/security_stack.c b/src/security/security_stack.c index e8bb058090..79b3e1f30f 100644 --- a/src/security/security_stack.c +++ b/src/security/security_stack.c @@ -364,6 +364,22 @@ virSecurityStackClearSocketLabel(virSecurityManagerPtr mgr, return rc; } +static int +virSecurityStackSetFDLabel(virSecurityManagerPtr mgr, + virDomainObjPtr vm, + int fd) +{ + virSecurityStackDataPtr priv = virSecurityManagerGetPrivateData(mgr); + int rc = 0; + + if (virSecurityManagerSetFDLabel(priv->secondary, vm, fd) < 0) + rc = -1; + if (virSecurityManagerSetFDLabel(priv->primary, vm, fd) < 0) + rc = -1; + + return rc; +} + virSecurityDriver virSecurityDriverStack = { sizeof(virSecurityStackData), @@ -398,4 +414,6 @@ virSecurityDriver virSecurityDriverStack = { virSecurityStackSetSavedStateLabel, virSecurityStackRestoreSavedStateLabel, + + virSecurityStackSetFDLabel, };