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 deletions(-)
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index f60489c..c7e4772 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 d82ba73..7dc01ac 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 0f24034..52353a3 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 e5a8d41..42dfcb8 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 6406161..0246dd8 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 189b6b4..3f88801 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 6d7cb47..24d36fe 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 7b71fd9..24609bc 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 e8bb058..79b3e1f 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,
};
--
1.7.3.4