[libvirt] [PATCH 2/3] Allow for resource relabelling with static labels

Daniel P. Berrange berrange at redhat.com
Mon Jun 27 12:20:37 UTC 2011


Add a new attribute to the <seclabel> XML to allow resource
relabelling to be enabled with static label usage.

  <seclabel model='selinux' type='static' relabel='yes'>
    <label>system_u:system_r:svirt_t:s0:c392,c662</label>
  </seclabel>

* docs/schemas/domain.rng: Add relabel attribute
* src/conf/domain_conf.c, src/conf/domain_conf.h: Parse
  the 'relabel' attribute
* src/qemu/qemu_process.c: Unconditionally clear out the
  'imagelabel' attribute
* src/security/security_apparmor.c: Skip based on 'relabel'
  attribute instead of label type
* src/security/security_selinux.c: Skip based on 'relabel'
  attribute instead of label type and fill in <imagelabel>
  attribute if relabel is enabled.
---
 docs/schemas/domain.rng          |    6 ++
 src/conf/domain_conf.c           |   41 ++++++++--
 src/conf/domain_conf.h           |    3 +-
 src/qemu/qemu_process.c          |    2 +-
 src/security/security_apparmor.c |   10 +-
 src/security/security_selinux.c  |  160 ++++++++++++++++++++++++--------------
 6 files changed, 149 insertions(+), 73 deletions(-)

diff --git a/docs/schemas/domain.rng b/docs/schemas/domain.rng
index ab5a56b..fb1497b 100644
--- a/docs/schemas/domain.rng
+++ b/docs/schemas/domain.rng
@@ -61,6 +61,12 @@
           <value>static</value>
         </choice>
       </attribute>
+      <attribute name="relabel">
+        <choice>
+          <value>yes</value>
+          <value>no</value>
+        </choice>
+      </attribute>
       <element name="label">
         <text/>
       </element>
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index cc318da..dc24d71 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -5072,6 +5072,30 @@ virSecurityLabelDefParseXML(const virDomainDefPtr def,
                              "%s", _("invalid security type"));
         goto error;
     }
