[libvirt] [PATCH v1 2/2] security_dac: Lock label store file

Michal Privoznik mprivozn at redhat.com
Thu Mar 13 09:02:45 UTC 2014


If there are two or more libvirtds fighting over the label store file
a data corruption is likely to occur. Therefore we need to enforce an
exclusive access to the file. With a little help from virtlockd we can
achieve that.

Signed-off-by: Michal Privoznik <mprivozn at redhat.com>
---
 src/Makefile.am                  |  3 +-
 src/locking/lock_driver.h        |  2 +
 src/locking/lock_driver_lockd.c  | 25 ++++++++++++
 src/lxc/lxc_controller.c         |  2 +-
 src/lxc/lxc_driver.c             |  3 +-
 src/qemu/qemu_driver.c           |  9 +++--
 src/security/security_dac.c      | 85 ++++++++++++++++++++++++++++++++++++++--
 src/security/security_manager.c  | 24 +++++++++---
 src/security/security_manager.h  |  7 +++-
 tests/qemuhotplugtest.c          |  2 +-
 tests/seclabeltest.c             |  2 +-
 tests/securityselinuxlabeltest.c |  3 +-
 tests/securityselinuxtest.c      |  2 +-
 13 files changed, 147 insertions(+), 22 deletions(-)

diff --git a/src/Makefile.am b/src/Makefile.am
index d4d7b2b..eab1dbf 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1555,7 +1555,7 @@ libvirt_security_manager_la_SOURCES = $(SECURITY_DRIVER_SOURCES)
 noinst_LTLIBRARIES += libvirt_security_manager.la
 libvirt_la_BUILT_LIBADD += libvirt_security_manager.la
 libvirt_security_manager_la_CFLAGS = \
-		-I$(top_srcdir)/src/conf $(AM_CFLAGS)
+		-I$(top_srcdir)/src/conf -I$(top_srcdir)/src/locking $(AM_CFLAGS)
 libvirt_security_manager_la_LDFLAGS = $(AM_LDFLAGS)
 libvirt_security_manager_la_LIBADD = $(SECDRIVER_LIBS)
 if WITH_SECDRIVER_SELINUX
@@ -2512,6 +2512,7 @@ libvirt_lxc_LDADD =			\
 		libvirt_security_manager.la \
 		libvirt_conf.la \
 		libvirt_util.la \
+		libvirt_driver.la \
 		../gnulib/lib/libgnu.la
 if WITH_DTRACE_PROBES
 libvirt_lxc_LDADD += libvirt_probes.lo
