]> xenbits.xensource.com Git - libvirt.git/commitdiff
selinux: add security selinux function to label tapfd
authorGuannan Ren <gren@redhat.com>
Mon, 15 Oct 2012 09:03:49 +0000 (17:03 +0800)
committerGuannan Ren <gren@redhat.com>
Mon, 15 Oct 2012 13:01:07 +0000 (21:01 +0800)
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
src/qemu/qemu_command.c
src/security/security_apparmor.c
src/security/security_dac.c
src/security/security_driver.h
src/security/security_manager.c
src/security/security_manager.h
src/security/security_nop.c
src/security/security_selinux.c
src/security/security_stack.c

index 9c916e487a14cc76ee7ebf18b1bf8518e920bcdf..0bd5a1216a63d4bb7485a5d913f37c183d091225 100644 (file)
@@ -1059,6 +1059,7 @@ virSecurityManagerSetHostdevLabel;
 virSecurityManagerSetProcessLabel;
 virSecurityManagerSetSavedStateLabel;
 virSecurityManagerSetSocketLabel;
+virSecurityManagerSetTapFDLabel;
 virSecurityManagerStackAddNested;
 virSecurityManagerVerify;
 virSecurityManagerGetMountOptions;
index d590df646b1545b11b2f399468af92b5e2361d8f..239592ca1914c585baec10345df00adb7c71c40b 100644 (file)
@@ -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);
 
index d3f9d9ebd30f957fdd1bb38a74b18726c80583c1..1315fe14750806f27f6e58abe7fd8071f1cd2435 100644 (file)
@@ -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,
 };
index f126aa54104e48135c7a3756910ada4b773fa622..9dbf95d5bae64f554066829e1bbd206498484233 100644 (file)
@@ -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,
 };
index 8f52ec59f554e014e87e3b3832ce816ad98ed0b2..d49b401d4fefcc7c3a16f17a35a375f2ed155436 100644 (file)
@@ -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;
 };
index 40c8b7e85737a90a4f87695f63bc819c23094f1f..d446607fcd980573c66d386360c233ff55df3b95 100644 (file)
@@ -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)
 {
index b3bc1916fe0006abc73a3ee193f33745dee9461c..1fdaf8e964c98f9b14bacfb38379d31c8f6f0802 100644 (file)
@@ -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*
index b56971ccd463bc89c2fb4a37525d31cf54a24d2a..86f644bd2c82b24d09788e035cff75b55101faa9 100644 (file)
@@ -204,7 +204,8 @@ virSecurityDriver virSecurityDriverNop = {
     .domainSetSavedStateLabel           = virSecurityDomainSetSavedStateLabelNop,
     .domainRestoreSavedStateLabel       = virSecurityDomainRestoreSavedStateLabelNop,
 
-    .domainSetSecurityImageFDLabel      =  virSecurityDomainSetFDLabelNop,
+    .domainSetSecurityImageFDLabel      = virSecurityDomainSetFDLabelNop,
+    .domainSetSecurityTapFDLabel        = virSecurityDomainSetFDLabelNop,
 
     .domainGetSecurityMountOptions      = virSecurityDomainGetMountOptionsNop,
 };
index 10135ed5e78e3aefd2b912f974cb9cb53453788e..0a2a9fe7b6cba7af6c6dcfe1027663dd8d74b314 100644 (file)
@@ -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,
 };
index 667448f29e5facb9352ca54624cfb3504aa26d51..91401c6c7c67aa10468cb2ab6fdae99963d4cc80 100644 (file)
@@ -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,
 };