[libvirt] [PATCH 3/6] Use private data struct in SELinux driver

Daniel P. Berrange berrange at redhat.com
Fri May 11 10:10:03 UTC 2012


From: Daniel Walsh <dwalsh at redhat.com>

Currently the SELinux driver stores its state in a set of global
variables. This switches it to use a private data struct instead.
This will enable different instances to have their own data.

Signed-off-by: Daniel P. Berrange <berrange at redhat.com>
---
 src/security/security_selinux.c |  173 ++++++++++++++++++++++++---------------
 1 file changed, 106 insertions(+), 67 deletions(-)

diff --git a/src/security/security_selinux.c b/src/security/security_selinux.c
index 4bd33a5..7202e71 100644
--- a/src/security/security_selinux.c
+++ b/src/security/security_selinux.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2008-2011 Red Hat, Inc.
+ * Copyright (C) 2008-2012 Red Hat, Inc.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -33,12 +33,30 @@
 #include "storage_file.h"
 #include "virfile.h"
 #include "virrandom.h"
+#include "util.h"
+#include "conf.h"
 
 #define VIR_FROM_THIS VIR_FROM_SECURITY
 
-static char default_domain_context[1024];
-static char default_content_context[1024];
-static char default_image_context[1024];
+#define MAX_CONTEXT 1024
+
+typedef struct _virSecuritySELinuxData virSecuritySELinuxData;
+typedef virSecuritySELinuxData *virSecuritySELinuxDataPtr;
+
+typedef struct _virSecuritySELinuxCallbackData virSecuritySELinuxCallbackData;
+typedef virSecuritySELinuxCallbackData *virSecuritySELinuxCallbackDataPtr;
+
+struct _virSecuritySELinuxData {
+    char *domain_context;
+    char *file_context;
+    char *content_context;
+};
+
+struct _virSecuritySELinuxCallbackData {
+    virSecurityManagerPtr manager;
+    virSecurityLabelDefPtr secdef;
+};
+
 #define SECURITY_SELINUX_VOID_DOI       "0"
 #define SECURITY_SELINUX_NAME "selinux"
 
@@ -109,60 +127,51 @@ err:
 }
 
 static int