diff --git a/src/locking/lock_driver.h b/src/locking/lock_driver.h
index a7d9782..6bcb3cc 100644
--- a/src/locking/lock_driver.h
+++ b/src/locking/lock_driver.h
@@ -42,6 +42,8 @@ typedef enum {
 typedef enum {
     /* The managed object is a virtual guest domain */
     VIR_LOCK_MANAGER_OBJECT_TYPE_DOMAIN = 0,
+    /* The managed object is DAC driver label store file */
+    VIR_LOCK_MANAGER_OBJECT_TYPE_DAC = (1 << 0),
 } virLockManagerObjectType;
 
 typedef enum {
diff --git a/src/locking/lock_driver_lockd.c b/src/locking/lock_driver_lockd.c
index 1b92d68..53f8ed6 100644
--- a/src/locking/lock_driver_lockd.c
+++ b/src/locking/lock_driver_lockd.c
@@ -494,6 +494,31 @@ static int virLockManagerLockDaemonNew(virLockManagerPtr lock,
         }
         break;
 
+    case VIR_LOCK_MANAGER_OBJECT_TYPE_DAC:
+        for (i = 0; i < nparams; i++) {
+            if (STREQ(params[i].key, "name")) {
+                if (VIR_STRDUP(priv->name, params[i].value.str) < 0)
+                    return -1;
+            } else if (STREQ(params[i].key, "pid")) {
+                priv->pid = params[i].value.iv;
+            } else {
+                virReportError(VIR_ERR_INTERNAL_ERROR,
+                               _("Unexpected parameter %s for object"),
+                               params[i].key);
+            }
+        }
+        if (!priv->name) {
+            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                           _("Missing name parameter for DAC object"));
+            return -1;
+        }
+        if (priv->pid == 0) {
+            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                           _("Missing PID parameter for DAC object"));
+            return -1;
+        }
+        break;
+
     default:
         virReportError(VIR_ERR_INTERNAL_ERROR,
                        _("Unknown lock manager object type %d"),
diff --git a/src/lxc/lxc_controller.c b/src/lxc/lxc_controller.c
index 5ca960f..1a85ebc 100644
--- a/src/lxc/lxc_controller.c
+++ b/src/lxc/lxc_controller.c
@@ -2392,7 +2392,7 @@ int main(int argc, char *argv[])
 
     if (!(ctrl->securityManager = virSecurityManagerNew(securityDriver,
                                                         LXC_DRIVER_NAME,
-                                                        false, false, false)))
+                                                        false, false, false, NULL)))
         goto cleanup;
 
     if (ctrl->def->seclabels) {
diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c
index 0ab1ba2..9b4d3ff 100644
--- a/src/lxc/lxc_driver.c
+++ b/src/lxc/lxc_driver.c
@@ -1485,7 +1485,8 @@ lxcSecurityInit(virLXCDriverConfigPtr cfg)
                                                       LXC_DRIVER_NAME,
                                                       false,
                                                       cfg->securityDefaultConfined,
-                                                      cfg->securityRequireConfined);
+                                                      cfg->securityRequireConfined,
+                                                      NULL);
     if (!mgr)
         goto error;
 
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index ba470a1..25c1c57 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -338,7 +338,8 @@ qemuSecurityInit(virQEMUDriverPtr driver)
                                               QEMU_DRIVER_NAME,
                                               cfg->allowDiskFormatProbing,
                                               cfg->securityDefaultConfined,
-                                              cfg->securityRequireConfined)))
+                                              cfg->securityRequireConfined,
+                                              driver->lockManager)))
                 goto error;
             if (!stack) {
                 if (!(stack = virSecurityManagerNewStack(mgr)))
@@ -355,7 +356,8 @@ qemuSecurityInit(virQEMUDriverPtr driver)
                                           QEMU_DRIVER_NAME,
                                           cfg->allowDiskFormatProbing,
                                           cfg->securityDefaultConfined,
-                                          cfg->securityRequireConfined)))
+                                          cfg->securityRequireConfined,
+                                          driver->lockManager)))
             goto error;
         if (!(stack = virSecurityManagerNewStack(mgr)))
             goto error;
@@ -369,7 +371,8 @@ qemuSecurityInit(virQEMUDriverPtr driver)
                                              cfg->allowDiskFormatProbing,
                                              cfg->securityDefaultConfined,
                                              cfg->securityRequireConfined,
-                                             cfg->dynamicOwnership)))
+                                             cfg->dynamicOwnership,
+                                             driver->lockManager)))
             goto error;
         if (!stack) {
             if (!(stack = virSecurityManagerNewStack(mgr)))
diff --git a/src/security/security_dac.c b/src/security/security_dac.c
index b119825..5527287 100644
--- a/src/security/security_dac.c
+++ b/src/security/security_dac.c
@@ -35,6 +35,8 @@
 #include "virstring.h"
 #include "virutil.h"
 #include "configmake.h"
+#include "lock_driver.h"
+#include "lock_manager.h"
 
 #define VIR_FROM_THIS VIR_FROM_SECURITY
 #define SECURITY_DAC_NAME "dac"
@@ -50,6 +52,7 @@ struct _virSecurityDACData {
     bool dynamicOwnership;
     char *baselabel;
     char *labelStore;
+    virLockManagerPluginPtr plugin;
 };
 
 typedef struct _virDACLabel virDACLabel;
@@ -183,6 +186,75 @@ cleanup:
     return ret;
 }
 
