[libvirt] [PATCH v2 3/5] Update security layer to handle many security labels

Marcelo Cerri mhcerri at linux.vnet.ibm.com
Wed Jul 18 01:28:36 UTC 2012


These changes make the security drivers able to find and handle the
correct security label information when more than one label is
available. They also update the DAC driver to be used as an usual
security driver.

 Please enter the commit message for your changes. Lines starting
---
 src/libvirt_private.syms         |    3 +
 src/qemu/qemu_driver.c           |   45 ++++--
 src/qemu/qemu_process.c          |   53 +++++--
 src/security/security_apparmor.c |  112 ++++++++++----
 src/security/security_dac.c      |  320 ++++++++++++++++++++++++++++++++++----
 src/security/security_manager.c  |   98 +++++++++---
 src/security/security_manager.h  |    8 +-
 src/security/security_selinux.c  |  249 +++++++++++++++++++++---------
 src/security/security_stack.c    |  237 +++++++++++++++++++---------
 src/security/security_stack.h    |   13 ++
 10 files changed, 872 insertions(+), 266 deletions(-)

diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 03f7f3e..758f219 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -281,6 +281,7 @@ virDomainDefClearPCIAddresses;
 virDomainDefFormat;
 virDomainDefFormatInternal;
 virDomainDefFree;
+virDomainDefGetSecurityLabelDef;
 virDomainDefParseFile;
 virDomainDefParseNode;
 virDomainDefParseString;
@@ -968,6 +969,7 @@ virSecurityManagerClearSocketLabel;
 virSecurityManagerFree;
 virSecurityManagerGenLabel;
 virSecurityManagerGetDOI;
+virSecurityManagerGetNested;
 virSecurityManagerGetModel;
 virSecurityManagerGetProcessLabel;
 virSecurityManagerNew;
@@ -987,6 +989,7 @@ virSecurityManagerSetHostdevLabel;
 virSecurityManagerSetProcessLabel;
 virSecurityManagerSetSavedStateLabel;
 virSecurityManagerSetSocketLabel;
+virSecurityManagerStackAddNested;
 virSecurityManagerVerify;
 virSecurityManagerGetMountOptions;
 
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index a512a45..1b02f28 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -240,8 +240,8 @@ qemuSecurityInit(struct qemud_driver *driver)
         if (!dac)
             goto error;
 
