BZ:https://bugzilla.redhat.com/show_bug.cgi?id=851981
When using macvtap, a character device gets first created by
kernel with name /dev/tapN, its selinux context is:
system_u:object_r:device_t:s0
Shortly, when udev gets notification when new file is created
in /dev, it will then jump in and relabel this file back to the
expected default context:
system_u:object_r:tun_tap_device_t:s0
There is a time gap happened.
Sometimes, it will have migration failed, AVC error message:
type=AVC msg=audit(1349858424.233:42507): avc: denied { read write } for
pid=19926 comm="qemu-kvm" path="/dev/tap33" dev=devtmpfs ino=131524
scontext=unconfined_u:system_r:svirt_t:s0:c598,c908
tcontext=system_u:object_r:device_t:s0 tclass=chr_file
This patch will label the tapfd device before qemu process starts:
system_u:object_r:tun_tap_device_t:MCS(MCS from seclabel->label)
---
src/libvirt_private.syms | 1 +
src/qemu/qemu_command.c | 4 ++
src/security/security_apparmor.c | 10 ++++
src/security/security_dac.c | 9 +++
src/security/security_driver.h | 4 ++
src/security/security_manager.c | 11 ++++
src/security/security_manager.h | 3 +
src/security/security_nop.c | 3 +-
src/security/security_selinux.c | 118 +++++++++++++++++++++++++++++++--------
src/security/security_stack.c | 18 ++++++
10 files changed, 156 insertions(+), 25 deletions(-)
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 6ea1308..1703f6d 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -1056,6 +1056,7 @@ virSecurityManagerSetHostdevLabel;
virSecurityManagerSetProcessLabel;
virSecurityManagerSetSavedStateLabel;
virSecurityManagerSetSocketLabel;
+virSecurityManagerSetTapFDLabel;
virSecurityManagerStackAddNested;
virSecurityManagerVerify;
virSecurityManagerGetMountOptions;
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index d590df6..239592c 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -5412,6 +5412,10 @@ qemuBuildCommandLine(virConnectPtr conn,
if (tapfd < 0)
goto error;
+ if (virSecurityManagerSetTapFDLabel(driver->securityManager,
+ def, tapfd) < 0)
+ goto error;
+
last_good_net = i;
virCommandTransferFD(cmd, tapfd);
diff --git a/src/security/security_apparmor.c b/src/security/security_apparmor.c
index d3f9d9e..1315fe1 100644
--- a/src/security/security_apparmor.c
+++ b/src/security/security_apparmor.c
@@ -872,6 +872,15 @@ AppArmorSetImageFDLabel(virSecurityManagerPtr mgr,
return reload_profile(mgr, def, fd_path, true);
}
+/* TODO need code here */
+static int
+AppArmorSetTapFDLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
+ virDomainDefPtr def ATTRIBUTE_UNUSED,
+ int fd ATTRIBUTE_UNUSED)
+{
+ return 0;
+}
+
virSecurityDriver virAppArmorSecurityDriver = {
.privateDataLen = 0,
.name = SECURITY_APPARMOR_NAME,
@@ -908,4 +917,5 @@ virSecurityDriver virAppArmorSecurityDriver = {
.domainRestoreSavedStateLabel = AppArmorRestoreSavedStateLabel,
.domainSetSecurityImageFDLabel = AppArmorSetImageFDLabel,
+ .domainSetSecurityTapFDLabel = AppArmorSetTapFDLabel,
};
diff --git a/src/security/security_dac.c b/src/security/security_dac.c
index f126aa5..9dbf95d 100644
--- a/src/security/security_dac.c
+++ b/src/security/security_dac.c
@@ -1029,6 +1029,14 @@ virSecurityDACSetImageFDLabel(virSecurityManagerPtr mgr
ATTRIBUTE_UNUSED,
return 0;
}
+static int
+virSecurityDACSetTapFDLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
+ virDomainDefPtr def ATTRIBUTE_UNUSED,
+ int fd ATTRIBUTE_UNUSED)
+{
+ return 0;
+}
+
static char *virSecurityDACGetMountOptions(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
virDomainDefPtr vm ATTRIBUTE_UNUSED) {
return NULL;
@@ -1070,6 +1078,7 @@ virSecurityDriver virSecurityDriverDAC = {
.domainRestoreSavedStateLabel = virSecurityDACRestoreSavedStateLabel,
.domainSetSecurityImageFDLabel = virSecurityDACSetImageFDLabel,
+ .domainSetSecurityTapFDLabel = virSecurityDACSetTapFDLabel,
.domainGetSecurityMountOptions = virSecurityDACGetMountOptions,
};
diff --git a/src/security/security_driver.h b/src/security/security_driver.h
index 8f52ec5..d49b401 100644
--- a/src/security/security_driver.h
+++ b/src/security/security_driver.h
@@ -95,6 +95,9 @@ typedef int (*virSecurityDomainSecurityVerify) (virSecurityManagerPtr
mgr,
typedef int (*virSecurityDomainSetImageFDLabel) (virSecurityManagerPtr mgr,
virDomainDefPtr def,
int fd);
+typedef int (*virSecurityDomainSetTapFDLabel) (virSecurityManagerPtr mgr,
+ virDomainDefPtr def,
+ int fd);
typedef char *(*virSecurityDomainGetMountOptions) (virSecurityManagerPtr mgr,
virDomainDefPtr def);
@@ -134,6 +137,7 @@ struct _virSecurityDriver {
virSecurityDomainRestoreSavedStateLabel domainRestoreSavedStateLabel;
virSecurityDomainSetImageFDLabel domainSetSecurityImageFDLabel;
+ virSecurityDomainSetTapFDLabel domainSetSecurityTapFDLabel;
virSecurityDomainGetMountOptions domainGetSecurityMountOptions;
};
diff --git a/src/security/security_manager.c b/src/security/security_manager.c
index 40c8b7e..d446607 100644
--- a/src/security/security_manager.c
+++ b/src/security/security_manager.c
@@ -469,6 +469,17 @@ int virSecurityManagerSetImageFDLabel(virSecurityManagerPtr mgr,
return -1;
}
+int virSecurityManagerSetTapFDLabel(virSecurityManagerPtr mgr,
+ virDomainDefPtr vm,
+ int fd)
+{
+ if (mgr->drv->domainSetSecurityTapFDLabel)
+ return mgr->drv->domainSetSecurityTapFDLabel(mgr, vm, fd);
+
+ virReportError(VIR_ERR_NO_SUPPORT, __FUNCTION__);
+ return -1;
+}
+
char *virSecurityManagerGetMountOptions(virSecurityManagerPtr mgr,
virDomainDefPtr vm)
{
diff --git a/src/security/security_manager.h b/src/security/security_manager.h
index b3bc191..1fdaf8e 100644
--- a/src/security/security_manager.h
+++ b/src/security/security_manager.h
@@ -105,6 +105,9 @@ int virSecurityManagerVerify(virSecurityManagerPtr mgr,
int virSecurityManagerSetImageFDLabel(virSecurityManagerPtr mgr,
virDomainDefPtr def,
int fd);
+int virSecurityManagerSetTapFDLabel(virSecurityManagerPtr mgr,
+ virDomainDefPtr vm,
+ int fd);
char *virSecurityManagerGetMountOptions(virSecurityManagerPtr mgr,
virDomainDefPtr vm);
virSecurityManagerPtr*
diff --git a/src/security/security_nop.c b/src/security/security_nop.c
index b56971c..86f644b 100644
--- a/src/security/security_nop.c
+++ b/src/security/security_nop.c
@@ -204,7 +204,8 @@ virSecurityDriver virSecurityDriverNop = {
.domainSetSavedStateLabel = virSecurityDomainSetSavedStateLabelNop,
.domainRestoreSavedStateLabel = virSecurityDomainRestoreSavedStateLabelNop,
- .domainSetSecurityImageFDLabel = virSecurityDomainSetFDLabelNop,
+ .domainSetSecurityImageFDLabel = virSecurityDomainSetFDLabelNop,
+ .domainSetSecurityTapFDLabel = virSecurityDomainSetFDLabelNop,
.domainGetSecurityMountOptions = virSecurityDomainGetMountOptionsNop,
};
diff --git a/src/security/security_selinux.c b/src/security/security_selinux.c
index 10135ed..0a2a9fe 100644
--- a/src/security/security_selinux.c
+++ b/src/security/security_selinux.c
@@ -237,6 +237,46 @@ cleanup:
return mcs;
}
+static char *
+virSecuritySELinuxContextAddRange(security_context_t src,
+ security_context_t dst)
+{
+ char *str = NULL;
+ char *ret = NULL;
+ context_t srccon = NULL;
+ context_t dstcon = NULL;
+
+ if (!src || !dst)
+ return ret;
+
+ if (!(srccon = context_new(src)) || !(dstcon = context_new(dst))) {
+ virReportSystemError(errno, "%s",
+ _("unable to allocate security context"));
+ goto cleanup;
+ }
+
+ if (context_range_set(dstcon, context_range_get(srccon)) == -1) {
+ virReportSystemError(errno,
+ _("unable to set security context range
'%s'"), dst);
+ goto cleanup;
+ }
+
+ if (!(str = context_str(dstcon))) {
+ virReportSystemError(errno, "%s",
+ _("Unable to format SELinux context"));
+ goto cleanup;
+ }
+
+ if (!(ret = strdup(str))) {
+ virReportOOMError();
+ goto cleanup;
+ }
+
+cleanup:
+ if (srccon) context_free(srccon);
+ if (dstcon) context_free(dstcon);
+ return ret;
+}
static char *
virSecuritySELinuxGenNewContext(const char *basecontext,
@@ -1597,6 +1637,7 @@
virSecuritySELinuxSetSecurityDaemonSocketLabel(virSecurityManagerPtr mgr,
context_t execcon = NULL;
context_t proccon = NULL;
security_context_t scon = NULL;
+ char *str = NULL;
int rc = -1;
secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
@@ -1615,13 +1656,6 @@
virSecuritySELinuxSetSecurityDaemonSocketLabel(virSecurityManagerPtr mgr,
goto done;
}
- if ( !(execcon = context_new(secdef->label)) ) {
- virReportSystemError(errno,
- _("unable to allocate socket security context
'%s'"),
- secdef->label);
- goto done;
- }
-
if (getcon_raw(&scon) == -1) {
virReportSystemError(errno,
_("unable to get current process context
'%s'"),
@@ -1629,26 +1663,13 @@
virSecuritySELinuxSetSecurityDaemonSocketLabel(virSecurityManagerPtr mgr,
goto done;
}
- if ( !(proccon = context_new(scon)) ) {
- virReportSystemError(errno,
- _("unable to set socket security context
'%s'"),
- secdef->label);
- goto done;
- }
-
- if (context_range_set(proccon, context_range_get(execcon)) == -1) {
- virReportSystemError(errno,
- _("unable to set socket security context range
'%s'"),
- secdef->label);
+ if (!(str = virSecuritySELinuxContextAddRange(secdef->label, scon)))
goto done;
- }
- VIR_DEBUG("Setting VM %s socket context %s",
- def->name, context_str(proccon));
- if (setsockcreatecon_raw(context_str(proccon)) == -1) {
+ VIR_DEBUG("Setting VM %s socket context %s", def->name, str);
+ if (setsockcreatecon_raw(str) == -1) {
virReportSystemError(errno,
- _("unable to set socket security context
'%s'"),
- context_str(proccon));
+ _("unable to set socket security context
'%s'"), str);
goto done;
}
@@ -1660,6 +1681,7 @@ done:
if (execcon) context_free(execcon);
if (proccon) context_free(proccon);
freecon(scon);
+ VIR_FREE(str);
return rc;
}
@@ -1869,6 +1891,53 @@ virSecuritySELinuxSetImageFDLabel(virSecurityManagerPtr mgr
ATTRIBUTE_UNUSED,
return virSecuritySELinuxFSetFilecon(fd, secdef->imagelabel);
}
+static int
+virSecuritySELinuxSetTapFDLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
+ virDomainDefPtr def,
+ int fd)
+{
+ struct stat buf;
+ security_context_t fcon = NULL;
+ virSecurityLabelDefPtr secdef;
+ char *str = NULL;
+ int rc = -1;
+
+ secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
+ if (secdef == NULL)
+ return rc;
+
+ if (secdef->label == NULL)
+ return 0;
+
+ if (fstat(fd, &buf) < 0) {
+ virReportSystemError(errno, _("cannot stat tap fd %d"), fd);
+ goto cleanup;
+ }
+
+ if ((buf.st_mode & S_IFMT) != S_IFCHR) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("tap fd %d is not character device"), fd);
+ goto cleanup;
+ }
+
+ if (getContext("/dev/tap.*", buf.st_mode, &fcon) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("cannot lookup default selinux label for tap fd %d"),
fd);
+ goto cleanup;
+ }
+
+ if (!(str = virSecuritySELinuxContextAddRange(secdef->label, fcon))) {
+ goto cleanup;
+ } else {
+ rc = virSecuritySELinuxFSetFilecon(fd, str);
+ }
+
+cleanup:
+ freecon(fcon);
+ VIR_FREE(str);
+ return rc;
+}
+
static char *
virSecuritySELinuxGenImageLabel(virSecurityManagerPtr mgr,
virDomainDefPtr def)
@@ -1969,6 +2038,7 @@ virSecurityDriver virSecurityDriverSELinux = {
.domainRestoreSavedStateLabel = virSecuritySELinuxRestoreSavedStateLabel,
.domainSetSecurityImageFDLabel = virSecuritySELinuxSetImageFDLabel,
+ .domainSetSecurityTapFDLabel = virSecuritySELinuxSetTapFDLabel,
.domainGetSecurityMountOptions = virSecuritySELinuxGetSecurityMountOptions,
};
diff --git a/src/security/security_stack.c b/src/security/security_stack.c
index 667448f..24de6f2 100644
--- a/src/security/security_stack.c
+++ b/src/security/security_stack.c
@@ -445,6 +445,23 @@ virSecurityStackSetImageFDLabel(virSecurityManagerPtr mgr,
return rc;
}
+static int
+virSecurityStackSetTapFDLabel(virSecurityManagerPtr mgr,
+ virDomainDefPtr vm,
+ int fd)
+{
+ virSecurityStackDataPtr priv = virSecurityManagerGetPrivateData(mgr);
+ virSecurityStackItemPtr item = priv->itemsHead;
+ int rc = 0;
+
+ for (; item; item = item->next) {
+ if (virSecurityManagerSetTapFDLabel(item->securityManager, vm, fd) < 0)
+ rc = -1;
+ }
+
+ return rc;
+}
+
static char *virSecurityStackGetMountOptions(virSecurityManagerPtr mgr
ATTRIBUTE_UNUSED,
virDomainDefPtr vm ATTRIBUTE_UNUSED) {
return NULL;
@@ -509,6 +526,7 @@ virSecurityDriver virSecurityDriverStack = {
.domainRestoreSavedStateLabel = virSecurityStackRestoreSavedStateLabel,
.domainSetSecurityImageFDLabel = virSecurityStackSetImageFDLabel,
+ .domainSetSecurityTapFDLabel = virSecurityStackSetTapFDLabel,
.domainGetSecurityMountOptions = virSecurityStackGetMountOptions,
};
The patch should work on all the tapfd possibilities and from the looks
of it, this is probably the best possibility we can do with the file
descriptor. Also policies without MCS/MLS ranges should work as well as
policies with the range already set, so ACK from me.
Martin