[libvirt] [PATCH 5/7] Update QEMU driver to support multiple security drivers

Marcelo Cerri mhcerri at linux.vnet.ibm.com
Mon May 21 13:39:27 UTC 2012


---
 src/driver.h            |    8 ++-
 src/qemu/qemu_conf.c    |   33 ++++++++
 src/qemu/qemu_conf.h    |    1 +
 src/qemu/qemu_driver.c  |  196 ++++++++++++++++++++++++++++++++++++++---------
 src/qemu/qemu_process.c |   53 +++++++++----
 5 files changed, 236 insertions(+), 55 deletions(-)

diff --git a/src/driver.h b/src/driver.h
index 03d249b..ca4927f 100644
--- a/src/driver.h
+++ b/src/driver.h
@@ -305,11 +305,14 @@ typedef int
                                          int maplen);
 typedef int
         (*virDrvDomainGetMaxVcpus)	(virDomainPtr domain);
-
 typedef int
-        (*virDrvDomainGetSecurityLabel)	(virDomainPtr domain,
+        (*virDrvDomainGetSecurityLabel) (virDomainPtr domain,
                                          virSecurityLabelPtr seclabel);
 typedef int
+        (*virDrvDomainGetSecurityLabelList) (virDomainPtr domain,
+                                         virSecurityLabelPtr seclabels,
+                                         int nseclabels);
+typedef int
         (*virDrvNodeGetSecurityModel)	(virConnectPtr conn,
                                          virSecurityModelPtr secmodel);
 typedef int
@@ -911,6 +914,7 @@ struct _virDriver {
     virDrvDomainGetVcpus		domainGetVcpus;
     virDrvDomainGetMaxVcpus		domainGetMaxVcpus;
     virDrvDomainGetSecurityLabel     domainGetSecurityLabel;
+    virDrvDomainGetSecurityLabelList     domainGetSecurityLabelList;
     virDrvNodeGetSecurityModel  nodeGetSecurityModel;
     virDrvDomainGetXMLDesc		domainGetXMLDesc;
     virDrvConnectDomainXMLFromNative domainXMLFromNative;
diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c
index 88a04bc..5cc2071 100644
--- a/src/qemu/qemu_conf.c
+++ b/src/qemu/qemu_conf.c
@@ -202,6 +202,39 @@ int qemudLoadDriverConfig(struct qemud_driver *driver,
         }
     }
 
+    p = virConfGetValue (conf, "additional_security_drivers");
+    CHECK_TYPE ("additional_security_driver", VIR_CONF_STRING);
+    if (p && p->str) {
+        char *it, *tok;
+        size_t len;
+
+        for (len = 1, it = p->str; *it; it++)
+            len++;
+        if (VIR_ALLOC_N(driver->additionalSecurityDriverNames, len + 1) < 0) {
+            virReportOOMError();
+            virConfFree(conf);
+            return -1;
+        }
+
+        i = 0;
+        tok = it = p->str;
+        while (1) {
+            if (*it == ',' || *it == '\0') {
+                driver->additionalSecurityDriverNames[i] = strndup(tok, it - tok);
+                if (driver->additionalSecurityDriverNames == NULL) {
+                    virReportOOMError();
+                    virConfFree(conf);
+                    return -1;
+                }
+                tok = it + 1;
+                i++;
+            }
+            if (*it == '\0')
+                break;
+            it++;
+        }
+    }
+
     p = virConfGetValue (conf, "security_default_confined");
     CHECK_TYPE ("security_default_confined", VIR_CONF_LONG);
     if (p) driver->securityDefaultConfined = p->l;
diff --git a/src/qemu/qemu_conf.h b/src/qemu/qemu_conf.h
index 482e6d3..a5867b6 100644
--- a/src/qemu/qemu_conf.h
+++ b/src/qemu/qemu_conf.h
@@ -117,6 +117,7 @@ struct qemud_driver {
     virDomainEventStatePtr domainEventState;
 
     char *securityDriverName;
+    char **additionalSecurityDriverNames;
     bool securityDefaultConfined;
     bool securityRequireConfined;
     virSecurityManagerPtr securityManager;
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index efbc421..39d9eee 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -214,36 +214,84 @@ qemuAutostartDomains(struct qemud_driver *driver)
 static int
 qemuSecurityInit(struct qemud_driver *driver)
 {
-    virSecurityManagerPtr mgr = virSecurityManagerNew(driver->securityDriverName,
-                                                      QEMU_DRIVER_NAME,
-                                                      driver->allowDiskFormatProbing,
-                                                      driver->securityDefaultConfined,
-                                                      driver->securityRequireConfined);
-
+    char **names;
+    virSecurityManagerPtr mgr, nested, stack;
+
+    /* Create primary driver */
+    mgr = virSecurityManagerNew(driver->securityDriverName,
+                                QEMU_DRIVER_NAME,
+                                driver->allowDiskFormatProbing,
+                                driver->securityDefaultConfined,
+                                driver->securityRequireConfined);
     if (!mgr)
         goto error;
 
-    if (driver->privileged) {
-        virSecurityManagerPtr dac = virSecurityManagerNewDAC(QEMU_DRIVER_NAME,
-                                                             driver->user,
-                                                             driver->group,
-                                                             driver->allowDiskFormatProbing,
-                                                             driver->securityDefaultConfined,
-                                                             driver->securityRequireConfined,
-                                                             driver->dynamicOwnership);
-        if (!dac)
+    /* If a DAC driver is required or additional drivers are provived, a stack
+     * driver should be create to group them all */
+    if (driver->privileged || driver->additionalSecurityDriverNames) {
+        stack = virSecurityManagerNewStack(mgr);
+        if (!stack)
             goto error;
+        mgr = stack;
+    }
+
+    /* Loop through additional driver names and add a secudary driver to each
+     * one */
+    if (driver->additionalSecurityDriverNames) {
+        names = driver->additionalSecurityDriverNames;
+        while (names && *names) {
+            if (STREQ("dac", *names)) {
+                /* A DAC driver has specic parameters */
+                nested = virSecurityManagerNewDAC(QEMU_DRIVER_NAME,
+                                                  driver->user,
+                                                  driver->group,
+                                                  driver->allowDiskFormatProbing,
+                                                  driver->securityDefaultConfined,
+                                                  driver->securityRequireConfined,
+                                                  driver->dynamicOwnership);
+            } else {
+                nested = virSecurityManagerNew(*names,
+                                               QEMU_DRIVER_NAME,
+                                               driver->allowDiskFormatProbing,
+                                               driver->securityDefaultConfined,
+                                               driver->securityRequireConfined);
+            }
+            if (nested == NULL)
+                goto error;
+            if (virSecurityManagerStackAddNested(stack, nested))
+                goto error;
+            names++;
+        }
+    }
 
-        if (!(driver->securityManager = virSecurityManagerNewStack(mgr,
-                                                                   dac))) {
-
-            virSecurityManagerFree(dac);
-            goto error;
+    if (driver->privileged) {
+        /* When a DAC driver is required, check if there is already one in the
+         * additional drivers */
+        names = driver->additionalSecurityDriverNames;
+        while (names && *names) {
+            if (STREQ("dac", *names)) {
+               break;
+            }
+            names++;
+        }
+        /* If there isn't a DAC driver, create a new one and add it to the stack
+         * manager */
+        if (names == NULL || *names == NULL) {
+            nested = virSecurityManagerNewDAC(QEMU_DRIVER_NAME,
+                                              driver->user,
+                                              driver->group,
+                                              driver->allowDiskFormatProbing,
+                                              driver->securityDefaultConfined,
+                                              driver->securityRequireConfined,
+                                              driver->dynamicOwnership);
+            if (nested == NULL)
+                goto error;
+            if (virSecurityManagerStackAddNested(stack, nested))
+                goto error;
         }
-    } else {
-        driver->securityManager = mgr;
     }
 
+    driver->securityManager = mgr;
     return 0;
 
 error:
@@ -257,7 +305,11 @@ static virCapsPtr
 qemuCreateCapabilities(virCapsPtr oldcaps,
                        struct qemud_driver *driver)
 {
+    size_t i;
     virCapsPtr caps;
+    virSecurityManagerPtr *sec_managers = NULL;
+    /* Security driver data */
+    const char *doi, *model;
 
     /* Basic host arch / guest machine capabilities */
     if (!(caps = qemuCapsInit(oldcaps))) {
@@ -282,26 +334,38 @@ qemuCreateCapabilities(virCapsPtr oldcaps,
         goto err_exit;
     }
 
-    /* Security driver data */
-    const char *doi, *model;
+    /* access sec drivers and create a sec model to each one */
+    sec_managers = virSecurityManagerGetNested(driver->securityManager);
+    if (sec_managers == NULL) {
+        goto err_exit;
+    }
+
+    /* calculate length */
+    for (i = 0; sec_managers[i]; i++)
+        ;
+    caps->host.nsecModels = i;
 
-    doi = virSecurityManagerGetDOI(driver->securityManager);
-    model = virSecurityManagerGetModel(driver->securityManager);
-    if (STRNEQ(model, "none")) {
-        if (!(caps->host.secModel.model = strdup(model)))
+    if (VIR_ALLOC_N(caps->host.secModels, caps->host.nsecModels) < 0)
+        goto no_memory;
+
+    for (i = 0; sec_managers[i]; i++) {
+        doi = virSecurityManagerGetDOI(sec_managers[i]);
+        model = virSecurityManagerGetModel(sec_managers[i]);
+        if (!(caps->host.secModels[i].model = strdup(model)))
             goto no_memory;
-        if (!(caps->host.secModel.doi = strdup(doi)))
+        if (!(caps->host.secModels[i].doi = strdup(doi)))
             goto no_memory;
+        VIR_DEBUG("Initialized caps for security driver \"%s\" with "
+                  "DOI \"%s\"", model, doi);
     }
-
-    VIR_DEBUG("Initialized caps for security driver \"%s\" with "
-              "DOI \"%s\"", model, doi);
+    VIR_FREE(sec_managers);
 
     return caps;
 
 no_memory:
     virReportOOMError();
 err_exit:
+    VIR_FREE(sec_managers);
     virCapabilitiesFree(caps);
     return NULL;
 }
@@ -3958,6 +4022,63 @@ cleanup:
     return ret;
 }
 
+static int qemudDomainGetSecurityLabelList(virDomainPtr dom,
+                                           virSecurityLabelPtr seclabel,
+                                           int nseclabels)
+{
+    struct qemud_driver *driver = (struct qemud_driver *)dom->conn->privateData;
+    virDomainObjPtr vm;
+    int i, ret = -1;
+
+    qemuDriverLock(driver);
+    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
+
+    memset(seclabel, 0, sizeof(*seclabel));
+
+    if (!vm) {
+        char uuidstr[VIR_UUID_STRING_BUFLEN];
+        virUUIDFormat(dom->uuid, uuidstr);
+        qemuReportError(VIR_ERR_NO_DOMAIN,
+                        _("no domain with matching uuid '%s'"), uuidstr);
+        goto cleanup;
+    }
+
+    if (!virDomainVirtTypeToString(vm->def->virtType)) {
+        qemuReportError(VIR_ERR_INTERNAL_ERROR,
+                        _("unknown virt type in domain definition '%d'"),
+                        vm->def->virtType);
+        goto cleanup;
+    }
+
+    /*
+     * Check the comment in qemudDomainGetSecurityLabel function.
+     */
+    if (virDomainObjIsActive(vm)) {
+        virSecurityManagerPtr* mgrs = virSecurityManagerGetNested(
+                                            driver->securityManager);
+        if (!mgrs)
+            goto cleanup;
+
+        for (i = 0; mgrs[i] && i < nseclabels; i++) {
+            if (virSecurityManagerGetProcessLabel(mgrs[i], vm->def, vm->pid,
+                                                  seclabel) < 0) {
+                qemuReportError(VIR_ERR_INTERNAL_ERROR,
+                                "%s", _("Failed to get security label"));
+                VIR_FREE(mgrs);
+                goto cleanup;
+            }
+        }
+        VIR_FREE(mgrs);
+    }
+
+    ret = 0;
+
+cleanup:
+    if (vm)
+        virDomainObjUnlock(vm);
+    qemuDriverUnlock(driver);
+    return ret;
+}
 static int qemudNodeGetSecurityModel(virConnectPtr conn,
                                      virSecurityModelPtr secmodel)
 {
@@ -3968,12 +4089,12 @@ static int qemudNodeGetSecurityModel(virConnectPtr conn,
     qemuDriverLock(driver);
     memset(secmodel, 0, sizeof(*secmodel));
 
-    /* NULL indicates no driver, which we treat as
-     * success, but simply return no data in *secmodel */
-    if (driver->caps->host.secModel.model == NULL)
+    /* We treat no driver as success, but simply return no data in *secmodel */
+    if (driver->caps->host.nsecModels == 0 ||
+        driver->caps->host.secModels[0].model == NULL)
         goto cleanup;
 
-    p = driver->caps->host.secModel.model;
+    p = driver->caps->host.secModels[0].model;
     if (strlen(p) >= VIR_SECURITY_MODEL_BUFLEN-1) {
         qemuReportError(VIR_ERR_INTERNAL_ERROR,
                         _("security model string exceeds max %d bytes"),
@@ -3983,7 +4104,7 @@ static int qemudNodeGetSecurityModel(virConnectPtr conn,
     }
     strcpy(secmodel->model, p);
 
-    p = driver->caps->host.secModel.doi;
+    p = driver->caps->host.secModels[0].doi;
     if (strlen(p) >= VIR_SECURITY_DOI_BUFLEN-1) {
         qemuReportError(VIR_ERR_INTERNAL_ERROR,
                         _("security DOI string exceeds max %d bytes"),
@@ -13004,6 +13125,7 @@ static virDriver qemuDriver = {
     .domainGetVcpus = qemudDomainGetVcpus, /* 0.4.4 */
     .domainGetMaxVcpus = qemudDomainGetMaxVcpus, /* 0.4.4 */
     .domainGetSecurityLabel = qemudDomainGetSecurityLabel, /* 0.6.1 */
+    .domainGetSecurityLabelList = qemudDomainGetSecurityLabelList, /* ? */
     .nodeGetSecurityModel = qemudNodeGetSecurityModel, /* 0.6.1 */
     .domainGetXMLDesc = qemuDomainGetXMLDesc, /* 0.2.0 */
     .domainXMLFromNative = qemuDomainXMLFromNative, /* 0.6.4 */
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
index 58ba5bf..59c7e0d 100644
--- a/src/qemu/qemu_process.c
+++ b/src/qemu/qemu_process.c
@@ -3979,12 +3979,12 @@ void qemuProcessStop(struct qemud_driver *driver,
     virSecurityManagerReleaseLabel(driver->securityManager, vm->def);
 
     /* Clear out dynamically assigned labels */
-    if (vm->def->seclabel.type == VIR_DOMAIN_SECLABEL_DYNAMIC) {
-        if (!vm->def->seclabel.baselabel)
-            VIR_FREE(vm->def->seclabel.model);
-        VIR_FREE(vm->def->seclabel.label);
+    for (i = 0; i < vm->def->nseclabels; i++) {
+        if (vm->def->seclabels[i]->type == VIR_DOMAIN_SECLABEL_DYNAMIC) {
+            VIR_FREE(vm->def->seclabels[i]->label);
+        }
+        VIR_FREE(vm->def->seclabels[i]->imagelabel);
     }
-    VIR_FREE(vm->def->seclabel.imagelabel);
 
     virDomainDefClearDeviceAliases(vm->def);
     if (!priv->persistentAddrs) {
@@ -4088,6 +4088,7 @@ int qemuProcessAttach(virConnectPtr conn ATTRIBUTE_UNUSED,
                       virDomainChrSourceDefPtr monConfig,
                       bool monJSON)
 {
+    size_t i;
     char ebuf[1024];
     int logfile = -1;
     char *timestamp;
@@ -4095,6 +4096,9 @@ int qemuProcessAttach(virConnectPtr conn ATTRIBUTE_UNUSED,
     bool running = true;
     virDomainPausedReason reason;
     virSecurityLabelPtr seclabel = NULL;
+    virSecurityLabelDefPtr seclabeldef = NULL;
+    virSecurityManagerPtr* sec_managers;
+    const char *model;
 
     VIR_DEBUG("Beginning VM attach process");
 
@@ -4127,17 +4131,35 @@ int qemuProcessAttach(virConnectPtr conn ATTRIBUTE_UNUSED,
         goto no_memory;
 
     VIR_DEBUG("Detect security driver config");
-    vm->def->seclabel.type = VIR_DOMAIN_SECLABEL_STATIC;
-    if (VIR_ALLOC(seclabel) < 0)
-        goto no_memory;
-    if (virSecurityManagerGetProcessLabel(driver->securityManager,
-                                          vm->def, vm->pid, seclabel) < 0)
+    sec_managers = virSecurityManagerGetNested(driver->securityManager);
+    if (sec_managers == NULL) {
         goto cleanup;
-    if (driver->caps->host.secModel.model &&
-        !(vm->def->seclabel.model = strdup(driver->caps->host.secModel.model)))
-        goto no_memory;
-    if (!(vm->def->seclabel.label = strdup(seclabel->label)))
-        goto no_memory;
+    }
+
+    for (i = 0; sec_managers[i]; i++) {
+        model = virSecurityManagerGetModel(sec_managers[i]);
+        seclabeldef = virDomainDefGetSecurityLabelDef(vm->def, model);
+        if (seclabeldef == NULL) {
+            goto cleanup;
+        }
+        seclabeldef->type = VIR_DOMAIN_SECLABEL_STATIC;
+        if (VIR_ALLOC(seclabel) < 0)
+            goto no_memory;
+        if (virSecurityManagerGetProcessLabel(driver->securityManager,
+                                              vm->def, vm->pid, seclabel) < 0)
+            goto cleanup;
+
+        //if (driver->caps->host.secModel.model &&
+        //    !(seclabeldef.model = strdup(driver->caps->host.secModel.model)))
+        //    goto no_memory;
+        if (!(seclabeldef->model = strdup(model)))
+            goto no_memory;
+
+        if (!(seclabeldef->label = strdup(seclabel->label)))
+            goto no_memory;
+        VIR_FREE(seclabel);
+        seclabel = NULL;
+    }
 
     VIR_DEBUG("Creating domain log file");
     if ((logfile = qemuDomainCreateLog(driver, vm, false)) < 0)
@@ -4256,7 +4278,6 @@ int qemuProcessAttach(virConnectPtr conn ATTRIBUTE_UNUSED,
         goto cleanup;
 
     VIR_FORCE_CLOSE(logfile);
-    VIR_FREE(seclabel);
 
     return 0;
 
-- 
1.7.1




More information about the libvir-list mailing list