+static int
+virSecurityDACLabelStoreLock(virSecurityDACDataPtr priv,
+                             bool lock)
+{
+    int ret = -1;
+    const unsigned int max_retries = 10;
+    unsigned int retries;
+    virLockManagerPtr lockMgr = NULL;
+    virLockManagerParam params[] = {
+        { .type = VIR_LOCK_MANAGER_PARAM_TYPE_STRING,
+            .key = "name",
+            .value = { .str = priv->labelStore },
+        },
+        { .type = VIR_LOCK_MANAGER_PARAM_TYPE_UINT,
+            .key = "pid",
+            .value = { .iv = getppid() },
+        },
+    };
+
+    if (!(lockMgr = virLockManagerNew(virLockManagerPluginGetDriver(priv->plugin),
+                                      VIR_LOCK_MANAGER_OBJECT_TYPE_DAC,
+                                      ARRAY_CARDINALITY(params),
+                                      params,
+                                      0)))
+        goto cleanup;
+
+    if (virLockManagerAddResource(lockMgr,
+                                  VIR_LOCK_MANAGER_RESOURCE_TYPE_DISK,
+                                  priv->labelStore,
+                                  0,
+                                  NULL,
+                                  0) < 0)
+        goto cleanup;
+
+    if (lock) {
+        for (retries = 0; retries < max_retries; retries++) {
+            struct timespec ts = { .tv_sec = 0, .tv_nsec = 50 * 1000 * 1000ull };
+            int rv;
+
+            rv = virLockManagerAcquire(lockMgr, NULL, 0,
+                                       VIR_DOMAIN_LOCK_FAILURE_IGNORE, NULL);
+
+            if (rv == 0)
+                break;
+
+            nanosleep(&ts, NULL);
+        }
+
+        if (retries == max_retries) {
+            virReportError(VIR_ERR_OPERATION_TIMEOUT,
+                           _("unable to lock %s"),
+                           priv->labelStore);
+            goto cleanup;
+        }
+    } else {
+        if (virLockManagerRelease(lockMgr, NULL, 0) < 0) {
+            virReportError(VIR_ERR_OPERATION_FAILED,
+                           _("unable to unlock %s"),
+                           priv->labelStore);
+            goto cleanup;
+        }
+    }
+
+    ret = 0;
+cleanup:
+    virLockManagerFree(lockMgr);
+    return ret;
+}
+
 /* returns -1 on error, 0 on success */
 int
 virSecurityDACSetUserAndGroup(virSecurityManagerPtr mgr,
@@ -350,6 +422,7 @@ virSecurityDACOpen(virSecurityManagerPtr mgr)
     if (VIR_STRDUP(priv->labelStore, LOCALSTATEDIR "/run/libvirt/labelStore.xml") < 0)
         return -1;
 
+    priv->plugin = virSecurityManagerGetLockPlugin(mgr);
     return 0;
 }
 
@@ -401,7 +474,9 @@ virSecurityDACRememberLabel(virSecurityManagerPtr mgr,
     struct stat sb;
     virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr);
 
-    /* TODO lock the labelStore file */
+    if (virSecurityDACLabelStoreLock(priv, true) < 0)
+        return ret;
+
     if (virSecurityDACLabelStoreParse(priv, &labels, &labels_size) < 0)
         goto cleanup;
 
@@ -433,7 +508,7 @@ virSecurityDACRememberLabel(virSecurityManagerPtr mgr,
 
     ret = 0;
 cleanup:
-    /* TODO unlock the labelStore file */
+    virSecurityDACLabelStoreLock(priv, false);
     virSecurityDACLabelStoreFree(labels, labels_size);
     return ret;
 }
@@ -450,7 +525,9 @@ virSecurityDACRecallLabel(virSecurityManagerPtr mgr,
     size_t labels_size = 0;
     virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr);
 
-    /* TODO lock the labelStore file */
+    if (virSecurityDACLabelStoreLock(priv, true) < 0)
+        return ret;
+
     if (virSecurityDACLabelStoreParse(priv, &labels, &labels_size) < 0)
         goto cleanup;
 
@@ -477,7 +554,7 @@ virSecurityDACRecallLabel(virSecurityManagerPtr mgr,
 
     ret = 0;
 cleanup:
-    /* TODO unlock the labelStore file */
+    virSecurityDACLabelStoreLock(priv, false);
     virSecurityDACLabelStoreFree(labels, labels_size);
     return ret;
 }