-        if (!(driver->securityManager = virSecurityManagerNewStack(mgr,
-                                                                   dac))) {
+        if (!(driver->securityManager = virSecurityManagerNewStack(mgr)) ||
+            !(virSecurityManagerStackAddNested(mgr, dac))) {
 
             virSecurityManagerFree(dac);
             goto error;
@@ -263,7 +263,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))) {
@@ -288,31 +292,38 @@ qemuCreateCapabilities(virCapsPtr oldcaps,
         goto err_exit;
     }
 
-    /* Security driver data */
-    const char *doi, *model;
+    /* access sec drivers and create a sec model for each one */
+    sec_managers = virSecurityManagerGetNested(driver->securityManager);
+    if (sec_managers == NULL) {
+        goto err_exit;
+    }
 
-    doi = virSecurityManagerGetDOI(driver->securityManager);
-    model = virSecurityManagerGetModel(driver->securityManager);
+    /* calculate length */
+    for (i = 0; sec_managers[i]; i++)
+        ;
+    caps->host.nsecModels = i;
 
-    if (VIR_ALLOC(caps->host.secModels) < 0) {
+    if (VIR_ALLOC_N(caps->host.secModels, caps->host.nsecModels) < 0)
         goto no_memory;
-    }
 
-    if (STRNEQ(model, "none")) {
-        if (!(caps->host.secModels[0].model = strdup(model)))
+    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.secModels[0].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;
 }
@@ -4035,9 +4046,9 @@ 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.secModels[0].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.secModels[0].model;
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
index e9a41df..7fbe412 100644
--- a/src/qemu/qemu_process.c
+++ b/src/qemu/qemu_process.c
@@ -4079,12 +4079,12 @@ void qemuProcessStop(struct qemud_driver *driver,
     virSecurityManagerReleaseLabel(driver->securityManager, vm->def);
 
     /* Clear out dynamically assigned labels */
-    if (vm->def->seclabels[0]->type == VIR_DOMAIN_SECLABEL_DYNAMIC) {
-        if (!vm->def->seclabels[0]->baselabel)
-            VIR_FREE(vm->def->seclabels[0]->model);
-        VIR_FREE(vm->def->seclabels[0]->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->seclabels[0]->imagelabel);
 
     virDomainDefClearDeviceAliases(vm->def);
     if (!priv->persistentAddrs) {
@@ -4188,6 +4188,7 @@ int qemuProcessAttach(virConnectPtr conn ATTRIBUTE_UNUSED,
                       virDomainChrSourceDefPtr monConfig,
                       bool monJSON)
 {
+    size_t i;
     char ebuf[1024];
     int logfile = -1;
     char *timestamp;
@@ -4195,6 +4196,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");
 
@@ -4227,17 +4231,35 @@ int qemuProcessAttach(virConnectPtr conn ATTRIBUTE_UNUSED,
         goto no_memory;
 
     VIR_DEBUG("Detect security driver config");
-    vm->def->seclabels[0]->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.secModels[0].model &&
-        !(vm->def->seclabels[0]->model = strdup(driver->caps->host.secModels[0].model)))
-        goto no_memory;
-    if (!(vm->def->seclabels[0]->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)
@@ -4359,7 +4381,6 @@ int qemuProcessAttach(virConnectPtr conn ATTRIBUTE_UNUSED,
     }
 
     VIR_FORCE_CLOSE(logfile);
-    VIR_FREE(seclabel);
 
     return 0;
 
diff --git a/src/security/security_apparmor.c b/src/security/security_apparmor.c
index 62af3c6..8639e16 100644
--- a/src/security/security_apparmor.c
+++ b/src/security/security_apparmor.c
@@ -262,9 +262,13 @@ reload_profile(virSecurityManagerPtr mgr,
                const char *fn,
                bool append)
 {
-    const virSecurityLabelDefPtr secdef = &def->seclabel;
     int rc = -1;
     char *profile_name = NULL;
+    const virSecurityLabelDefPtr secdef = virDomainDefGetSecurityLabelDef(
+                                                def, SECURITY_APPARMOR_NAME);
+
+    if (!secdef)
+        return rc;
 
     if (secdef->norelabel)
         return 0;
@@ -298,7 +302,12 @@ AppArmorSetSecurityUSBLabel(usbDevice *dev ATTRIBUTE_UNUSED,
     virDomainDefPtr def = ptr->def;
 
     if (reload_profile(ptr->mgr, def, file, true) < 0) {
-        const virSecurityLabelDefPtr secdef = &def->seclabel;
+        const virSecurityLabelDefPtr secdef = virDomainDefGetSecurityLabelDef(
+                                                def, SECURITY_APPARMOR_NAME);
+        if (!secdef) {
+            virReportOOMError();
+            return -1;
+        }
         virSecurityReportError(VIR_ERR_INTERNAL_ERROR,
                                _("cannot update AppArmor profile "
                                  "\'%s\'"),
@@ -316,7 +325,12 @@ AppArmorSetSecurityPCILabel(pciDevice *dev ATTRIBUTE_UNUSED,
     virDomainDefPtr def = ptr->def;
 
     if (reload_profile(ptr->mgr, def, file, true) < 0) {
-        const virSecurityLabelDefPtr secdef = &def->seclabel;
+        const virSecurityLabelDefPtr secdef = virDomainDefGetSecurityLabelDef(
+                                                def, SECURITY_APPARMOR_NAME);
+        if (!secdef) {
+            virReportOOMError();
+            return -1;
+        }
         virSecurityReportError(VIR_ERR_INTERNAL_ERROR,
                                _("cannot update AppArmor profile "
                                  "\'%s\'"),
@@ -398,18 +412,23 @@ AppArmorGenSecurityLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
 {
     int rc = -1;
     char *profile_name = NULL;
+    virSecurityLabelDefPtr secdef = virDomainDefGetSecurityLabelDef(def,
+                                                SECURITY_APPARMOR_NAME);
 
-    if (def->seclabel.type == VIR_DOMAIN_SECLABEL_STATIC)
+    if (!secdef)
+        return -1;
+
+    if (secdef->type == VIR_DOMAIN_SECLABEL_STATIC)
         return 0;
 
-    if (def->seclabel.baselabel) {
+    if (secdef->baselabel) {
         virSecurityReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                                "%s", _("Cannot set a base label with AppArmour"));
         return rc;
     }
 
-    if ((def->seclabel.label) ||
-        (def->seclabel.model) || (def->seclabel.imagelabel)) {
+    if ((secdef->label) ||
+        (secdef->model) || (secdef->imagelabel)) {
         virSecurityReportError(VIR_ERR_INTERNAL_ERROR,
                                "%s",
                                _("security label already defined for VM"));
@@ -419,31 +438,31 @@ AppArmorGenSecurityLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
     if ((profile_name = get_profile_name(def)) == NULL)
         return rc;
 
-    def->seclabel.label = strndup(profile_name, strlen(profile_name));
-    if (!def->seclabel.label) {
+    secdef->label = strndup(profile_name, strlen(profile_name));
+    if (!secdef->label) {
         virReportOOMError();
         goto clean;
     }
 
     /* set imagelabel the same as label (but we won't use it) */
-    def->seclabel.imagelabel = strndup(profile_name,
-                                           strlen(profile_name));
-    if (!def->seclabel.imagelabel) {
+    secdef->imagelabel = strndup(profile_name,
+                                 strlen(profile_name));
+    if (!secdef->imagelabel) {
         virReportOOMError();
         goto err;
     }
 
-    def->seclabel.model = strdup(SECURITY_APPARMOR_NAME);
-    if (!def->seclabel.model) {
+    secdef->model = strdup(SECURITY_APPARMOR_NAME);
+    if (!secdef->model) {
         virReportOOMError();
         goto err;
     }
 
     /* Now that we have a label, load the profile into the kernel. */
-    if (load_profile(mgr, def->seclabel.label, def, NULL, false) < 0) {
+    if (load_profile(mgr, secdef->label, def, NULL, false) < 0) {
         virSecurityReportError(VIR_ERR_INTERNAL_ERROR,
                                _("cannot load AppArmor profile "
-                               "\'%s\'"), def->seclabel.label);
+                               "\'%s\'"), secdef->label);
         goto err;
     }
 
@@ -451,9 +470,9 @@ AppArmorGenSecurityLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
     goto clean;
 
   err:
-    VIR_FREE(def->seclabel.label);
-    VIR_FREE(def->seclabel.imagelabel);
-    VIR_FREE(def->seclabel.model);
+    VIR_FREE(secdef->label);
+    VIR_FREE(secdef->imagelabel);
+    VIR_FREE(secdef->model);
 
   clean:
     VIR_FREE(profile_name);
@@ -465,7 +484,12 @@ static int
 AppArmorSetSecurityAllLabel(virSecurityManagerPtr mgr,
                             virDomainDefPtr def, const char *stdin_path)
 {
-    if (def->seclabel.norelabel)
+    virSecurityLabelDefPtr secdef = virDomainDefGetSecurityLabelDef(def,
+                                                    SECURITY_APPARMOR_NAME);
+    if (!secdef)
+        return -1;
+
+    if (secdef->norelabel)
         return 0;
 
     /* Reload the profile if stdin_path is specified. Note that
@@ -518,7 +542,10 @@ static int
 AppArmorReleaseSecurityLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
                              virDomainDefPtr def)
 {
-    const virSecurityLabelDefPtr secdef = &def->seclabel;
+    const virSecurityLabelDefPtr secdef = virDomainDefGetSecurityLabelDef(def,
+                                                        SECURITY_APPARMOR_NAME);
+    if (!secdef)
+        return -1;
 
     VIR_FREE(secdef->model);
     VIR_FREE(secdef->label);
@@ -533,8 +560,12 @@ AppArmorRestoreSecurityAllLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
                                 virDomainDefPtr def,
                                 int migrated ATTRIBUTE_UNUSED)
 {
-    const virSecurityLabelDefPtr secdef = &def->seclabel;
     int rc = 0;
+    const virSecurityLabelDefPtr secdef =
+        virDomainDefGetSecurityLabelDef(def, SECURITY_APPARMOR_NAME);
+
+    if (!secdef)
+        return -1;
 
     if (secdef->type == VIR_DOMAIN_SECLABEL_DYNAMIC) {
         if ((rc = remove_profile(secdef->label)) != 0) {
@@ -552,9 +583,13 @@ AppArmorRestoreSecurityAllLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
 static int
 AppArmorSetSecurityProcessLabel(virSecurityManagerPtr mgr, virDomainDefPtr def)
 {
-    const virSecurityLabelDefPtr secdef = &def->seclabel;
     int rc = -1;
     char *profile_name = NULL;
+    const virSecurityLabelDefPtr secdef =
+        virDomainDefGetSecurityLabelDef(def, SECURITY_APPARMOR_NAME);
+
+    if (!secdef)
+        return -1;
 
     if ((profile_name = get_profile_name(def)) == NULL)
         return rc;
@@ -621,9 +656,13 @@ static int
 AppArmorSetSecurityImageLabel(virSecurityManagerPtr mgr,
                               virDomainDefPtr def, virDomainDiskDefPtr disk)
 {
-    const virSecurityLabelDefPtr secdef = &def->seclabel;
     int rc = -1;
     char *profile_name;
+    const virSecurityLabelDefPtr secdef =
+        virDomainDefGetSecurityLabelDef(def, SECURITY_APPARMOR_NAME);
+
+    if (!secdef)
+        return -1;
 
     if (secdef->norelabel)
         return 0;
@@ -666,7 +705,11 @@ static int
 AppArmorSecurityVerify(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
                        virDomainDefPtr def)
 {
-    const virSecurityLabelDefPtr secdef = &def->seclabel;
+    const virSecurityLabelDefPtr secdef =
+        virDomainDefGetSecurityLabelDef(def, SECURITY_APPARMOR_NAME);
+
+    if (!secdef)
+        return -1;
 
     if (secdef->type == VIR_DOMAIN_SECLABEL_STATIC) {
         if (use_apparmor() < 0 || profile_status(secdef->label, 0) < 0) {
@@ -694,9 +737,13 @@ AppArmorSetSecurityHostdevLabel(virSecurityManagerPtr mgr,
                                 virDomainHostdevDefPtr dev)
 
 {
-    const virSecurityLabelDefPtr secdef = &def->seclabel;
     struct SDPDOP *ptr;
     int ret = -1;
+    const virSecurityLabelDefPtr secdef =
+        virDomainDefGetSecurityLabelDef(def, SECURITY_APPARMOR_NAME);
+
+    if (!secdef)
+        return -1;
 
     if (secdef->norelabel)
         return 0;
@@ -756,7 +803,12 @@ AppArmorRestoreSecurityHostdevLabel(virSecurityManagerPtr mgr,
                                     virDomainHostdevDefPtr dev ATTRIBUTE_UNUSED)
 
 {
-    const virSecurityLabelDefPtr secdef = &def->seclabel;
+    const virSecurityLabelDefPtr secdef =
+        virDomainDefGetSecurityLabelDef(def, SECURITY_APPARMOR_NAME);
+
+    if (!secdef)
+        return -1;
+
     if (secdef->norelabel)
         return 0;
 
@@ -789,7 +841,11 @@ AppArmorSetImageFDLabel(virSecurityManagerPtr mgr,
     char *proc = NULL;
     char *fd_path = NULL;
 
-    const virSecurityLabelDefPtr secdef = &def->seclabel;
+    const virSecurityLabelDefPtr secdef =
+        virDomainDefGetSecurityLabelDef(def, SECURITY_APPARMOR_NAME);
+
+    if (!secdef)
+        return -1;
 
     if (secdef->imagelabel == NULL)
         return 0;
diff --git a/src/security/security_dac.c b/src/security/security_dac.c
index 9182b39..18be55a 100644
--- a/src/security/security_dac.c
+++ b/src/security/security_dac.c
@@ -33,6 +33,7 @@
 #include "storage_file.h"
 
 #define VIR_FROM_THIS VIR_FROM_SECURITY
+#define SECURITY_DAC_NAME "dac"
 
 typedef struct _virSecurityDACData virSecurityDACData;
 typedef virSecurityDACData *virSecurityDACDataPtr;
@@ -64,6 +65,132 @@ void virSecurityDACSetDynamicOwnership(virSecurityManagerPtr mgr,
     priv->dynamicOwnership = dynamicOwnership;
 }
 
+static
+int parseIds(const char *label, uid_t *uidPtr, gid_t *gidPtr)
+{
+    uid_t uid;
+    gid_t gid;
+    char *endptr = NULL;
+
+    if (label == NULL)
+        return -1;
+
+    if (virStrToLong_ui(label, &endptr, 10, &uid) ||
+        endptr == NULL || *endptr != ':') {
+        return -1;
+    }
+
+    if (virStrToLong_ui(endptr + 1, NULL, 10, &gid))
+        return -1;
+
+    if (uidPtr)
+        *uidPtr = uid;
+    if (gidPtr)
+        *gidPtr = gid;
+    return 0;
+}
+
+static
+int virSecurityDACParseIds(virDomainDefPtr def, uid_t *uidPtr, gid_t *gidPtr)
+{
+    uid_t uid;
+    gid_t gid;
+    virSecurityLabelDefPtr seclabel;
+
+    if (def == NULL)
+        return -1;
+
+    seclabel = virDomainDefGetSecurityLabelDef(def, SECURITY_DAC_NAME);
+    if (seclabel == NULL) {
+        virSecurityReportError(VIR_ERR_INTERNAL_ERROR,
+                               _("security label for DAC not found"));
+        return -1;
+    }
+
+    if (seclabel->label && parseIds(seclabel->label, &uid, &gid)) {
+        virSecurityReportError(VIR_ERR_INTERNAL_ERROR,
+                               _("failed to parse uid and gid for DAC "
+                                 "security driver"));
+        return -1;
+    }
+
+    if (uidPtr)
+        *uidPtr = uid;
+    if (gidPtr)
+        *gidPtr = gid;
+
+    return 0;
+}
+
+static
+int virSecurityDACGetIds(virDomainDefPtr def, virSecurityDACDataPtr priv,
+                         uid_t *uidPtr, gid_t *gidPtr)
+{
+    if (virSecurityDACParseIds(def, uidPtr, gidPtr) == 0)
+        return 0;
+
+    if (priv) {
+        if (uidPtr)
+            *uidPtr = priv->user;
+        if (gidPtr)
+            *gidPtr = priv->group;
+        return 0;
+    }
+    return -1;
+}
+
+static
+int virSecurityDACParseImageIds(virDomainDefPtr def,
+                                uid_t *uidPtr, gid_t *gidPtr)
+{
+    uid_t uid;
+    gid_t gid;
+    virSecurityLabelDefPtr seclabel;
+
+    if (def == NULL)
+        return -1;
+
+    seclabel = virDomainDefGetSecurityLabelDef(def, SECURITY_DAC_NAME);
+    if (seclabel == NULL) {
+        virSecurityReportError(VIR_ERR_INTERNAL_ERROR,
+                               _("security label for DAC not found"));
+        return -1;
+    }
+
+    if (seclabel->imagelabel
+        && parseIds(seclabel->imagelabel, &uid, &gid)) {
+        virSecurityReportError(VIR_ERR_INTERNAL_ERROR,
+                               _("failed to parse uid and gid for DAC "
+                                 "security driver"));
+        return -1;
+    }
+
+    if (uidPtr)
+        *uidPtr = uid;
+    if (gidPtr)
+        *gidPtr = gid;
+
+    return 0;
+}
+
+static
+int virSecurityDACGetImageIds(virDomainDefPtr def, virSecurityDACDataPtr priv,
+                         uid_t *uidPtr, gid_t *gidPtr)
+{
+    if (virSecurityDACParseImageIds(def, uidPtr, gidPtr) == 0)
+        return 0;
+
+    if (priv) {
+        if (uidPtr)
+            *uidPtr = priv->user;
+        if (gidPtr)
+            *gidPtr = priv->group;
+        return 0;
+    }
+    return -1;
+}
+
+
 static virSecurityDriverStatus
 virSecurityDACProbe(const char *virtDriver ATTRIBUTE_UNUSED)
 {
@@ -85,7 +212,7 @@ virSecurityDACClose(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED)
 
 static const char * virSecurityDACGetModel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED)
 {
-    return "dac";
+    return SECURITY_DAC_NAME;
 }
 
 static const char * virSecurityDACGetDOI(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED)
@@ -167,10 +294,17 @@ virSecurityDACSetSecurityFileLabel(virDomainDiskDefPtr disk ATTRIBUTE_UNUSED,
                                    size_t depth ATTRIBUTE_UNUSED,
                                    void *opaque)
 {
-    virSecurityManagerPtr mgr = opaque;
+    void **params = opaque;
+    virSecurityManagerPtr mgr = params[0];
+    virDomainDefPtr def = params[1];
     virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr);
+    uid_t user;
+    gid_t group;
+
+    if (virSecurityDACGetImageIds(def, priv, &user, &group))
+        return -1;
 
-    return virSecurityDACSetOwnership(path, priv->user, priv->group);
+    return virSecurityDACSetOwnership(path, user, group);
 }
 
 
@@ -180,6 +314,9 @@ virSecurityDACSetSecurityImageLabel(virSecurityManagerPtr mgr,
                                     virDomainDiskDefPtr disk)
 
 {
+    uid_t user;
+    gid_t group;
+    void *params[2];
     virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr);
 
     if (!priv->dynamicOwnership)
@@ -188,12 +325,17 @@ virSecurityDACSetSecurityImageLabel(virSecurityManagerPtr mgr,
     if (disk->type == VIR_DOMAIN_DISK_TYPE_NETWORK)
         return 0;
 
+    if (virSecurityDACGetImageIds(def, priv, &user, &group))
+        return -1;
+
+    params[0] = mgr;
+    params[1] = def;
     return virDomainDiskDefForeachPath(disk,
                                        virSecurityManagerGetAllowDiskFormatProbing(mgr),
                                        false,
-                                       priv->user, priv->group,
+                                       user, group,
                                        virSecurityDACSetSecurityFileLabel,
-                                       mgr);
+                                       params);
 }
 
 
@@ -259,10 +401,17 @@ virSecurityDACSetSecurityPCILabel(pciDevice *dev ATTRIBUTE_UNUSED,
                                   const char *file,
                                   void *opaque)
 {
-    virSecurityManagerPtr mgr = opaque;
+    void **params = opaque;
+    virSecurityManagerPtr mgr = params[0];
+    virDomainDefPtr def = params[1];
     virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr);
+    uid_t user;
+    gid_t group;
 
-    return virSecurityDACSetOwnership(file, priv->user, priv->group);
+    if (virSecurityDACGetIds(def, priv, &user, &group))
+        return -1;
+
+    return virSecurityDACSetOwnership(file, user, group);
 }
 
 
@@ -271,18 +420,26 @@ virSecurityDACSetSecurityUSBLabel(usbDevice *dev ATTRIBUTE_UNUSED,
                                   const char *file,
                                   void *opaque)
 {
-    virSecurityManagerPtr mgr = opaque;
+    void **params = opaque;
+    virSecurityManagerPtr mgr = params[0];
+    virDomainDefPtr def = params[1];
     virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr);
+    uid_t user;
+    gid_t group;
 
-    return virSecurityDACSetOwnership(file, priv->user, priv->group);
+    if (virSecurityDACGetIds(def, priv, &user, &group))
+        return -1;
+
+    return virSecurityDACSetOwnership(file, user, group);
 }
 
 
 static int
 virSecurityDACSetSecurityHostdevLabel(virSecurityManagerPtr mgr,
-                                      virDomainDefPtr def ATTRIBUTE_UNUSED,
+                                      virDomainDefPtr def,
                                       virDomainHostdevDefPtr dev)
 {
+    void *params[] = {mgr, def};
     virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr);
     int ret = -1;
 
@@ -300,7 +457,8 @@ virSecurityDACSetSecurityHostdevLabel(virSecurityManagerPtr mgr,
         if (!usb)
             goto done;
 
-        ret = usbDeviceFileIterate(usb, virSecurityDACSetSecurityUSBLabel, mgr);
+        ret = usbDeviceFileIterate(usb, virSecurityDACSetSecurityUSBLabel,
+                                   params);
         usbFreeDevice(usb);
         break;
     }
@@ -314,7 +472,8 @@ virSecurityDACSetSecurityHostdevLabel(virSecurityManagerPtr mgr,
         if (!pci)
             goto done;
 
-        ret = pciDeviceFileIterate(pci, virSecurityDACSetSecurityPCILabel, mgr);
+        ret = pciDeviceFileIterate(pci, virSecurityDACSetSecurityPCILabel,
+                                   params);
         pciFreeDevice(pci);
 
         break;
@@ -404,17 +563,23 @@ done:
 
 static int
 virSecurityDACSetChardevLabel(virSecurityManagerPtr mgr,
+                              virDomainDefPtr def,
                               virDomainChrSourceDefPtr dev)
 
 {
     virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr);
     char *in = NULL, *out = NULL;
     int ret = -1;
+    uid_t user;
+    gid_t group;
+
+    if (virSecurityDACGetIds(def, priv, &user, &group))
+        return -1;
 
     switch (dev->type) {
     case VIR_DOMAIN_CHR_TYPE_DEV:
     case VIR_DOMAIN_CHR_TYPE_FILE:
-        ret = virSecurityDACSetOwnership(dev->data.file.path, priv->user, priv->group);
+        ret = virSecurityDACSetOwnership(dev->data.file.path, user, group);
         break;
 
     case VIR_DOMAIN_CHR_TYPE_PIPE:
@@ -424,12 +589,12 @@ virSecurityDACSetChardevLabel(virSecurityManagerPtr mgr,
             goto done;
         }
         if (virFileExists(in) && virFileExists(out)) {
-            if ((virSecurityDACSetOwnership(in, priv->user, priv->group) < 0) ||
-                (virSecurityDACSetOwnership(out, priv->user, priv->group) < 0)) {
+            if ((virSecurityDACSetOwnership(in, user, group) < 0) ||
+                (virSecurityDACSetOwnership(out, user, group) < 0)) {
                 goto done;
             }
         } else if (virSecurityDACSetOwnership(dev->data.file.path,
-                                              priv->user, priv->group) < 0) {
+                                              user, group) < 0) {
             goto done;
         }
         ret = 0;
@@ -554,7 +719,7 @@ virSecurityDACSetChardevCallback(virDomainDefPtr def ATTRIBUTE_UNUSED,
 {
     virSecurityManagerPtr mgr = opaque;
 
-    return virSecurityDACSetChardevLabel(mgr, &dev->source);
+    return virSecurityDACSetChardevLabel(mgr, def, &dev->source);
 }
 
 
@@ -565,6 +730,8 @@ virSecurityDACSetSecurityAllLabel(virSecurityManagerPtr mgr,
 {
     virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr);
     int i;
+    uid_t user;
+    gid_t group;
 
     if (!priv->dynamicOwnership)
         return 0;
@@ -591,16 +758,15 @@ virSecurityDACSetSecurityAllLabel(virSecurityManagerPtr mgr,
                                mgr) < 0)
         return -1;
 
+    if (virSecurityDACGetImageIds(def, priv, &user, &group))
+        return -1;
+
     if (def->os.kernel &&
-        virSecurityDACSetOwnership(def->os.kernel,
-                                    priv->user,
-                                    priv->group) < 0)
+        virSecurityDACSetOwnership(def->os.kernel, user, group) < 0)
         return -1;
 
     if (def->os.initrd &&
-        virSecurityDACSetOwnership(def->os.initrd,
-                                    priv->user,
-                                    priv->group) < 0)
+        virSecurityDACSetOwnership(def->os.initrd, user, group) < 0)
         return -1;
 
     return 0;
@@ -609,12 +775,17 @@ virSecurityDACSetSecurityAllLabel(virSecurityManagerPtr mgr,
 
 static int
 virSecurityDACSetSavedStateLabel(virSecurityManagerPtr mgr,
-                                 virDomainDefPtr def ATTRIBUTE_UNUSED,
+                                 virDomainDefPtr def,
                                  const char *savefile)
 {
+    uid_t user;
+    gid_t group;
     virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr);
 
-    return virSecurityDACSetOwnership(savefile, priv->user, priv->group);
+    if (virSecurityDACGetImageIds(def, priv, &user, &group))
+        return -1;
+
+    return virSecurityDACSetOwnership(savefile, user, group);
 }
 
 
@@ -636,12 +807,16 @@ static int
 virSecurityDACSetProcessLabel(virSecurityManagerPtr mgr,
                               virDomainDefPtr def ATTRIBUTE_UNUSED)
 {
+    uid_t user;
+    gid_t group;
     virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr);
 
-    VIR_DEBUG("Dropping privileges of DEF to %u:%u",
-              (unsigned int) priv->user, (unsigned int) priv->group);
+    if (virSecurityDACGetIds(def, priv, &user, &group))
+        return -1;
+
+    VIR_DEBUG("Dropping privileges of DEF to %u:%u", user, group);
 
-    if (virSetUIDGID(priv->user, priv->group) < 0)
+    if (virSetUIDGID(user, group) < 0)
         return -1;
 
     return 0;
@@ -656,9 +831,83 @@ virSecurityDACVerify(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
 }
 
 static int
-virSecurityDACGenLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
-                       virDomainDefPtr def ATTRIBUTE_UNUSED)
+virSecurityDACGenLabel(virSecurityManagerPtr mgr,
+                       virDomainDefPtr def)
 {
+    int rc = -1;
+    virSecurityLabelDefPtr seclabel;
+    virSecurityDACDataPtr priv = virSecurityManagerGetPrivateData(mgr);
+
+    if (mgr == NULL) {
+        virSecurityReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                               _("invalid security driver"));
+        return rc;
+    }
+
+    seclabel = virDomainDefGetSecurityLabelDef(def, SECURITY_DAC_NAME);
+    if (seclabel == NULL) {
+        return rc;
+    }
+
+    if (seclabel->imagelabel) {
+        virSecurityReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                               _("security image label already "
+                                 "defined for VM"));
+        return rc;
+    }
+
+    if (seclabel->model
+        && STRNEQ(seclabel->model, SECURITY_DAC_NAME)) {
+        virSecurityReportError(VIR_ERR_INTERNAL_ERROR,
+                               _("security label model %s is not supported "
+                                 "with selinux"),
+                               seclabel->model);
+            return rc;
+    }
+
+    switch(seclabel->type) {
+    case VIR_DOMAIN_SECLABEL_STATIC:
+        if (seclabel->label == NULL) {
+            virSecurityReportError(VIR_ERR_INTERNAL_ERROR,
+                                   _("missing label for static security "
+                                     "driver"));
+            return rc;
+        }
+        break;
+    case VIR_DOMAIN_SECLABEL_DYNAMIC:
+        if (virAsprintf(&seclabel->label, "%d:%d", priv->user, priv->group) < 0) {
+            virReportOOMError();
+            return rc;
+        }
+        if (seclabel->label == NULL) {
+            virSecurityReportError(VIR_ERR_INTERNAL_ERROR,
+                                   _("cannot generate dac user and group id"));
+            return rc;
+        }
+        break;
+    case VIR_DOMAIN_SECLABEL_NONE:
+        /* no op */
+        break;
+    default:
+        virSecurityReportError(VIR_ERR_INTERNAL_ERROR,
+                               _("unexpected security label type '%s'"),
+                               virDomainSeclabelTypeToString(seclabel->type));
+        return rc;
+    }
+
+    if (!seclabel->norelabel) {
+        if (seclabel->imagelabel == NULL) {
+            seclabel->imagelabel = strdup(seclabel->label);
+            if (seclabel->imagelabel == NULL) {
+                virSecurityReportError(VIR_ERR_INTERNAL_ERROR,
+                                       _("cannot generate dac user and group id"));
+                VIR_FREE(seclabel->label);
+                seclabel->label = NULL;
+                return rc;
+            }
+        }
+    }
+
     return 0;
 }
 
@@ -683,6 +932,15 @@ virSecurityDACGetProcessLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
                               pid_t pid ATTRIBUTE_UNUSED,
                               virSecurityLabelPtr seclabel ATTRIBUTE_UNUSED)
 {
+    virSecurityLabelDefPtr secdef =
+        virDomainDefGetSecurityLabelDef(def, SECURITY_DAC_NAME);
+
+    if (!secdef || !seclabel)
+        return -1;
+
+    if (secdef->label)
+        strcpy(seclabel->label, secdef->label);
+
     return 0;
 }
 
@@ -724,7 +982,7 @@ static char *virSecurityDACGetMountOptions(virSecurityManagerPtr mgr ATTRIBUTE_U
 
 virSecurityDriver virSecurityDriverDAC = {
     .privateDataLen                     = sizeof(virSecurityDACData),
-    .name                               = "virDAC",
+    .name                               = SECURITY_DAC_NAME,
     .probe                              = virSecurityDACProbe,
     .open                               = virSecurityDACOpen,
     .close                              = virSecurityDACClose,
diff --git a/src/security/security_manager.c b/src/security/security_manager.c
index 5ca3201..970bfd5 100644
--- a/src/security/security_manager.c
+++ b/src/security/security_manager.c
@@ -68,8 +68,7 @@ static virSecurityManagerPtr virSecurityManagerNewDriver(virSecurityDriverPtr dr
     return mgr;
 }
 
-virSecurityManagerPtr virSecurityManagerNewStack(virSecurityManagerPtr primary,
-                                                 virSecurityManagerPtr secondary)
+virSecurityManagerPtr virSecurityManagerNewStack(virSecurityManagerPtr primary)
 {
     virSecurityManagerPtr mgr =
         virSecurityManagerNewDriver(&virSecurityDriverStack,
@@ -81,12 +80,19 @@ virSecurityManagerPtr virSecurityManagerNewStack(virSecurityManagerPtr primary,
     if (!mgr)
         return NULL;
 
-    virSecurityStackSetPrimary(mgr, primary);
-    virSecurityStackSetSecondary(mgr, secondary);
+    virSecurityStackAddPrimary(mgr, primary);
 
     return mgr;
 }
 
+int virSecurityManagerStackAddNested(virSecurityManagerPtr stack,
+                                     virSecurityManagerPtr nested)
+{
+    if (!STREQ("stack", stack->drv->name))
+        return -1;
+    return virSecurityStackAddNested(stack, nested);
+}
+
 virSecurityManagerPtr virSecurityManagerNewDAC(const char *virtDriver,
                                                uid_t user,
                                                gid_t group,
@@ -308,25 +314,51 @@ int virSecurityManagerRestoreSavedStateLabel(virSecurityManagerPtr mgr,
 int virSecurityManagerGenLabel(virSecurityManagerPtr mgr,
                                virDomainDefPtr vm)
 {
-    if (vm->seclabels[0]->type == VIR_DOMAIN_SECLABEL_DEFAULT) {
-        if (mgr->defaultConfined)
-            vm->seclabels[0]->type = VIR_DOMAIN_SECLABEL_DYNAMIC;
-        else
-            vm->seclabels[0]->type = VIR_DOMAIN_SECLABEL_NONE;
-    }
+    int rc = 0;
+    size_t i;
+    virSecurityManagerPtr* sec_managers = NULL;
+    virSecurityLabelDefPtr seclabel;
 
-    if ((vm->seclabels[0]->type == VIR_DOMAIN_SECLABEL_NONE) &&
-        mgr->requireConfined) {
-        virSecurityReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
-                               _("Unconfined guests are not allowed on this host"));
+    if (mgr == NULL || mgr->drv == NULL)
         return -1;
-    }
 
-    if (mgr->drv->domainGenSecurityLabel)
-        return mgr->drv->domainGenSecurityLabel(mgr, vm);
+    if ((sec_managers = virSecurityManagerGetNested(mgr)) == NULL)
+        return -1;
 
-    virSecurityReportError(VIR_ERR_NO_SUPPORT, __FUNCTION__);
-    return -1;
+    for (i = 0; sec_managers[i]; i++) {
+        seclabel = virDomainDefGetSecurityLabelDef(vm,
+                                                   sec_managers[i]->drv->name);
+        if (seclabel == NULL) {
+            rc = -1;
+            goto cleanup;
+        }
+
+        if (seclabel->type == VIR_DOMAIN_SECLABEL_DEFAULT) {
+            if (sec_managers[i]->defaultConfined)
+                seclabel->type = VIR_DOMAIN_SECLABEL_DYNAMIC;
+            else
+                seclabel->type = VIR_DOMAIN_SECLABEL_NONE;
+        }
+
+        if ((seclabel->type == VIR_DOMAIN_SECLABEL_NONE) &&
+            sec_managers[i]->requireConfined) {
+            virSecurityReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                                   _("Unconfined guests are not allowed on this host"));
+            return -1;
+        }
+
+        if (!sec_managers[i]->drv->domainGenSecurityLabel) {
+            virSecurityReportError(VIR_ERR_NO_SUPPORT, __FUNCTION__);
+        } else {
+            rc += sec_managers[i]->drv->domainGenSecurityLabel(sec_managers[i], vm);
+            if (rc)
+                goto cleanup;
+        }
+    }
+
+cleanup:
+    VIR_FREE(sec_managers);
+    return rc;
 }
 
 int virSecurityManagerReserveLabel(virSecurityManagerPtr mgr,
@@ -397,12 +429,17 @@ int virSecurityManagerSetProcessLabel(virSecurityManagerPtr mgr,
 int virSecurityManagerVerify(virSecurityManagerPtr mgr,
                              virDomainDefPtr def)
 {
-    const virSecurityLabelDefPtr secdef = def->seclabels[0];
+    virSecurityLabelDefPtr secdef;
+
+    if (mgr == NULL || mgr->drv == NULL)
+        return 0;
+
     /* NULL model == dynamic labelling, with whatever driver
      * is active, so we can short circuit verify check to
      * avoid drivers de-referencing NULLs by accident
      */
-    if (!secdef->model)
+    secdef = virDomainDefGetSecurityLabelDef(def, mgr->drv->name);
+    if (secdef == NULL || secdef->model == NULL)
         return 0;
 
     if (mgr->drv->domainSecurityVerify)
@@ -435,3 +472,22 @@ char *virSecurityManagerGetMountOptions(virSecurityManagerPtr mgr,
     */
     return NULL;
 }
+
+virSecurityManagerPtr*
+virSecurityManagerGetNested(virSecurityManagerPtr mgr)
+{
+    virSecurityManagerPtr* list = NULL;
+
+    if (STREQ("stack", mgr->drv->name)) {
+        return virSecurityStackGetNested(mgr);
+    }
+
+    if (VIR_ALLOC_N(list, 2) < 0) {
+        virReportOOMError();
+        return NULL;
+    }
+
+    list[0] = mgr;
+    list[1] = NULL;
+    return list;
+}
diff --git a/src/security/security_manager.h b/src/security/security_manager.h
index f0bf60d..f86b84d 100644
--- a/src/security/security_manager.h
+++ b/src/security/security_manager.h
@@ -37,8 +37,9 @@ virSecurityManagerPtr virSecurityManagerNew(const char *name,
                                             bool defaultConfined,
                                             bool requireConfined);
 
-virSecurityManagerPtr virSecurityManagerNewStack(virSecurityManagerPtr primary,
-                                                 virSecurityManagerPtr secondary);
+virSecurityManagerPtr virSecurityManagerNewStack(virSecurityManagerPtr primary);
+int virSecurityManagerStackAddNested(virSecurityManagerPtr stack,
+                                     virSecurityManagerPtr nested);
 
 virSecurityManagerPtr virSecurityManagerNewDAC(const char *virtDriver,
                                                uid_t user,
@@ -109,4 +110,7 @@ int virSecurityManagerSetImageFDLabel(virSecurityManagerPtr mgr,
                                       int fd);
 char *virSecurityManagerGetMountOptions(virSecurityManagerPtr mgr,
                                               virDomainDefPtr vm);
+virSecurityManagerPtr*
+virSecurityManagerGetNested(virSecurityManagerPtr mgr);
+
 #endif /* VIR_SECURITY_MANAGER_H__ */
diff --git a/src/security/security_selinux.c b/src/security/security_selinux.c
index 9a708b1..dc05910 100644
--- a/src/security/security_selinux.c
+++ b/src/security/security_selinux.c
@@ -271,46 +271,52 @@ SELinuxGenSecurityLabel(virSecurityManagerPtr mgr,
     int c2 = 0;
     context_t ctx = NULL;
     const char *range;
-    virSecuritySELinuxDataPtr data = virSecurityManagerGetPrivateData(mgr);
+    virSecurityLabelDefPtr seclabel;
+    virSecuritySELinuxDataPtr data;
 
-    VIR_DEBUG("SELinuxGenSecurityLabel %s", virSecurityManagerGetDriver(mgr));
-    if ((def->seclabels[0]->type == VIR_DOMAIN_SECLABEL_DYNAMIC) &&
-        !def->seclabels[0]->baselabel &&
-        def->seclabels[0]->model) {
+    if (mgr == NULL) {
         virSecurityReportError(VIR_ERR_INTERNAL_ERROR,
-                               "%s", _("security model already defined for VM"));
+                               "%s", _("invalid security driver"));
+        return rc;
+    }
+
+    seclabel = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
+    if (seclabel == NULL) {
         return rc;
     }
 
-    if (def->seclabels[0]->type == VIR_DOMAIN_SECLABEL_DYNAMIC &&
-        def->seclabels[0]->label) {
+    data = virSecurityManagerGetPrivateData(mgr);
+
+    VIR_DEBUG("SELinuxGenSecurityLabel %s", virSecurityManagerGetDriver(mgr));
+    if (seclabel->type == VIR_DOMAIN_SECLABEL_DYNAMIC &&
+        seclabel->label) {
         virSecurityReportError(VIR_ERR_INTERNAL_ERROR,
                                "%s", _("security label already defined for VM"));
         return rc;
     }
 
-    if (def->seclabels[0]->imagelabel) {
+    if (seclabel->imagelabel) {
         virSecurityReportError(VIR_ERR_INTERNAL_ERROR,
                                "%s", _("security image label already defined for VM"));
         return rc;
     }
 
-    if (def->seclabels[0]->model &&
-        STRNEQ(def->seclabels[0]->model, SECURITY_SELINUX_NAME)) {
+    if (seclabel->model &&
+        STRNEQ(seclabel->model, SECURITY_SELINUX_NAME)) {
         virSecurityReportError(VIR_ERR_INTERNAL_ERROR,
                                _("security label model %s is not supported with selinux"),
-                               def->seclabels[0]->model);
+                               seclabel->model);
         return rc;
     }
 
-    VIR_DEBUG("SELinuxGenSecurityLabel %d", def->seclabels[0]->type);
+    VIR_DEBUG("SELinuxGenSecurityLabel %d", seclabel->type);
 
-    switch (def->seclabels[0]->type) {
+    switch (seclabel->type) {
     case VIR_DOMAIN_SECLABEL_STATIC:
-        if (!(ctx = context_new(def->seclabels[0]->label)) ) {
+        if (!(ctx = context_new(seclabel->label)) ) {
             virReportSystemError(errno,
                                  _("unable to allocate socket security context '%s'"),
-                                 def->seclabels[0]->label);
+                                 seclabel->label);
             return rc;
         }
 
@@ -345,11 +351,11 @@ SELinuxGenSecurityLabel(virSecurityManagerPtr mgr,
             }
         } while (mcsAdd(mcs) == -1);
 
-        def->seclabels[0]->label =
-            SELinuxGenNewContext(def->seclabels[0]->baselabel ?
-                                 def->seclabels[0]->baselabel :
+        seclabel->label =
+            SELinuxGenNewContext(seclabel->baselabel ?
+                                 seclabel->baselabel :
                                  data->domain_context, mcs);
-        if (! def->seclabels[0]->label)  {
+        if (! seclabel->label)  {
             virSecurityReportError(VIR_ERR_INTERNAL_ERROR,
                                    _("cannot generate selinux context for %s"), mcs);
             goto cleanup;
@@ -363,21 +369,21 @@ SELinuxGenSecurityLabel(virSecurityManagerPtr mgr,
     default:
         virSecurityReportError(VIR_ERR_INTERNAL_ERROR,
                                _("unexpected security label type '%s'"),
-                               virDomainSeclabelTypeToString(def->seclabels[0]->type));
+                               virDomainSeclabelTypeToString(seclabel->type));
         goto cleanup;
     }
 
-    if (!def->seclabels[0]->norelabel) {
-        def->seclabels[0]->imagelabel = SELinuxGenNewContext(data->file_context, mcs);
-        if (!def->seclabels[0]->imagelabel)  {
+    if (!seclabel->norelabel) {
+        seclabel->imagelabel = SELinuxGenNewContext(data->domain_context, mcs);
+        if (!seclabel->imagelabel)  {
             virSecurityReportError(VIR_ERR_INTERNAL_ERROR,
                                    _("cannot generate selinux context for %s"), mcs);
             goto cleanup;
         }
     }
 
-    if (!def->seclabels[0]->model &&
-        !(def->seclabels[0]->model = strdup(SECURITY_SELINUX_NAME))) {
+    if (!seclabel->model &&
+        !(seclabel->model = strdup(SECURITY_SELINUX_NAME))) {
         virReportOOMError();
         goto cleanup;
     }
@@ -386,12 +392,12 @@ SELinuxGenSecurityLabel(virSecurityManagerPtr mgr,
 
 cleanup:
     if (rc != 0) {
-        if (def->seclabels[0]->type == VIR_DOMAIN_SECLABEL_DYNAMIC)
-            VIR_FREE(def->seclabels[0]->label);
-        VIR_FREE(def->seclabels[0]->imagelabel);
-        if (def->seclabels[0]->type == VIR_DOMAIN_SECLABEL_DYNAMIC &&
-            !def->seclabels[0]->baselabel)
-            VIR_FREE(def->seclabels[0]->model);
+        if (seclabel->type == VIR_DOMAIN_SECLABEL_DYNAMIC)
+            VIR_FREE(seclabel->label);
+        VIR_FREE(seclabel->imagelabel);
+        if (seclabel->type == VIR_DOMAIN_SECLABEL_DYNAMIC &&
+            !seclabel->baselabel)
+            VIR_FREE(seclabel->model);
     }
 
     if (ctx)
@@ -400,10 +406,10 @@ cleanup:
     VIR_FREE(mcs);
 
     VIR_DEBUG("model=%s label=%s imagelabel=%s baselabel=%s",
-              NULLSTR(def->seclabels[0]->model),
-              NULLSTR(def->seclabels[0]->label),
-              NULLSTR(def->seclabels[0]->imagelabel),
-              NULLSTR(def->seclabels[0]->baselabel));
+              NULLSTR(seclabel->model),
+              NULLSTR(seclabel->label),
+              NULLSTR(seclabel->imagelabel),
+              NULLSTR(seclabel->baselabel));
 
     return rc;
 }
@@ -416,8 +422,14 @@ SELinuxReserveSecurityLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
     security_context_t pctx;
     context_t ctx = NULL;
     const char *mcs;
+    virSecurityLabelDefPtr seclabel;
+
+    seclabel = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
+    if (seclabel == NULL) {
+        return -1;
+    }
 
-    if (def->seclabels[0]->type == VIR_DOMAIN_SECLABEL_STATIC)
+    if (seclabel->type == VIR_DOMAIN_SECLABEL_STATIC)
         return 0;
 
     if (getpidcon(pid, &pctx) == -1) {
@@ -709,9 +721,16 @@ SELinuxRestoreSecurityImageLabelInt(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
                                     virDomainDiskDefPtr disk,
                                     int migrated)
 {
-    const virSecurityLabelDefPtr secdef = def->seclabels[0];
+    virSecurityLabelDefPtr seclabel;
+    virSecurityDeviceLabelDefPtr disk_seclabel;
 
-    if (secdef->norelabel || (disk->seclabels[0] && disk->seclabels[0]->norelabel))
+    seclabel = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
+    if (seclabel == NULL)
+        return -1;
+
+    disk_seclabel = virDomainDiskDefGetSecurityLabelDef(disk,
+                                                        SECURITY_SELINUX_NAME);
+    if (seclabel->norelabel || (disk_seclabel && disk_seclabel->norelabel))
         return 0;
 
     /* Don't restore labels on readoly/shared disks, because
@@ -763,17 +782,21 @@ SELinuxSetSecurityFileLabel(virDomainDiskDefPtr disk,
                             size_t depth,
                             void *opaque)
 {
+    int ret;
+    virSecurityDeviceLabelDefPtr disk_seclabel;
     virSecuritySELinuxCallbackDataPtr cbdata = opaque;
     const virSecurityLabelDefPtr secdef = cbdata->secdef;
-    int ret;
     virSecuritySELinuxDataPtr data = virSecurityManagerGetPrivateData(cbdata->manager);
 
-    if (disk->seclabels[0] && disk->seclabels[0]->norelabel)
+    disk_seclabel = virDomainDiskDefGetSecurityLabelDef(disk,
+                                                        SECURITY_SELINUX_NAME);
+
+    if (disk_seclabel && disk_seclabel->norelabel)
         return 0;
 
-    if (disk->seclabels[0] && !disk->seclabels[0]->norelabel &&
-        disk->seclabels[0]->label) {
-        ret = SELinuxSetFilecon(path, disk->seclabels[0]->label);
+    if (disk_seclabel && !disk_seclabel->norelabel &&
+        disk_seclabel->label) {
+        ret = SELinuxSetFilecon(path, disk_seclabel->label);
     } else if (depth == 0) {
 
         if (disk->shared) {
@@ -788,14 +811,14 @@ SELinuxSetSecurityFileLabel(virDomainDiskDefPtr disk,
     } else {
         ret = SELinuxSetFileconOptional(path, data->content_context);
     }
-    if (ret == 1 && !disk->seclabels[0]) {
+    if (ret == 1 && !disk_seclabel) {
         /* If we failed to set a label, but virt_use_nfs let us
          * proceed anyway, then we don't need to relabel later.  */
-        if (VIR_ALLOC(disk->seclabels[0]) < 0) {
+        if (VIR_ALLOC(disk_seclabel) < 0) {
             virReportOOMError();
             return -1;
         }
-        disk->seclabels[0]->norelabel = true;
+        disk_seclabel->norelabel = true;
         ret = 0;
     }
     return ret;
@@ -807,11 +830,15 @@ SELinuxSetSecurityImageLabel(virSecurityManagerPtr mgr,
                              virDomainDiskDefPtr disk)
 
 {
+    bool allowDiskFormatProbing;
     virSecuritySELinuxCallbackData cbdata;
-    cbdata.secdef = def->seclabels[0];
     cbdata.manager = mgr;
+    cbdata.secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
 
-    bool allowDiskFormatProbing = virSecurityManagerGetAllowDiskFormatProbing(mgr);
+    allowDiskFormatProbing = virSecurityManagerGetAllowDiskFormatProbing(mgr);
+
+    if (cbdata.secdef == NULL)
+        return -1;
 
     if (cbdata.secdef->norelabel)
         return 0;
@@ -838,9 +865,12 @@ static int
 SELinuxSetSecurityPCILabel(pciDevice *dev ATTRIBUTE_UNUSED,
                            const char *file, void *opaque)
 {
+    virSecurityLabelDefPtr secdef;
     virDomainDefPtr def = opaque;
-    const virSecurityLabelDefPtr secdef = def->seclabels[0];
 
+    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
+    if (secdef == NULL)
+        return -1;
     return SELinuxSetFilecon(file, secdef->imagelabel);
 }
 
@@ -848,8 +878,12 @@ static int
 SELinuxSetSecurityUSBLabel(usbDevice *dev ATTRIBUTE_UNUSED,
                            const char *file, void *opaque)
 {
+    virSecurityLabelDefPtr secdef;
     virDomainDefPtr def = opaque;
-    const virSecurityLabelDefPtr secdef = def->seclabels[0];
+
+    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
+    if (secdef == NULL)
+        return -1;
 
     return SELinuxSetFilecon(file, secdef->imagelabel);
 }
@@ -860,9 +894,13 @@ SELinuxSetSecurityHostdevLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
                                virDomainHostdevDefPtr dev)
 
 {
-    const virSecurityLabelDefPtr secdef = def->seclabels[0];
+    virSecurityLabelDefPtr secdef;
     int ret = -1;
 
+    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
+    if (secdef == NULL)
+        return -1;
+
     if (secdef->norelabel)
         return 0;
 
@@ -929,9 +967,13 @@ SELinuxRestoreSecurityHostdevLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
                                    virDomainHostdevDefPtr dev)
 
 {
-    const virSecurityLabelDefPtr secdef = def->seclabels[0];
+    virSecurityLabelDefPtr secdef;
     int ret = -1;
 
+    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
+    if (secdef == NULL)
+        return -1;
+
     if (secdef->norelabel)
         return 0;
 
@@ -982,10 +1024,14 @@ SELinuxSetSecurityChardevLabel(virDomainDefPtr def,
                                virDomainChrSourceDefPtr dev)
 
 {
-    const virSecurityLabelDefPtr secdef = def->seclabels[0];
+    virSecurityLabelDefPtr secdef;
     char *in = NULL, *out = NULL;
     int ret = -1;
 
+    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
+    if (secdef == NULL)
+        return -1;
+
     if (secdef->norelabel)
         return 0;
 
@@ -1028,10 +1074,14 @@ SELinuxRestoreSecurityChardevLabel(virDomainDefPtr def,
                                    virDomainChrSourceDefPtr dev)
 
 {
-    const virSecurityLabelDefPtr secdef = def->seclabels[0];
+    virSecurityLabelDefPtr secdef;
     char *in = NULL, *out = NULL;
     int ret = -1;
 
+    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
+    if (secdef == NULL)
+        return -1;
+
     if (secdef->norelabel)
         return 0;
 
@@ -1121,12 +1171,16 @@ SELinuxRestoreSecurityAllLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
                                virDomainDefPtr def,
                                int migrated ATTRIBUTE_UNUSED)
 {
-    const virSecurityLabelDefPtr secdef = def->seclabels[0];
+    virSecurityLabelDefPtr secdef;
     int i;
     int rc = 0;
 
     VIR_DEBUG("Restoring security label on %s", def->name);
 
+    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
+    if (secdef == NULL)
+        return -1;
+
     if (secdef->norelabel)
         return 0;
 
@@ -1171,7 +1225,11 @@ static int
 SELinuxReleaseSecurityLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
                             virDomainDefPtr def)
 {
-    const virSecurityLabelDefPtr secdef = def->seclabels[0];
+    virSecurityLabelDefPtr secdef;
+
+    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
+    if (secdef == NULL)
+        return -1;
 
     if (secdef->type == VIR_DOMAIN_SECLABEL_DYNAMIC) {
         if (secdef->label != NULL) {
@@ -1196,7 +1254,11 @@ SELinuxSetSavedStateLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
                           virDomainDefPtr def,
                           const char *savefile)
 {
-    const virSecurityLabelDefPtr secdef = def->seclabels[0];
+    virSecurityLabelDefPtr secdef;
+
+    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
+    if (secdef == NULL)
+        return -1;
 
     if (secdef->norelabel)
         return 0;
@@ -1210,7 +1272,11 @@ SELinuxRestoreSavedStateLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
                               virDomainDefPtr def,
                               const char *savefile)
 {
-    const virSecurityLabelDefPtr secdef = def->seclabels[0];
+    virSecurityLabelDefPtr secdef;
+
+    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
+    if (secdef == NULL)
+        return -1;
 
     if (secdef->norelabel)
         return 0;
@@ -1223,7 +1289,12 @@ static int
 SELinuxSecurityVerify(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
                       virDomainDefPtr def)
 {
-    const virSecurityLabelDefPtr secdef = def->seclabels[0];
+    virSecurityLabelDefPtr secdef;
+
+    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
+    if (secdef == NULL)
+        return -1;
+
     if (!STREQ(virSecurityManagerGetModel(mgr), secdef->model)) {
         virSecurityReportError(VIR_ERR_INTERNAL_ERROR,
                                _("security label driver mismatch: "
@@ -1248,12 +1319,16 @@ SELinuxSetSecurityProcessLabel(virSecurityManagerPtr mgr,
                                virDomainDefPtr def)
 {
     /* TODO: verify DOI */
-    const virSecurityLabelDefPtr secdef = def->seclabels[0];
-    VIR_DEBUG("SELinuxSetSecurityProcessLabel %s", secdef->label);
+    virSecurityLabelDefPtr secdef;
 
-    if (def->seclabels[0]->label == NULL)
+    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
+    if (secdef == NULL)
+        return -1;
+
+    if (secdef->label == NULL)
         return 0;
 
+    VIR_DEBUG("SELinuxSetSecurityProcessLabel %s", secdef->label);
     if (!STREQ(virSecurityManagerGetModel(mgr), secdef->model)) {
         virSecurityReportError(VIR_ERR_INTERNAL_ERROR,
                                _("security label driver mismatch: "
@@ -1280,13 +1355,17 @@ SELinuxSetSecurityDaemonSocketLabel(virSecurityManagerPtr mgr,
                                     virDomainDefPtr def)
 {
     /* TODO: verify DOI */
-    const virSecurityLabelDefPtr secdef = def->seclabels[0];
+    virSecurityLabelDefPtr secdef;
     context_t execcon = NULL;
     context_t proccon = NULL;
     security_context_t scon = NULL;
     int rc = -1;
 
-    if (def->seclabels[0]->label == NULL)
+    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
+    if (secdef == NULL)
+        return -1;
+
+    if (secdef->label == NULL)
         return 0;
 
     if (!STREQ(virSecurityManagerGetModel(mgr), secdef->model)) {
@@ -1350,9 +1429,13 @@ static int
 SELinuxSetSecuritySocketLabel(virSecurityManagerPtr mgr,
                               virDomainDefPtr vm)
 {
-    const virSecurityLabelDefPtr secdef = vm->seclabels[0];
+    virSecurityLabelDefPtr secdef;
     int rc = -1;
 
+    secdef = virDomainDefGetSecurityLabelDef(vm, SECURITY_SELINUX_NAME);
+    if (secdef == NULL)
+        return -1;
+
     if (secdef->label == NULL)
         return 0;
 
@@ -1388,9 +1471,13 @@ SELinuxClearSecuritySocketLabel(virSecurityManagerPtr mgr,
                                 virDomainDefPtr def)
 {
     /* TODO: verify DOI */
-    const virSecurityLabelDefPtr secdef = def->seclabels[0];
+    virSecurityLabelDefPtr secdef;
+
+    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
+    if (secdef == NULL)
+        return -1;
 
-    if (def->seclabels[0]->label == NULL)
+    if (secdef->label == NULL)
         return 0;
 
     if (!STREQ(virSecurityManagerGetModel(mgr), secdef->model)) {
@@ -1466,9 +1553,13 @@ SELinuxSetSecurityAllLabel(virSecurityManagerPtr mgr,
                            virDomainDefPtr def,
                            const char *stdin_path)
 {
-    virSecuritySELinuxDataPtr data = virSecurityManagerGetPrivateData(mgr);
-    const virSecurityLabelDefPtr secdef = def->seclabels[0];
     int i;
+    virSecuritySELinuxDataPtr data = virSecurityManagerGetPrivateData(mgr);
+    virSecurityLabelDefPtr secdef;
+
+    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
+    if (secdef == NULL)
+        return -1;
 
     if (secdef->norelabel)
         return 0;
@@ -1528,7 +1619,11 @@ SELinuxSetImageFDLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
                        virDomainDefPtr def,
                        int fd)
 {
-    const virSecurityLabelDefPtr secdef = def->seclabels[0];
+    virSecurityLabelDefPtr secdef;
+
+    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
+    if (secdef == NULL)
+        return -1;
 
     if (secdef->imagelabel == NULL)
         return 0;
@@ -1538,13 +1633,17 @@ SELinuxSetImageFDLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
 
 static char *genImageLabel(virSecurityManagerPtr mgr,
                            virDomainDefPtr def) {
-    const virSecurityLabelDefPtr secdef = def->seclabels[0];
+    virSecurityLabelDefPtr secdef;
     virSecuritySELinuxDataPtr data = virSecurityManagerGetPrivateData(mgr);
     const char *range;
     context_t ctx = NULL;
     char *label = NULL;
     const char *mcs = NULL;
 
+    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
+    if (secdef == NULL)
+        goto cleanup;
+
     if (secdef->label) {
         ctx = context_new(secdef->label);
         if (!ctx) {
@@ -1575,7 +1674,11 @@ cleanup:
 static char *SELinuxGetSecurityMountOptions(virSecurityManagerPtr mgr,
                                             virDomainDefPtr def) {
     char *opts = NULL;
-    const virSecurityLabelDefPtr secdef = def->seclabels[0];
+    virSecurityLabelDefPtr secdef;
+
+    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
+    if (secdef == NULL)
+        return NULL;
 
     if (! secdef->imagelabel)
         secdef->imagelabel = genImageLabel(mgr,def);
diff --git a/src/security/security_stack.c b/src/security/security_stack.c
index 65d30d6..a7b8741 100644
--- a/src/security/security_stack.c
+++ b/src/security/security_stack.c
@@ -23,29 +23,70 @@
 #include "security_stack.h"
 
 #include "virterror_internal.h"
+#include "memory.h"
 
 #define VIR_FROM_THIS VIR_FROM_SECURITY
 
 typedef struct _virSecurityStackData virSecurityStackData;
 typedef virSecurityStackData *virSecurityStackDataPtr;
+typedef struct _virSecurityStackItem virSecurityStackItem;
+typedef virSecurityStackItem* virSecurityStackItemPtr;
+
+struct _virSecurityStackItem {
+    virSecurityManagerPtr securityManager;
+    virSecurityStackItemPtr next;
+};
 
 struct _virSecurityStackData {
     virSecurityManagerPtr primary;
-    virSecurityManagerPtr secondary;
+    virSecurityStackItemPtr itemsHead;
 };
 
-void virSecurityStackSetPrimary(virSecurityManagerPtr mgr,
-                                virSecurityManagerPtr primary)
+int
+virSecurityStackAddPrimary(virSecurityManagerPtr mgr,
+                           virSecurityManagerPtr primary)
 {
     virSecurityStackDataPtr priv = virSecurityManagerGetPrivateData(mgr);
+    if (virSecurityStackAddNested(mgr, primary) < 0)
+        return -1;
     priv->primary = primary;
+    return 0;
+}
+
+int
+virSecurityStackAddNested(virSecurityManagerPtr mgr,
+                          virSecurityManagerPtr nested)
+{
+    virSecurityStackItemPtr item = NULL;
+    virSecurityStackDataPtr priv = virSecurityManagerGetPrivateData(mgr);
+
+    if (VIR_ALLOC(item) < 0) {
+        virReportOOMError();
+        return -1;
+    }
+    item->securityManager = nested;
+    item->next = priv->itemsHead;
+    priv->itemsHead = item;
+    return 0;
+}
+
+virSecurityManagerPtr
+virSecurityStackGetPrimary(virSecurityManagerPtr mgr)
+{
+    virSecurityStackDataPtr priv = virSecurityManagerGetPrivateData(mgr);
+    return (priv->primary) ? priv->primary : priv->itemsHead->securityManager;
+}
+
+void virSecurityStackSetPrimary(virSecurityManagerPtr mgr,
+                                virSecurityManagerPtr primary)
+{
+    virSecurityStackAddPrimary(mgr, primary);
 }
 
 void virSecurityStackSetSecondary(virSecurityManagerPtr mgr,
                                   virSecurityManagerPtr secondary)
 {
-    virSecurityStackDataPtr priv = virSecurityManagerGetPrivateData(mgr);
-    priv->secondary = secondary;
+    virSecurityStackAddNested(mgr, secondary);
 }
 
 static virSecurityDriverStatus
@@ -64,9 +105,14 @@ static int
 virSecurityStackClose(virSecurityManagerPtr mgr)
 {
     virSecurityStackDataPtr priv = virSecurityManagerGetPrivateData(mgr);
+    virSecurityStackItemPtr next, item = priv->itemsHead;
 
-    virSecurityManagerFree(priv->primary);
-    virSecurityManagerFree(priv->secondary);
+    while (item) {
+        next = item->next;
+        virSecurityManagerFree(item->securityManager);
+        VIR_FREE(item);
+        item = next;
+    }
 
     return 0;
 }
@@ -74,17 +120,13 @@ virSecurityStackClose(virSecurityManagerPtr mgr)
 static const char *
 virSecurityStackGetModel(virSecurityManagerPtr mgr)
 {
-    virSecurityStackDataPtr priv = virSecurityManagerGetPrivateData(mgr);
-
-    return virSecurityManagerGetModel(priv->primary);
+    return virSecurityManagerGetModel(virSecurityStackGetPrimary(mgr));
 }
 
 static const char *
 virSecurityStackGetDOI(virSecurityManagerPtr mgr)
 {
-    virSecurityStackDataPtr priv = virSecurityManagerGetPrivateData(mgr);
-
-    return virSecurityManagerGetDOI(priv->primary);
+    return virSecurityManagerGetDOI(virSecurityStackGetPrimary(mgr));
 }
 
 static int
@@ -92,13 +134,15 @@ virSecurityStackVerify(virSecurityManagerPtr mgr,
                        virDomainDefPtr def)
 {
     virSecurityStackDataPtr priv = virSecurityManagerGetPrivateData(mgr);
+    virSecurityStackItemPtr item = priv->itemsHead;
     int rc = 0;
 
-    if (virSecurityManagerVerify(priv->primary, def) < 0)
-        rc = -1;
-
-    if (virSecurityManagerVerify(priv->secondary, def) < 0)
-        rc = -1;
+    for(; item; item = item->next) {
+        if (virSecurityManagerVerify(item->securityManager, def) < 0) {
+            rc = -1;
+            break;
+        }
+    }
 
     return rc;
 }
@@ -108,12 +152,12 @@ static int
 virSecurityStackGenLabel(virSecurityManagerPtr mgr,
                          virDomainDefPtr vm)
 {
-    virSecurityStackDataPtr priv = virSecurityManagerGetPrivateData(mgr);
     int rc = 0;
 
-    if (virSecurityManagerGenLabel(priv->primary, vm) < 0)
+    if (virSecurityManagerGenLabel(virSecurityStackGetPrimary(mgr), vm) < 0)
         rc = -1;
 
+// TODO
 #if 0
     /* We don't allow secondary drivers to generate labels.
      * This may have to change in the future, but requires
@@ -133,11 +177,12 @@ static int
 virSecurityStackReleaseLabel(virSecurityManagerPtr mgr,
                              virDomainDefPtr vm)
 {
-    virSecurityStackDataPtr priv = virSecurityManagerGetPrivateData(mgr);
     int rc = 0;
 
-    if (virSecurityManagerReleaseLabel(priv->primary, vm) < 0)
+    if (virSecurityManagerReleaseLabel(virSecurityStackGetPrimary(mgr), vm) < 0)
         rc = -1;
+
+// TODO
 #if 0
     /* XXX See note in GenLabel */
     if (virSecurityManagerReleaseLabel(priv->secondary, vm) < 0)
@@ -153,11 +198,11 @@ virSecurityStackReserveLabel(virSecurityManagerPtr mgr,
                              virDomainDefPtr vm,
                              pid_t pid)
 {
-    virSecurityStackDataPtr priv = virSecurityManagerGetPrivateData(mgr);
     int rc = 0;
 
-    if (virSecurityManagerReserveLabel(priv->primary, vm, pid) < 0)
+    if (virSecurityManagerReserveLabel(virSecurityStackGetPrimary(mgr), vm, pid) < 0)
         rc = -1;
+// TODO
 #if 0
     /* XXX See note in GenLabel */
     if (virSecurityManagerReserveLabel(priv->secondary, vm, pid) < 0)
@@ -174,12 +219,13 @@ virSecurityStackSetSecurityImageLabel(virSecurityManagerPtr mgr,
                                       virDomainDiskDefPtr disk)
 {
     virSecurityStackDataPtr priv = virSecurityManagerGetPrivateData(mgr);
+    virSecurityStackItemPtr item = priv->itemsHead;
     int rc = 0;
 
-    if (virSecurityManagerSetImageLabel(priv->secondary, vm, disk) < 0)
-        rc = -1;
-    if (virSecurityManagerSetImageLabel(priv->primary, vm, disk) < 0)
-        rc = -1;
+    for (; item; item = item->next) {
+        if (virSecurityManagerSetImageLabel(item->securityManager, vm, disk) < 0)
+            rc = -1;
+    }
 
     return rc;
 }
@@ -191,12 +237,13 @@ virSecurityStackRestoreSecurityImageLabel(virSecurityManagerPtr mgr,
                                           virDomainDiskDefPtr disk)
 {
     virSecurityStackDataPtr priv = virSecurityManagerGetPrivateData(mgr);
+    virSecurityStackItemPtr item = priv->itemsHead;
     int rc = 0;
 
-    if (virSecurityManagerRestoreImageLabel(priv->secondary, vm, disk) < 0)
-        rc = -1;
-    if (virSecurityManagerRestoreImageLabel(priv->primary, vm, disk) < 0)
-        rc = -1;
+    for (; item; item = item->next) {
+        if (virSecurityManagerRestoreImageLabel(item->securityManager, vm, disk) < 0)
+            rc = -1;
+    }
 
     return rc;
 }
@@ -209,12 +256,13 @@ virSecurityStackSetSecurityHostdevLabel(virSecurityManagerPtr mgr,
 
 {
     virSecurityStackDataPtr priv = virSecurityManagerGetPrivateData(mgr);
+    virSecurityStackItemPtr item = priv->itemsHead;
     int rc = 0;
 
-    if (virSecurityManagerSetHostdevLabel(priv->secondary, vm, dev) < 0)
-        rc = -1;
-    if (virSecurityManagerSetHostdevLabel(priv->primary, vm, dev) < 0)
-        rc = -1;
+    for (; item; item = item->next) {
+        if (virSecurityManagerSetHostdevLabel(item->securityManager, vm, dev) < 0)
+            rc = -1;
+    }
 
     return rc;
 }
@@ -226,12 +274,13 @@ virSecurityStackRestoreSecurityHostdevLabel(virSecurityManagerPtr mgr,
                                             virDomainHostdevDefPtr dev)
 {
     virSecurityStackDataPtr priv = virSecurityManagerGetPrivateData(mgr);
+    virSecurityStackItemPtr item = priv->itemsHead;
     int rc = 0;
 
-    if (virSecurityManagerRestoreHostdevLabel(priv->secondary, vm, dev) < 0)
-        rc = -1;
-    if (virSecurityManagerRestoreHostdevLabel(priv->primary, vm, dev) < 0)
-        rc = -1;
+    for (; item; item = item->next) {
+        if (virSecurityManagerRestoreHostdevLabel(item->securityManager, vm, dev) < 0)
+            rc = -1;
+    }
 
     return rc;
 }
@@ -243,12 +292,13 @@ virSecurityStackSetSecurityAllLabel(virSecurityManagerPtr mgr,
                                     const char *stdin_path)
 {
     virSecurityStackDataPtr priv = virSecurityManagerGetPrivateData(mgr);
+    virSecurityStackItemPtr item = priv->itemsHead;
     int rc = 0;
 
-    if (virSecurityManagerSetAllLabel(priv->secondary, vm, stdin_path) < 0)
-        rc = -1;
-    if (virSecurityManagerSetAllLabel(priv->primary, vm, stdin_path) < 0)
-        rc = -1;
+    for (; item; item = item->next) {
+        if (virSecurityManagerSetAllLabel(item->securityManager, vm, stdin_path) < 0)
+            rc = -1;
+    }
 
     return rc;
 }
@@ -260,12 +310,13 @@ virSecurityStackRestoreSecurityAllLabel(virSecurityManagerPtr mgr,
                                         int migrated)
 {
     virSecurityStackDataPtr priv = virSecurityManagerGetPrivateData(mgr);
+    virSecurityStackItemPtr item = priv->itemsHead;
     int rc = 0;
 
-    if (virSecurityManagerRestoreAllLabel(priv->secondary, vm, migrated) < 0)
-        rc = -1;
-    if (virSecurityManagerRestoreAllLabel(priv->primary, vm, migrated) < 0)
-        rc = -1;
+    for (; item; item = item->next) {
+        if (virSecurityManagerRestoreAllLabel(item->securityManager, vm, migrated) < 0)
+            rc = -1;
+    }
 
     return rc;
 }
@@ -277,12 +328,13 @@ virSecurityStackSetSavedStateLabel(virSecurityManagerPtr mgr,
                                    const char *savefile)
 {
     virSecurityStackDataPtr priv = virSecurityManagerGetPrivateData(mgr);
+    virSecurityStackItemPtr item = priv->itemsHead;
     int rc = 0;
 
-    if (virSecurityManagerSetSavedStateLabel(priv->secondary, vm, savefile) < 0)
-        rc = -1;
-    if (virSecurityManagerSetSavedStateLabel(priv->primary, vm, savefile) < 0)
-        rc = -1;
+    for (; item; item = item->next) {
+        if (virSecurityManagerSetSavedStateLabel(item->securityManager, vm, savefile) < 0)
+            rc = -1;
+    }
 
     return rc;
 }
@@ -294,12 +346,13 @@ virSecurityStackRestoreSavedStateLabel(virSecurityManagerPtr mgr,
                                        const char *savefile)
 {
     virSecurityStackDataPtr priv = virSecurityManagerGetPrivateData(mgr);
+    virSecurityStackItemPtr item = priv->itemsHead;
     int rc = 0;
 
-    if (virSecurityManagerRestoreSavedStateLabel(priv->secondary, vm, savefile) < 0)
-        rc = -1;
-    if (virSecurityManagerRestoreSavedStateLabel(priv->primary, vm, savefile) < 0)
-        rc = -1;
+    for (; item; item = item->next) {
+        if (virSecurityManagerRestoreSavedStateLabel(item->securityManager, vm, savefile) < 0)
+            rc = -1;
+    }
 
     return rc;
 }
@@ -310,12 +363,13 @@ virSecurityStackSetProcessLabel(virSecurityManagerPtr mgr,
                                 virDomainDefPtr vm)
 {
     virSecurityStackDataPtr priv = virSecurityManagerGetPrivateData(mgr);
+    virSecurityStackItemPtr item = priv->itemsHead;
     int rc = 0;
 
-    if (virSecurityManagerSetProcessLabel(priv->secondary, vm) < 0)
-        rc = -1;
-    if (virSecurityManagerSetProcessLabel(priv->primary, vm) < 0)
-        rc = -1;
+    for (; item; item = item->next) {
+        if (virSecurityManagerSetProcessLabel(item->securityManager, vm) < 0)
+            rc = -1;
+    }
 
     return rc;
 }
@@ -326,14 +380,14 @@ virSecurityStackGetProcessLabel(virSecurityManagerPtr mgr,
                                 pid_t pid,
                                 virSecurityLabelPtr seclabel)
 {
-    virSecurityStackDataPtr priv = virSecurityManagerGetPrivateData(mgr);
     int rc = 0;
 
+// TODO
 #if 0
     if (virSecurityManagerGetProcessLabel(priv->secondary, vm, pid, seclabel) < 0)
         rc = -1;
 #endif
-    if (virSecurityManagerGetProcessLabel(priv->primary, vm, pid, seclabel) < 0)
+    if (virSecurityManagerGetProcessLabel(virSecurityStackGetPrimary(mgr), vm, pid, seclabel) < 0)
         rc = -1;
 
     return rc;
@@ -345,12 +399,13 @@ virSecurityStackSetDaemonSocketLabel(virSecurityManagerPtr mgr,
                                      virDomainDefPtr vm)
 {
     virSecurityStackDataPtr priv = virSecurityManagerGetPrivateData(mgr);
+    virSecurityStackItemPtr item = priv->itemsHead;
     int rc = 0;
 
-    if (virSecurityManagerSetDaemonSocketLabel(priv->secondary, vm) < 0)
-        rc = -1;
-    if (virSecurityManagerSetDaemonSocketLabel(priv->primary, vm) < 0)
-        rc = -1;
+    for (; item; item = item->next) {
+        if (virSecurityManagerSetDaemonSocketLabel(item->securityManager, vm) < 0)
+            rc = -1;
+    }
 
     return rc;
 }
@@ -361,12 +416,13 @@ virSecurityStackSetSocketLabel(virSecurityManagerPtr mgr,
                                virDomainDefPtr vm)
 {
     virSecurityStackDataPtr priv = virSecurityManagerGetPrivateData(mgr);
+    virSecurityStackItemPtr item = priv->itemsHead;
     int rc = 0;
 
-    if (virSecurityManagerSetSocketLabel(priv->secondary, vm) < 0)
-        rc = -1;
-    if (virSecurityManagerSetSocketLabel(priv->primary, vm) < 0)
-        rc = -1;
+    for (; item; item = item->next) {
+        if (virSecurityManagerSetSocketLabel(item->securityManager, vm) < 0)
+            rc = -1;
+    }
 
     return rc;
 }
@@ -377,12 +433,13 @@ virSecurityStackClearSocketLabel(virSecurityManagerPtr mgr,
                                  virDomainDefPtr vm)
 {
     virSecurityStackDataPtr priv = virSecurityManagerGetPrivateData(mgr);
+    virSecurityStackItemPtr item = priv->itemsHead;
     int rc = 0;
 
-    if (virSecurityManagerClearSocketLabel(priv->secondary, vm) < 0)
-        rc = -1;
-    if (virSecurityManagerClearSocketLabel(priv->primary, vm) < 0)
-        rc = -1;
+    for (; item; item = item->next) {
+        if (virSecurityManagerClearSocketLabel(item->securityManager, vm) < 0)
+            rc = -1;
+    }
 
     return rc;
 }
@@ -393,12 +450,13 @@ virSecurityStackSetImageFDLabel(virSecurityManagerPtr mgr,
                                 int fd)
 {
     virSecurityStackDataPtr priv = virSecurityManagerGetPrivateData(mgr);
+    virSecurityStackItemPtr item = priv->itemsHead;
     int rc = 0;
 
-    if (virSecurityManagerSetImageFDLabel(priv->secondary, vm, fd) < 0)
-        rc = -1;
-    if (virSecurityManagerSetImageFDLabel(priv->primary, vm, fd) < 0)
-        rc = -1;
+    for (; item; item = item->next) {
+        if (virSecurityManagerSetImageFDLabel(item->securityManager, vm, fd) < 0)
+            rc = -1;
+    }
 
     return rc;
 }
@@ -408,6 +466,29 @@ static char *virSecurityStackGetMountOptions(virSecurityManagerPtr mgr ATTRIBUTE
     return NULL;
 }
 
+virSecurityManagerPtr*
+virSecurityStackGetNested(virSecurityManagerPtr mgr)
+{
+    virSecurityManagerPtr *list = NULL;
+    virSecurityStackDataPtr priv = virSecurityManagerGetPrivateData(mgr);
+    virSecurityStackItemPtr item;
+    int len = 0, i = 0;
+
+    for (item = priv->itemsHead; item; item = item->next)
+        len++;
+
+    if (VIR_ALLOC_N(list, len + 1) < 0) {
+        virReportOOMError();
+        return NULL;
+    }
+
+    for (item = priv->itemsHead; item; item = item->next, i++)
+        list[i] = item->securityManager;
+    list[len] = NULL;
+
+    return list;
+}
+
 virSecurityDriver virSecurityDriverStack = {
     .privateDataLen                     = sizeof(virSecurityStackData),
     .name                               = "stack",
diff --git a/src/security/security_stack.h b/src/security/security_stack.h
index bc83ff3..13a7a88 100644
--- a/src/security/security_stack.h
+++ b/src/security/security_stack.h
@@ -25,9 +25,22 @@
 
 extern virSecurityDriver virSecurityDriverStack;
 
+
+int
+virSecurityStackAddPrimary(virSecurityManagerPtr mgr,
+                           virSecurityManagerPtr primary);
+int
+virSecurityStackAddNested(virSecurityManagerPtr mgr,
+                          virSecurityManagerPtr nested);
+virSecurityManagerPtr
+virSecurityStackGetPrimary(virSecurityManagerPtr mgr);
+
 void virSecurityStackSetPrimary(virSecurityManagerPtr mgr,
                                 virSecurityManagerPtr primary);
 void virSecurityStackSetSecondary(virSecurityManagerPtr mgr,
                                   virSecurityManagerPtr secondary);
 
+virSecurityManagerPtr*
+virSecurityStackGetNested(virSecurityManagerPtr mgr);
+
 #endif /* __VIR_SECURITY_DAC */
-- 
1.7.1




More information about the libvir-list mailing list