-SELinuxInitialize(void)
+SELinuxInitialize(virSecurityManagerPtr mgr)
 {
-    char *ptr = NULL;
-    int fd = 0;
+    char *ptr;
+    virSecuritySELinuxDataPtr data = virSecurityManagerGetPrivateData(mgr);
 
-    fd = open(selinux_virtual_domain_context_path(), O_RDONLY);
-    if (fd < 0) {
+    if (virFileReadAll(selinux_virtual_domain_context_path(), MAX_CONTEXT, &(data->domain_context)) < 0) {
         virReportSystemError(errno,
-                             _("cannot open SELinux virtual domain context file '%s'"),
+                             _("cannot read SELinux virtual domain context file '%s'"),
                              selinux_virtual_domain_context_path());
-        return -1;
+        goto error;
     }
 
-    if (saferead(fd, default_domain_context, sizeof(default_domain_context)) < 0) {
-        virReportSystemError(errno,
-                             _("cannot read SELinux virtual domain context file %s"),
-                             selinux_virtual_domain_context_path());
-        VIR_FORCE_CLOSE(fd);
-        return -1;
-    }
-    VIR_FORCE_CLOSE(fd);
-
-    ptr = strchrnul(default_domain_context, '\n');
-    *ptr = '\0';
-
-    if ((fd = open(selinux_virtual_image_context_path(), O_RDONLY)) < 0) {
-        virReportSystemError(errno,
-                             _("cannot open SELinux virtual image context file %s"),
-                             selinux_virtual_image_context_path());
-        return -1;
-    }
+    ptr = strchrnul(data->domain_context, '\n');
+    if (ptr)
+        *ptr = '\0';
 
-    if (saferead(fd, default_image_context, sizeof(default_image_context)) < 0) {
+    if (virFileReadAll(selinux_virtual_image_context_path(), 2*MAX_CONTEXT, &(data->file_context)) < 0) {
         virReportSystemError(errno,
                              _("cannot read SELinux virtual image context file %s"),
                              selinux_virtual_image_context_path());
-        VIR_FORCE_CLOSE(fd);
-        return -1;
+        goto error;
     }
-    VIR_FORCE_CLOSE(fd);
 
-    ptr = strchrnul(default_image_context, '\n');
-    if (*ptr == '\n') {
+    ptr = strchrnul(data->file_context, '\n');
+    if (ptr && *ptr == '\n') {
         *ptr = '\0';
-        strcpy(default_content_context, ptr+1);
-        ptr = strchrnul(default_content_context, '\n');
-        if (*ptr == '\n')
+        data->content_context = strdup(ptr+1);
+        if (!data->content_context)
+            goto error;
+        ptr = strchrnul(data->content_context, '\n');
+        if (ptr && *ptr == '\n')
             *ptr = '\0';
     }
+
     return 0;
+
+error:
+    VIR_FREE(data->domain_context);
+    VIR_FREE(data->file_context);
+    VIR_FREE(data->content_context);
+    return -1;
 }
 
 static int
-SELinuxGenSecurityLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
+SELinuxGenSecurityLabel(virSecurityManagerPtr mgr,
                         virDomainDefPtr def)
 {
     int rc = -1;
@@ -172,7 +181,9 @@ SELinuxGenSecurityLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
     int c2 = 0;
     context_t ctx = NULL;
     const char *range;
+    virSecuritySELinuxDataPtr data = virSecurityManagerGetPrivateData(mgr);
 
+    VIR_DEBUG("SELinuxGenSecurityLabel %s", virSecurityManagerGetDriver(mgr));
     if ((def->seclabel.type == VIR_DOMAIN_SECLABEL_DYNAMIC) &&
         !def->seclabel.baselabel &&
         def->seclabel.model) {
@@ -202,6 +213,8 @@ SELinuxGenSecurityLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
         return rc;
     }
 
+    VIR_DEBUG("SELinuxGenSecurityLabel %d", def->seclabel.type);
+
     switch (def->seclabel.type) {
     case VIR_DOMAIN_SECLABEL_STATIC:
         if (!(ctx = context_new(def->seclabel.label)) ) {
@@ -245,7 +258,7 @@ SELinuxGenSecurityLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
         def->seclabel.label =
             SELinuxGenNewContext(def->seclabel.baselabel ?
                                  def->seclabel.baselabel :
-                                 default_domain_context, mcs);
+                                 data->domain_context, mcs);
         if (! def->seclabel.label)  {
             virSecurityReportError(VIR_ERR_INTERNAL_ERROR,
                                    _("cannot generate selinux context for %s"), mcs);
@@ -264,13 +277,11 @@ SELinuxGenSecurityLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
         goto cleanup;
     }
 
-    if (!def->seclabel.norelabel) {
-        def->seclabel.imagelabel = SELinuxGenNewContext(default_image_context, mcs);
-        if (!def->seclabel.imagelabel)  {
-            virSecurityReportError(VIR_ERR_INTERNAL_ERROR,
-                                   _("cannot generate selinux context for %s"), mcs);
-            goto cleanup;
-        }
+    def->seclabel.imagelabel = SELinuxGenNewContext(data->file_context, mcs);
+    if (!def->seclabel.imagelabel)  {
+        virSecurityReportError(VIR_ERR_INTERNAL_ERROR,
+                               _("cannot generate selinux context for %s"), mcs);
+        goto cleanup;
     }
 
     if (!def->seclabel.model &&
@@ -344,22 +355,39 @@ err:
 }
 
 
-
 static int
-SELinuxSecurityDriverProbe(const char *virtDriver ATTRIBUTE_UNUSED)
+SELinuxSecurityDriverProbe(const char *virtDriver)
 {
-    return is_selinux_enabled() ? SECURITY_DRIVER_ENABLE : SECURITY_DRIVER_DISABLE;
+    if (!is_selinux_enabled())
+        return SECURITY_DRIVER_DISABLE;
+
+    if (virtDriver && STREQ(virtDriver, "LXC") &&
+        !virFileExists(selinux_lxc_contexts_path()))
+        return SECURITY_DRIVER_DISABLE;
+
+    return SECURITY_DRIVER_ENABLE;
 }
 
+
 static int
-SELinuxSecurityDriverOpen(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED)
+SELinuxSecurityDriverOpen(virSecurityManagerPtr mgr)
 {
-    return SELinuxInitialize();
+    return SELinuxInitialize(mgr);
 }
 
+
 static int
-SELinuxSecurityDriverClose(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED)
+SELinuxSecurityDriverClose(virSecurityManagerPtr mgr)
 {
+    virSecuritySELinuxDataPtr data = virSecurityManagerGetPrivateData(mgr);
+
+    if (!data)
+        return 0;
+
+    VIR_FREE(data->domain_context);
+    VIR_FREE(data->file_context);
+    VIR_FREE(data->content_context);
+
     return 0;
 }
 
@@ -405,6 +433,7 @@ SELinuxGetSecurityProcessLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
     strcpy(sec->label, (char *) ctx);
     freecon(ctx);
 
+    VIR_DEBUG("SELinuxGetSecurityProcessLabel %s", sec->label);
     sec->enforcing = security_getenforce();
     if (sec->enforcing == -1) {
         virReportSystemError(errno, "%s",
@@ -639,8 +668,10 @@ SELinuxSetSecurityFileLabel(virDomainDiskDefPtr disk,
                             size_t depth,
                             void *opaque)
 {
-    const virSecurityLabelDefPtr secdef = opaque;
+    virSecuritySELinuxCallbackDataPtr cbdata = opaque;
+    const virSecurityLabelDefPtr secdef = cbdata->secdef;
     int ret;
+    virSecuritySELinuxDataPtr data = virSecurityManagerGetPrivateData(cbdata->manager);
 
     if (disk->seclabel && disk->seclabel->norelabel)
         return 0;
@@ -649,17 +680,18 @@ SELinuxSetSecurityFileLabel(virDomainDiskDefPtr disk,
         disk->seclabel->label) {
         ret = SELinuxSetFilecon(path, disk->seclabel->label);
     } else if (depth == 0) {
+
         if (disk->shared) {
-            ret = SELinuxSetFileconOptional(path, default_image_context);
+            ret = SELinuxSetFileconOptional(path, data->file_context);
         } else if (disk->readonly) {
-            ret = SELinuxSetFileconOptional(path, default_content_context);
+            ret = SELinuxSetFileconOptional(path, data->content_context);
         } else if (secdef->imagelabel) {
             ret = SELinuxSetFileconOptional(path, secdef->imagelabel);
         } else {
             ret = 0;
         }
     } else {
-        ret = SELinuxSetFileconOptional(path, default_content_context);
+        ret = SELinuxSetFileconOptional(path, data->content_context);
     }
     if (ret == 1 && !disk->seclabel) {
         /* If we failed to set a label, but virt_use_nfs let us
@@ -680,10 +712,13 @@ SELinuxSetSecurityImageLabel(virSecurityManagerPtr mgr,
                              virDomainDiskDefPtr disk)
 
 {
-    const virSecurityLabelDefPtr secdef = &def->seclabel;
+    virSecuritySELinuxCallbackData cbdata;
+    cbdata.secdef = &def->seclabel;
+    cbdata.manager = mgr;
+
     bool allowDiskFormatProbing = virSecurityManagerGetAllowDiskFormatProbing(mgr);
 
-    if (secdef->norelabel)
+    if (cbdata.secdef->norelabel)
         return 0;
 
     if (disk->type == VIR_DOMAIN_DISK_TYPE_NETWORK)
@@ -700,7 +735,7 @@ SELinuxSetSecurityImageLabel(virSecurityManagerPtr mgr,
                                        true,
                                        -1, -1, /* current process uid:gid */
                                        SELinuxSetSecurityFileLabel,
-                                       secdef);
+                                       &cbdata);
 }
 
 
@@ -1119,6 +1154,7 @@ SELinuxSetSecurityProcessLabel(virSecurityManagerPtr mgr,
 {
     /* TODO: verify DOI */
     const virSecurityLabelDefPtr secdef = &def->seclabel;
+    VIR_DEBUG("SELinuxSetSecurityProcessLabel %s", secdef->label);
 
     if (def->seclabel.label == NULL)
         return 0;
@@ -1300,9 +1336,11 @@ SELinuxSetSecurityChardevCallback(virDomainDefPtr def,
 static int
 SELinuxSetSecuritySmartcardCallback(virDomainDefPtr def,
                                     virDomainSmartcardDefPtr dev,
-                                    void *opaque ATTRIBUTE_UNUSED)
+                                    void *opaque)
 {
     const char *database;
+    virSecurityManagerPtr mgr = opaque;
+    virSecuritySELinuxDataPtr data = virSecurityManagerGetPrivateData(mgr);
 
     switch (dev->type) {
     case VIR_DOMAIN_SMARTCARD_TYPE_HOST:
@@ -1312,7 +1350,7 @@ SELinuxSetSecuritySmartcardCallback(virDomainDefPtr def,
         database = dev->data.cert.database;
         if (!database)
             database = VIR_DOMAIN_SMARTCARD_DEFAULT_DATABASE;
-        return SELinuxSetFilecon(database, default_content_context);
+        return SELinuxSetFilecon(database, data->content_context);
 
     case VIR_DOMAIN_SMARTCARD_TYPE_PASSTHROUGH:
         return SELinuxSetSecurityChardevLabel(def, &dev->data.passthru);
@@ -1333,6 +1371,7 @@ SELinuxSetSecurityAllLabel(virSecurityManagerPtr mgr,
                            virDomainDefPtr def,
                            const char *stdin_path)
 {
+    virSecuritySELinuxDataPtr data = virSecurityManagerGetPrivateData(mgr);
     const virSecurityLabelDefPtr secdef = &def->seclabel;
     int i;
 
@@ -1368,19 +1407,19 @@ SELinuxSetSecurityAllLabel(virSecurityManagerPtr mgr,
     if (virDomainSmartcardDefForeach(def,
                                      true,
                                      SELinuxSetSecuritySmartcardCallback,
-                                     NULL) < 0)
+                                     mgr) < 0)
         return -1;
 
     if (def->os.kernel &&
-        SELinuxSetFilecon(def->os.kernel, default_content_context) < 0)
+        SELinuxSetFilecon(def->os.kernel, data->content_context) < 0)
         return -1;
 
     if (def->os.initrd &&
-        SELinuxSetFilecon(def->os.initrd, default_content_context) < 0)
+        SELinuxSetFilecon(def->os.initrd, data->content_context) < 0)
         return -1;
 
     if (stdin_path) {
-        if (SELinuxSetFilecon(stdin_path, default_content_context) < 0 &&
+        if (SELinuxSetFilecon(stdin_path, data->content_context) < 0 &&
             virStorageFileIsSharedFSType(stdin_path,
                                          VIR_STORAGE_FILE_SHFS_NFS) != 1)
             return -1;
@@ -1403,7 +1442,7 @@ SELinuxSetImageFDLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
 }
 
 virSecurityDriver virSecurityDriverSELinux = {
-    0,
+    sizeof(virSecuritySELinuxData),
     SECURITY_SELINUX_NAME,
     SELinuxSecurityDriverProbe,
     SELinuxSecurityDriverOpen,
-- 
1.7.10.1




More information about the libvir-list mailing list