diff --git a/src/security/security_manager.c b/src/security/security_manager.c
index 5ecf72f..e5a67f2 100644
--- a/src/security/security_manager.c
+++ b/src/security/security_manager.c
@@ -43,6 +43,7 @@ struct _virSecurityManager {
     bool requireConfined;
     const char *virtDriver;
     void *privateData;
+    void *lockPlugin;
 };
 
 static virClassPtr virSecurityManagerClass;
@@ -66,7 +67,8 @@ static virSecurityManagerPtr virSecurityManagerNewDriver(virSecurityDriverPtr dr
                                                          const char *virtDriver,
                                                          bool allowDiskFormatProbing,
                                                          bool defaultConfined,
-                                                         bool requireConfined)
+                                                         bool requireConfined,
+                                                         void *lockPlugin)
 {
     virSecurityManagerPtr mgr;
     char *privateData;
@@ -94,6 +96,7 @@ static virSecurityManagerPtr virSecurityManagerNewDriver(virSecurityDriverPtr dr
     mgr->requireConfined = requireConfined;
     mgr->virtDriver = virtDriver;
     mgr->privateData = privateData;
+    mgr->lockPlugin = lockPlugin;
 
     if (drv->open(mgr) < 0) {
         virObjectUnref(mgr);
@@ -110,7 +113,8 @@ virSecurityManagerPtr virSecurityManagerNewStack(virSecurityManagerPtr primary)
                                     virSecurityManagerGetDriver(primary),
                                     virSecurityManagerGetAllowDiskFormatProbing(primary),
                                     virSecurityManagerGetDefaultConfined(primary),
-                                    virSecurityManagerGetRequireConfined(primary));
+                                    virSecurityManagerGetRequireConfined(primary),
+                                    virSecurityManagerGetLockPlugin(primary));
 
     if (!mgr)
         return NULL;
@@ -134,14 +138,16 @@ virSecurityManagerPtr virSecurityManagerNewDAC(const char *virtDriver,
                                                bool allowDiskFormatProbing,
                                                bool defaultConfined,
                                                bool requireConfined,
-                                               bool dynamicOwnership)
+                                               bool dynamicOwnership,
+                                               void *lockPlugin)
 {
     virSecurityManagerPtr mgr =
         virSecurityManagerNewDriver(&virSecurityDriverDAC,
                                     virtDriver,
                                     allowDiskFormatProbing,
                                     defaultConfined,
-                                    requireConfined);
+                                    requireConfined,
+                                    lockPlugin);
 
     if (!mgr)
         return NULL;
@@ -159,7 +165,8 @@ virSecurityManagerPtr virSecurityManagerNew(const char *name,
                                             const char *virtDriver,
                                             bool allowDiskFormatProbing,
                                             bool defaultConfined,
-                                            bool requireConfined)
+                                            bool requireConfined,
+                                            void *lockPlugin)
 {
     virSecurityDriverPtr drv = virSecurityDriverLookup(name, virtDriver);
     if (!drv)
@@ -189,7 +196,8 @@ virSecurityManagerPtr virSecurityManagerNew(const char *name,
                                        virtDriver,
                                        allowDiskFormatProbing,
                                        defaultConfined,
-                                       requireConfined);
+                                       requireConfined,
+                                       lockPlugin);
 }
 
 
@@ -229,6 +237,10 @@ void *virSecurityManagerGetPrivateData(virSecurityManagerPtr mgr)
     return mgr->privateData;
 }
 