+    p = virXPathStringLimit("string(./seclabel/@relabel)",
+                            VIR_SECURITY_LABEL_BUFLEN-1, ctxt);
+    if (p != NULL) {
+        if (STREQ(p, "yes")) {
+            def->seclabel.relabel = true;
+        } else if (STREQ(p, "no")) {
+            def->seclabel.relabel = false;
+        } else {
+            virDomainReportError(VIR_ERR_XML_ERROR,
+                                 _("invalid security relabel value %s"), p);
+            goto error;
+        }
+        if (def->seclabel.type == VIR_DOMAIN_SECLABEL_DYNAMIC &&
+            !def->seclabel.relabel) {
+            virDomainReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                                 "%s", _("dynamic label type must use resource relabelling"));
+            goto error;
+        }
+    } else {
+        if (def->seclabel.type == VIR_DOMAIN_SECLABEL_STATIC)
+            def->seclabel.relabel = false;
+        else
+            def->seclabel.relabel = true;
+    }
 
     /* Only parse label, if using static labels, or
      * if the 'live' VM XML is requested
@@ -5089,8 +5113,8 @@ virSecurityLabelDefParseXML(const virDomainDefPtr def,
         def->seclabel.label = p;
     }
 
-    /* Only parse imagelabel, if requested live XML for dynamic label */
-    if (def->seclabel.type == VIR_DOMAIN_SECLABEL_DYNAMIC &&
+    /* Only parse imagelabel, if requested live XML with relabelling */
+    if (def->seclabel.relabel &&
         !(flags & VIR_DOMAIN_XML_INACTIVE)) {
         p = virXPathStringLimit("string(./seclabel/imagelabel[1])",
                                 VIR_SECURITY_LABEL_BUFLEN-1, ctxt);
@@ -9864,16 +9888,17 @@ char *virDomainDefFormat(virDomainDefPtr def,
         if (def->seclabel.type == VIR_DOMAIN_SECLABEL_DYNAMIC &&
             !def->seclabel.baselabel &&
             (flags & VIR_DOMAIN_XML_INACTIVE)) {
-            virBufferAsprintf(&buf, "  <seclabel type='%s' model='%s'/>\n",
-                              sectype, def->seclabel.model);
+            virBufferAsprintf(&buf, "  <seclabel type='%s' model='%s' relabel='%s'/>\n",
+                              sectype, def->seclabel.model,
+                              def->seclabel.relabel ? "yes" : "no");
         } else {
-            virBufferAsprintf(&buf, "  <seclabel type='%s' model='%s'>\n",
-                              sectype, def->seclabel.model);
+            virBufferAsprintf(&buf, "  <seclabel type='%s' model='%s' relabel='%s'>\n",
+                              sectype, def->seclabel.model,
+                              def->seclabel.relabel ? "yes" : "no");
             if (def->seclabel.label)
                 virBufferEscapeString(&buf, "    <label>%s</label>\n",
                                       def->seclabel.label);
-            if (def->seclabel.imagelabel &&
-                (def->seclabel.type == VIR_DOMAIN_SECLABEL_DYNAMIC))
+            if (def->seclabel.relabel && def->seclabel.imagelabel)
                 virBufferEscapeString(&buf, "    <imagelabel>%s</imagelabel>\n",
                                       def->seclabel.imagelabel);
             if (def->seclabel.baselabel &&
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index 17c2584..926f4a9 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -959,7 +959,8 @@ struct _virSecurityLabelDef {
     char *label;        /* security label string */
     char *imagelabel;   /* security image label string */
     char *baselabel;    /* base name of label string */
-    int type;
+    int type;           /* virDomainSeclabelType */
+    bool relabel;
 };
 
 enum virDomainTimerNameType {
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
index 1a404ff..0d547a9 100644
--- a/src/qemu/qemu_process.c
+++ b/src/qemu/qemu_process.c
@@ -2911,8 +2911,8 @@ void qemuProcessStop(struct qemud_driver *driver,
         if (!vm->def->seclabel.baselabel)
             VIR_FREE(vm->def->seclabel.model);
         VIR_FREE(vm->def->seclabel.label);
-        VIR_FREE(vm->def->seclabel.imagelabel);
     }
+    VIR_FREE(vm->def->seclabel.imagelabel);
 
     virDomainDefClearDeviceAliases(vm->def);
     if (!priv->persistentAddrs) {
diff --git a/src/security/security_apparmor.c b/src/security/security_apparmor.c
index b6ce5b7..7c7d0a7 100644
--- a/src/security/security_apparmor.c
+++ b/src/security/security_apparmor.c
@@ -265,7 +265,7 @@ reload_profile(virSecurityManagerPtr mgr,
     int rc = -1;
     char *profile_name = NULL;
 
-    if (secdef->type == VIR_DOMAIN_SECLABEL_STATIC)
+    if (!secdef->relabel)
         return 0;
 
     if ((profile_name = get_profile_name(vm)) == NULL)
@@ -461,7 +461,7 @@ static int
 AppArmorSetSecurityAllLabel(virSecurityManagerPtr mgr,
                             virDomainObjPtr vm, const char *stdin_path)
 {
-    if (vm->def->seclabel.type == VIR_DOMAIN_SECLABEL_STATIC)
+    if (!vm->def->seclabel.relabel)
         return 0;
 
     /* Reload the profile if stdin_path is specified. Note that
@@ -610,7 +610,7 @@ AppArmorSetSecurityImageLabel(virSecurityManagerPtr mgr,
     int rc = -1;
     char *profile_name;
 
-    if (secdef->type == VIR_DOMAIN_SECLABEL_STATIC)
+    if (!secdef->relabel)
         return 0;
 
     if (!disk->src || disk->type == VIR_DOMAIN_DISK_TYPE_NETWORK)
@@ -682,7 +682,7 @@ AppArmorSetSecurityHostdevLabel(virSecurityManagerPtr mgr,
     struct SDPDOP *ptr;
     int ret = -1;
 
-    if (secdef->type == VIR_DOMAIN_SECLABEL_STATIC)
+    if (!secdef->relabel)
         return 0;
 
     if (dev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
@@ -741,7 +741,7 @@ AppArmorRestoreSecurityHostdevLabel(virSecurityManagerPtr mgr,
 
 {
     const virSecurityLabelDefPtr secdef = &vm->def->seclabel;
-    if (secdef->type == VIR_DOMAIN_SECLABEL_STATIC)
+    if (!secdef->relabel)
         return 0;
 
     return reload_profile(mgr, vm, NULL, false);
diff --git a/src/security/security_selinux.c b/src/security/security_selinux.c
index 736cd7f..9071ec7 100644
--- a/src/security/security_selinux.c
+++ b/src/security/security_selinux.c
@@ -165,13 +165,11 @@ SELinuxGenSecurityLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
                         virDomainObjPtr vm)
 {
     int rc = -1;
-    char mcs[1024];
+    char *mcs = NULL;
     char *scontext = NULL;
     int c1 = 0;
     int c2 = 0;
-
-    if (vm->def->seclabel.type == VIR_DOMAIN_SECLABEL_STATIC)
-        return 0;
+    context_t ctx = NULL;
 
     if ((vm->def->seclabel.type == VIR_DOMAIN_SECLABEL_DYNAMIC) &&
         !vm->def->seclabel.baselabel &&
@@ -181,13 +179,19 @@ SELinuxGenSecurityLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
         return rc;
     }
 
-    if (vm->def->seclabel.label ||
-        vm->def->seclabel.imagelabel) {
+    if (vm->def->seclabel.type == VIR_DOMAIN_SECLABEL_DYNAMIC &&
+        vm->def->seclabel.label) {
         virSecurityReportError(VIR_ERR_INTERNAL_ERROR,
                                "%s", _("security label already defined for VM"));
         return rc;
     }
 
+    if (vm->def->seclabel.imagelabel) {
+        virSecurityReportError(VIR_ERR_INTERNAL_ERROR,
+                               "%s", _("security image label already defined for VM"));
+        return rc;
+    }
+
     if (vm->def->seclabel.model &&
         STRNEQ(vm->def->seclabel.model, SECURITY_SELINUX_NAME)) {
         virSecurityReportError(VIR_ERR_INTERNAL_ERROR,
@@ -196,51 +200,89 @@ SELinuxGenSecurityLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
         return rc;
     }
 
-    do {
-        c1 = virRandom(1024);
-        c2 = virRandom(1024);
-
-        if ( c1 == c2 ) {
-            snprintf(mcs, sizeof(mcs), "s0:c%d", c1);
-        } else {
-            if ( c1 < c2 )
-                snprintf(mcs, sizeof(mcs), "s0:c%d,c%d", c1, c2);
-            else
-                snprintf(mcs, sizeof(mcs), "s0:c%d,c%d", c2, c1);
+    if (vm->def->seclabel.type == VIR_DOMAIN_SECLABEL_STATIC) {
+        if (!(ctx = context_new(vm->def->seclabel.label)) ) {
+            virReportSystemError(errno,
+                                 _("unable to allocate socket security context '%s'"),
+                                 vm->def->seclabel.label);
+            return rc;
         }
-    } while(mcsAdd(mcs) == -1);
 
-    vm->def->seclabel.label =
-        SELinuxGenNewContext(vm->def->seclabel.baselabel ?
-                             vm->def->seclabel.baselabel :
-                             default_domain_context, mcs);
-    if (! vm->def->seclabel.label)  {
-        virSecurityReportError(VIR_ERR_INTERNAL_ERROR,
-                               _("cannot generate selinux context for %s"), mcs);
-        goto err;
+        const char *range = context_range_get(ctx);
+        if (!range ||
+            !(mcs = strdup(range))) {
+            virReportOOMError();
+            goto cleanup;
+        }
+    } else {
+        do {
+            c1 = virRandom(1024);
+            c2 = virRandom(1024);
+
+            if ( c1 == c2 ) {
+                if (virAsprintf(&mcs, "s0:c%d", c1) < 0) {
+                    virReportOOMError();
+                    goto cleanup;
+                }
+            } else {
+                if (c1 > c2) {
+                    c1 ^= c2;
+                    c2 ^= c1;
+                    c1 ^= c2;
+                }
+                if (virAsprintf(&mcs, "s0:c%d,c%d", c1, c2) < 0) {
+                    virReportOOMError();
+                    goto cleanup;
+                }
+            }
+        } while (mcsAdd(mcs) == -1);
+
+        vm->def->seclabel.label =
+            SELinuxGenNewContext(vm->def->seclabel.baselabel ?
+                                 vm->def->seclabel.baselabel :
+                                 default_domain_context, mcs);
+        if (! vm->def->seclabel.label)  {
+            virSecurityReportError(VIR_ERR_INTERNAL_ERROR,
+                                   _("cannot generate selinux context for %s"), mcs);
+            goto cleanup;
+        }
     }
     vm->def->seclabel.imagelabel = SELinuxGenNewContext(default_image_context, mcs);
-    if (! vm->def->seclabel.imagelabel)  {
+    if (!vm->def->seclabel.imagelabel)  {
         virSecurityReportError(VIR_ERR_INTERNAL_ERROR,
                                _("cannot generate selinux context for %s"), mcs);
-        goto err;
+        goto cleanup;
     }
+
     if (!vm->def->seclabel.model &&
         !(vm->def->seclabel.model = strdup(SECURITY_SELINUX_NAME))) {
         virReportOOMError();
-        goto err;
+        goto cleanup;
     }
 
-
     rc = 0;
-    goto done;
-err:
-    VIR_FREE(vm->def->seclabel.label);
-    VIR_FREE(vm->def->seclabel.imagelabel);
-    if (!vm->def->seclabel.baselabel)
-        VIR_FREE(vm->def->seclabel.model);
-done:
+
+cleanup:
+    if (rc != 0) {
+        if (vm->def->seclabel.type == VIR_DOMAIN_SECLABEL_DYNAMIC)
+            VIR_FREE(vm->def->seclabel.label);
+        VIR_FREE(vm->def->seclabel.imagelabel);
+        if (vm->def->seclabel.type == VIR_DOMAIN_SECLABEL_DYNAMIC &&
+            !vm->def->seclabel.baselabel)
+            VIR_FREE(vm->def->seclabel.model);
+    }
+
+    if (ctx)
+        context_free(ctx);
     VIR_FREE(scontext);
+    VIR_FREE(mcs);
+
+    VIR_DEBUG("model=%s label=%s imagelabel=%s baselabel=%s",
+              NULLSTR(vm->def->seclabel.model),
+              NULLSTR(vm->def->seclabel.label),
+              NULLSTR(vm->def->seclabel.imagelabel),
+              NULLSTR(vm->def->seclabel.baselabel));
+
     return rc;
 }
 
@@ -495,7 +537,7 @@ SELinuxRestoreSecurityImageLabelInt(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
 {
     const virSecurityLabelDefPtr secdef = &vm->def->seclabel;
 
-    if (secdef->type == VIR_DOMAIN_SECLABEL_STATIC)
+    if (!secdef->relabel)
         return 0;
 
     /* Don't restore labels on readoly/shared disks, because
@@ -579,7 +621,7 @@ SELinuxSetSecurityImageLabel(virSecurityManagerPtr mgr,
     const virSecurityLabelDefPtr secdef = &vm->def->seclabel;
     bool allowDiskFormatProbing = virSecurityManagerGetAllowDiskFormatProbing(mgr);
 
-    if (secdef->type == VIR_DOMAIN_SECLABEL_STATIC)
+    if (!secdef->relabel)
         return 0;
 
     return virDomainDiskDefForeachPath(disk,
@@ -619,7 +661,7 @@ SELinuxSetSecurityHostdevLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
     const virSecurityLabelDefPtr secdef = &vm->def->seclabel;
     int ret = -1;
 
-    if (secdef->type == VIR_DOMAIN_SECLABEL_STATIC)
+    if (!secdef->relabel)
         return 0;
 
     if (dev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
@@ -688,7 +730,7 @@ SELinuxRestoreSecurityHostdevLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
     const virSecurityLabelDefPtr secdef = &vm->def->seclabel;
     int ret = -1;
 
-    if (secdef->type == VIR_DOMAIN_SECLABEL_STATIC)
+    if (!secdef->relabel)
         return 0;
 
     if (dev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
@@ -742,7 +784,7 @@ SELinuxSetSecurityChardevLabel(virDomainObjPtr vm,
     char *in = NULL, *out = NULL;
     int ret = -1;
 
-    if (secdef->type == VIR_DOMAIN_SECLABEL_STATIC)
+    if (!secdef->relabel)
         return 0;
 
     switch (dev->type) {
@@ -788,7 +830,7 @@ SELinuxRestoreSecurityChardevLabel(virDomainObjPtr vm,
     char *in = NULL, *out = NULL;
     int ret = -1;
 
-    if (secdef->type == VIR_DOMAIN_SECLABEL_STATIC)
+    if (!secdef->relabel)
         return 0;
 
     switch (dev->type) {
@@ -876,7 +918,7 @@ SELinuxRestoreSecurityAllLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
 
     VIR_DEBUG("Restoring security label on %s", vm->def->name);
 
-    if (secdef->type == VIR_DOMAIN_SECLABEL_STATIC)
+    if (!secdef->relabel)
         return 0;
 
     for (i = 0 ; i < vm->def->nhostdevs ; i++) {
@@ -922,18 +964,18 @@ SELinuxReleaseSecurityLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
 {
     const virSecurityLabelDefPtr secdef = &vm->def->seclabel;
 
-    if (secdef->type == VIR_DOMAIN_SECLABEL_STATIC ||
-        secdef->label == NULL)
-        return 0;
-
-    context_t con = context_new(secdef->label);
-    if (con) {
-        mcsRemove(context_range_get(con));
-        context_free(con);
+    if (secdef->type == VIR_DOMAIN_SECLABEL_DYNAMIC) {
+        if (secdef->label != NULL) {
+            context_t con = context_new(secdef->label);
+            if (con) {
+                mcsRemove(context_range_get(con));
+                context_free(con);
+            }
+        }
+        VIR_FREE(secdef->label);
+        if (!secdef->baselabel)
+            VIR_FREE(secdef->model);
     }
-
-    VIR_FREE(secdef->model);
-    VIR_FREE(secdef->label);
     VIR_FREE(secdef->imagelabel);
 
     return 0;
@@ -947,7 +989,7 @@ SELinuxSetSavedStateLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
 {
     const virSecurityLabelDefPtr secdef = &vm->def->seclabel;
 
-    if (secdef->type == VIR_DOMAIN_SECLABEL_STATIC)
+    if (!secdef->relabel)
         return 0;
 
     return SELinuxSetFilecon(savefile, secdef->imagelabel);
@@ -961,7 +1003,7 @@ SELinuxRestoreSavedStateLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
 {
     const virSecurityLabelDefPtr secdef = &vm->def->seclabel;
 
-    if (secdef->type == VIR_DOMAIN_SECLABEL_STATIC)
+    if (!secdef->relabel)
         return 0;
 
     return SELinuxRestoreSecurityFileLabel(savefile);
@@ -1176,7 +1218,7 @@ SELinuxSetSecurityAllLabel(virSecurityManagerPtr mgr,
     const virSecurityLabelDefPtr secdef = &vm->def->seclabel;
     int i;
 
-    if (secdef->type == VIR_DOMAIN_SECLABEL_STATIC)
+    if (!secdef->relabel)
         return 0;
 
     for (i = 0 ; i < vm->def->ndisks ; i++) {
@@ -1190,6 +1232,8 @@ SELinuxSetSecurityAllLabel(virSecurityManagerPtr mgr,
                                          vm, vm->def->disks[i]) < 0)
             return -1;
     }
+    /* XXX fixme process  vm->def->fss if relabel == true */
+
     for (i = 0 ; i < vm->def->nhostdevs ; i++) {
         if (SELinuxSetSecurityHostdevLabel(mgr,
                                            vm,
-- 
1.7.4.4




More information about the libvir-list mailing list