+void *virSecurityManagerGetLockPlugin(virSecurityManagerPtr mgr)
+{
+    return mgr->lockPlugin;
+}
 
 static void virSecurityManagerDispose(void *obj)
 {
diff --git a/src/security/security_manager.h b/src/security/security_manager.h
index 81d3160..52b2ff0 100644
--- a/src/security/security_manager.h
+++ b/src/security/security_manager.h
@@ -33,7 +33,8 @@ virSecurityManagerPtr virSecurityManagerNew(const char *name,
                                             const char *virtDriver,
                                             bool allowDiskFormatProbing,
                                             bool defaultConfined,
-                                            bool requireConfined);
+                                            bool requireConfined,
+                                            void *lockPlugin);
 
 virSecurityManagerPtr virSecurityManagerNewStack(virSecurityManagerPtr primary);
 int virSecurityManagerStackAddNested(virSecurityManagerPtr stack,
@@ -45,12 +46,14 @@ virSecurityManagerPtr virSecurityManagerNewDAC(const char *virtDriver,
                                                bool allowDiskFormatProbing,
                                                bool defaultConfined,
                                                bool requireConfined,
-                                               bool dynamicOwnership);
+                                               bool dynamicOwnership,
+                                               void *lockPlugin);
 
 int virSecurityManagerPreFork(virSecurityManagerPtr mgr);
 void virSecurityManagerPostFork(virSecurityManagerPtr mgr);
 
 void *virSecurityManagerGetPrivateData(virSecurityManagerPtr mgr);
+void *virSecurityManagerGetLockPlugin(virSecurityManagerPtr mgr);
 
 const char *virSecurityManagerGetDriver(virSecurityManagerPtr mgr);
 const char *virSecurityManagerGetDOI(virSecurityManagerPtr mgr);
diff --git a/tests/qemuhotplugtest.c b/tests/qemuhotplugtest.c
index 8036adc..041cf36 100644
--- a/tests/qemuhotplugtest.c
+++ b/tests/qemuhotplugtest.c
@@ -353,7 +353,7 @@ mymain(void)
     if (!driver.lockManager)
         return EXIT_FAILURE;
 
-    if (!(mgr = virSecurityManagerNew("none", "qemu", false, false, false)))
+    if (!(mgr = virSecurityManagerNew("none", "qemu", false, false, false, NULL)))
         return EXIT_FAILURE;
     if (!(driver.securityManager = virSecurityManagerNewStack(mgr)))
         return EXIT_FAILURE;
diff --git a/tests/seclabeltest.c b/tests/seclabeltest.c
index cd34b6b..e21a8c1 100644
--- a/tests/seclabeltest.c
+++ b/tests/seclabeltest.c
@@ -17,7 +17,7 @@ main(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED)
     if (virThreadInitialize() < 0)
         return EXIT_FAILURE;
 
-    mgr = virSecurityManagerNew(NULL, "QEMU", false, true, false);
+    mgr = virSecurityManagerNew(NULL, "QEMU", false, true, false, NULL);
     if (mgr == NULL) {
         fprintf(stderr, "Failed to start security driver");
         return EXIT_FAILURE;
diff --git a/tests/securityselinuxlabeltest.c b/tests/securityselinuxlabeltest.c
index 3505f8c..8bd2a5b 100644
--- a/tests/securityselinuxlabeltest.c
+++ b/tests/securityselinuxlabeltest.c
@@ -320,7 +320,8 @@ mymain(void)
 {
     int ret = 0;
 
-    if (!(mgr = virSecurityManagerNew("selinux", "QEMU", false, true, false))) {
+    if (!(mgr = virSecurityManagerNew("selinux", "QEMU", false,
+                                      true, false, NULL))) {
         virErrorPtr err = virGetLastError();
         fprintf(stderr, "Unable to initialize security driver: %s\n",
                 err->message);
diff --git a/tests/securityselinuxtest.c b/tests/securityselinuxtest.c
index feb5366..99980f4 100644
--- a/tests/securityselinuxtest.c
+++ b/tests/securityselinuxtest.c
@@ -270,7 +270,7 @@ mymain(void)
     int ret = 0;
     virSecurityManagerPtr mgr;
 
-    if (!(mgr = virSecurityManagerNew("selinux", "QEMU", false, true, false))) {
+    if (!(mgr = virSecurityManagerNew("selinux", "QEMU", false, true, false, NULL))) {
         virErrorPtr err = virGetLastError();
         fprintf(stderr, "Unable to initialize security driver: %s\n",
                 err->message);
-- 
1.9.0




More information about the libvir-list mailing list