[libvirt] [PATCH v3 2/2] Add <seclabel> to character devices.

Richard W.M. Jones rjones at redhat.com
Thu Sep 20 15:29:59 UTC 2012


From: "Richard W.M. Jones" <rjones at redhat.com>

This allows the user to control labelling of each character device
separately (the default is to inherit from the VM).
---
 docs/formatdomain.html.in       |    8 ++++
 src/conf/domain_conf.c          |   77 +++++++++++++++++++++++++++++++++--
 src/conf/domain_conf.h          |    6 +++
 src/security/security_selinux.c |   86 +++++++++++++++++++++++++++------------
 4 files changed, 147 insertions(+), 30 deletions(-)

diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in
index 51f897c..939312c 100644
--- a/docs/formatdomain.html.in
+++ b/docs/formatdomain.html.in
@@ -3434,6 +3434,14 @@ qemu-kvm -net nic,model=? /dev/null
     </p>
 
     <p>
+      The <code>source</code> element may contain an optional
+      <code>seclabel</code> to override the way that labelling
+      is done on the socket path.  If this element is not present,
+      the <a href="#seclabel">security label is inherited from
+        the per-domain setting</a>.
+    </p>
+
+    <p>
       Each character device element has an optional
       sub-element <code><address></code> which can tie the
       device to a
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 06b3209..7023897 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -1273,6 +1273,8 @@ virDomainChrSourceDefIsEqual(const virDomainChrSourceDef *src,
 
 void virDomainChrDefFree(virDomainChrDefPtr def)
 {
+    size_t i;
+
     if (!def)
         return;
 
@@ -1296,6 +1298,12 @@ void virDomainChrDefFree(virDomainChrDefPtr def)
     virDomainChrSourceDefClear(&def->source);
     virDomainDeviceInfoClear(&def->info);
 
+    if (def->seclabels) {
+        for (i = 0; i < def->nseclabels; i++)
+            virSecurityDeviceLabelDefFree(def->seclabels[i]);
+        VIR_FREE(def->seclabels);
+    }
+
     VIR_FREE(def);
 }
 
@@ -5343,7 +5351,11 @@ error:
  * <target>, which is used by <serial> but not <smartcard>). */
 static int
 virDomainChrSourceDefParseXML(virDomainChrSourceDefPtr def,
-                              xmlNodePtr cur, unsigned int flags)
+                              xmlNodePtr cur, unsigned int flags,
+                              virDomainChrDefPtr chr_def,
+                              xmlXPathContextPtr ctxt,
+                              virSecurityLabelDefPtr* vmSeclabels,
+                              int nvmSeclabels)
 {
     char *bindHost = NULL;
     char *bindService = NULL;
@@ -5398,6 +5410,21 @@ virDomainChrSourceDefParseXML(virDomainChrSourceDefPtr def,
                     if (def->type == VIR_DOMAIN_CHR_TYPE_UDP)
                         VIR_FREE(mode);
                 }
+
+                /* Check for an optional seclabel override in <source/>. */
+                if (chr_def) {
+                    xmlNodePtr saved_node = ctxt->node;
+                    ctxt->node = cur;
+                    if (virSecurityDeviceLabelDefParseXML (&chr_def->seclabels,
+                                                           &chr_def->nseclabels,
+                                                           vmSeclabels,
+                                                           nvmSeclabels,
+                                                           ctxt) < 0) {
+                        ctxt->node = saved_node;
+                        goto error;
+                    }
+                    ctxt->node = saved_node;
+                }
             } else if (xmlStrEqual(cur->name, BAD_CAST "protocol")) {
                 if (protocol == NULL)
                     protocol = virXMLPropString(cur, "type");
@@ -5591,7 +5618,10 @@ virDomainChrDefNew(void) {
 static virDomainChrDefPtr
 virDomainChrDefParseXML(virCapsPtr caps,
                         virDomainDefPtr vmdef,
+                        xmlXPathContextPtr ctxt,
                         xmlNodePtr node,
+                        virSecurityLabelDefPtr* vmSeclabels,
+                        int nvmSeclabels,
                         unsigned int flags)
 {
     xmlNodePtr cur;
@@ -5622,7 +5652,8 @@ virDomainChrDefParseXML(virCapsPtr caps,
     }
 
     cur = node->children;
-    remaining = virDomainChrSourceDefParseXML(&def->source, cur, flags);
+    remaining = virDomainChrSourceDefParseXML(&def->source, cur, flags,
+                                              def, ctxt, vmSeclabels, nvmSeclabels);
     if (remaining < 0)
         goto error;
     if (remaining) {
@@ -5759,7 +5790,8 @@ virDomainSmartcardDefParseXML(xmlNodePtr node,
         }
 
         cur = node->children;
-        if (virDomainChrSourceDefParseXML(&def->data.passthru, cur, flags) < 0)
+        if (virDomainChrSourceDefParseXML(&def->data.passthru, cur, flags,
+                                          NULL, NULL, NULL, 0) < 0)
             goto error;
 
         if (def->data.passthru.type == VIR_DOMAIN_CHR_TYPE_SPICEVMC) {
@@ -7240,7 +7272,8 @@ virDomainRedirdevDefParseXML(const xmlNodePtr node,
             if (xmlStrEqual(cur->name, BAD_CAST "source")) {
                 int remaining;
 
-                remaining = virDomainChrSourceDefParseXML(&def->source.chr, cur, flags);
+                remaining = virDomainChrSourceDefParseXML(&def->source.chr, cur, flags,
+                                                          NULL, NULL, NULL, 0);
                 if (remaining != 0)
                     goto error;
             }
@@ -9282,7 +9315,10 @@ static virDomainDefPtr virDomainDefParseXML(virCapsPtr caps,
     for (i = 0 ; i < n ; i++) {
         virDomainChrDefPtr chr = virDomainChrDefParseXML(caps,
                                                          def,
+                                                         ctxt,
                                                          nodes[i],
+                                                         def->seclabels,
+                                                         def->nseclabels,
                                                          flags);
         if (!chr)
             goto error;
@@ -9309,7 +9345,10 @@ static virDomainDefPtr virDomainDefParseXML(virCapsPtr caps,
     for (i = 0 ; i < n ; i++) {
         virDomainChrDefPtr chr = virDomainChrDefParseXML(caps,
                                                          def,
+                                                         ctxt,
                                                          nodes[i],
+                                                         def->seclabels,
+                                                         def->nseclabels,
                                                          flags);
         if (!chr)
             goto error;
@@ -9339,7 +9378,10 @@ static virDomainDefPtr virDomainDefParseXML(virCapsPtr caps,
         bool create_stub = true;
         virDomainChrDefPtr chr = virDomainChrDefParseXML(caps,
                                                          def,
+                                                         ctxt,
                                                          nodes[i],
+                                                         def->seclabels,
+                                                         def->nseclabels,
                                                          flags);
         if (!chr)
             goto error;
@@ -9415,7 +9457,10 @@ static virDomainDefPtr virDomainDefParseXML(virCapsPtr caps,
     for (i = 0 ; i < n ; i++) {
         virDomainChrDefPtr chr = virDomainChrDefParseXML(caps,
                                                          def,
+                                                         ctxt,
                                                          nodes[i],
+                                                         def->seclabels,
+                                                         def->nseclabels,
                                                          flags);
         if (!chr)
             goto error;
@@ -12359,6 +12404,7 @@ virDomainChrDefFormat(virBufferPtr buf,
     const char *targetType = virDomainChrTargetTypeToString(def->deviceType,
                                                             def->targetType);
     bool tty_compat;
+    size_t n;
 
     int ret = 0;
 
@@ -12438,6 +12484,14 @@ virDomainChrDefFormat(virBufferPtr buf,
             return -1;
     }
 
+    /* Security label overrides, if any. */
+    if (def->seclabels && def->nseclabels > 0) {
+        virBufferAdjustIndent(buf, 2);
+        for (n = 0; n < def->nseclabels; n++)
+            virSecurityDeviceLabelDefFormat(buf, def->seclabels[n]);
+        virBufferAdjustIndent(buf, -2);
+    }
+
     virBufferAsprintf(buf, "    </%s>\n", elementName);
 
     return ret;
@@ -15262,6 +15316,21 @@ virDomainDiskDefGetSecurityLabelDef(virDomainDiskDefPtr def, const char *model)
     return NULL;
 }
 
+virSecurityDeviceLabelDefPtr
+virDomainChrDefGetSecurityLabelDef(virDomainChrDefPtr def, const char *model)
+{
+    int i;
+
+    if (def == NULL)
+        return NULL;
+
+    for (i = 0; i < def->nseclabels; i++) {
+        if (STREQ_NULLABLE(def->seclabels[i]->model, model))
+            return def->seclabels[i];
+    }
+    return NULL;
+}
+
 virSecurityLabelDefPtr
 virDomainDefAddSecurityLabelDef(virDomainDefPtr def, const char *model)
 {
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index 510406a..84f566f 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -966,6 +966,9 @@ struct _virDomainChrDef {
     virDomainChrSourceDef source;
 
     virDomainDeviceInfo info;
+
+    size_t nseclabels;
+    virSecurityDeviceLabelDefPtr *seclabels;
 };
 
 enum virDomainSmartcardType {
@@ -2123,6 +2126,9 @@ virDomainDefGetSecurityLabelDef(virDomainDefPtr def, const char *model);
 virSecurityDeviceLabelDefPtr
 virDomainDiskDefGetSecurityLabelDef(virDomainDiskDefPtr def, const char *model);
 
+virSecurityDeviceLabelDefPtr
+virDomainChrDefGetSecurityLabelDef(virDomainChrDefPtr def, const char *model);
+
 virSecurityLabelDefPtr
 virDomainDefAddSecurityLabelDef(virDomainDefPtr def, const char *model);
 
diff --git a/src/security/security_selinux.c b/src/security/security_selinux.c
index a7e2420..c47c872 100644
--- a/src/security/security_selinux.c
+++ b/src/security/security_selinux.c
@@ -1213,38 +1213,58 @@ done:
 
 static int
 virSecuritySELinuxSetSecurityChardevLabel(virDomainDefPtr def,
-                                          virDomainChrSourceDefPtr dev)
+                                          virDomainChrDefPtr dev,
+                                          virDomainChrSourceDefPtr dev_source)
 
 {
-    virSecurityLabelDefPtr secdef;
+    virSecurityLabelDefPtr seclabel;
+    virSecurityDeviceLabelDefPtr chr_seclabel = NULL;
+    char *imagelabel;
     char *in = NULL, *out = NULL;
     int ret = -1;
 
-    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
-    if (secdef == NULL)
+    seclabel = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
+    if (seclabel == NULL)
         return -1;
 
-    if (secdef->norelabel)
+    if (dev)
+        chr_seclabel = virDomainChrDefGetSecurityLabelDef(dev,
+                                                          SECURITY_SELINUX_NAME);
+
+    if (seclabel->norelabel || (chr_seclabel && chr_seclabel->norelabel))
         return 0;
 
-    switch (dev->type) {
+    if (chr_seclabel)
+        imagelabel = chr_seclabel->label;
+    else
+        imagelabel = seclabel->imagelabel;
+
+    switch (dev_source->type) {
     case VIR_DOMAIN_CHR_TYPE_DEV:
     case VIR_DOMAIN_CHR_TYPE_FILE:
-        ret = virSecuritySELinuxSetFilecon(dev->data.file.path, secdef->imagelabel);
+        ret = virSecuritySELinuxSetFilecon(dev_source->data.file.path, imagelabel);
+        break;
+
+    case VIR_DOMAIN_CHR_TYPE_UNIX:
+        if (!dev_source->data.nix.listen) {
+            if (virSecuritySELinuxSetFilecon(dev_source->data.file.path, imagelabel) < 0)
+                goto done;
+        }
+        ret = 0;
         break;
 
     case VIR_DOMAIN_CHR_TYPE_PIPE:
-        if ((virAsprintf(&in, "%s.in", dev->data.file.path) < 0) ||
-            (virAsprintf(&out, "%s.out", dev->data.file.path) < 0)) {
+        if ((virAsprintf(&in, "%s.in", dev_source->data.file.path) < 0) ||
+            (virAsprintf(&out, "%s.out", dev_source->data.file.path) < 0)) {
             virReportOOMError();
             goto done;
         }
         if (virFileExists(in) && virFileExists(out)) {
-            if ((virSecuritySELinuxSetFilecon(in, secdef->imagelabel) < 0) ||
-                (virSecuritySELinuxSetFilecon(out, secdef->imagelabel) < 0)) {
+            if ((virSecuritySELinuxSetFilecon(in, imagelabel) < 0) ||
+                (virSecuritySELinuxSetFilecon(out, imagelabel) < 0)) {
                 goto done;
             }
-        } else if (virSecuritySELinuxSetFilecon(dev->data.file.path, secdef->imagelabel) < 0) {
+        } else if (virSecuritySELinuxSetFilecon(dev_source->data.file.path, imagelabel) < 0) {
             goto done;
         }
         ret = 0;
@@ -1263,30 +1283,44 @@ done:
 
 static int
 virSecuritySELinuxRestoreSecurityChardevLabel(virDomainDefPtr def,
-                                              virDomainChrSourceDefPtr dev)
+                                              virDomainChrDefPtr dev,
+                                              virDomainChrSourceDefPtr dev_source)
 
 {
-    virSecurityLabelDefPtr secdef;
+    virSecurityLabelDefPtr seclabel;
+    virSecurityDeviceLabelDefPtr chr_seclabel = NULL;
     char *in = NULL, *out = NULL;
     int ret = -1;
 
-    secdef = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
-    if (secdef == NULL)
+    seclabel = virDomainDefGetSecurityLabelDef(def, SECURITY_SELINUX_NAME);
+    if (seclabel == NULL)
         return -1;
 
-    if (secdef->norelabel)
+    if (dev)
+        chr_seclabel = virDomainChrDefGetSecurityLabelDef(dev,
+                                                          SECURITY_SELINUX_NAME);
+    if (seclabel->norelabel || (chr_seclabel && chr_seclabel->norelabel))
         return 0;
 
-    switch (dev->type) {
+    switch (dev_source->type) {
     case VIR_DOMAIN_CHR_TYPE_DEV:
     case VIR_DOMAIN_CHR_TYPE_FILE:
-        if (virSecuritySELinuxRestoreSecurityFileLabel(dev->data.file.path) < 0)
+        if (virSecuritySELinuxRestoreSecurityFileLabel(dev_source->data.file.path) < 0)
             goto done;
         ret = 0;
         break;
+
+    case VIR_DOMAIN_CHR_TYPE_UNIX:
+        if (!dev_source->data.nix.listen) {
+            if (virSecuritySELinuxRestoreSecurityFileLabel(dev_source->data.file.path) < 0)
+                goto done;
+        }
+        ret = 0;
+        break;
+
     case VIR_DOMAIN_CHR_TYPE_PIPE:
-        if ((virAsprintf(&out, "%s.out", dev->data.file.path) < 0) ||
-            (virAsprintf(&in, "%s.in", dev->data.file.path) < 0)) {
+        if ((virAsprintf(&out, "%s.out", dev_source->data.file.path) < 0) ||
+            (virAsprintf(&in, "%s.in", dev_source->data.file.path) < 0)) {
             virReportOOMError();
             goto done;
         }
@@ -1295,7 +1329,7 @@ virSecuritySELinuxRestoreSecurityChardevLabel(virDomainDefPtr def,
                 (virSecuritySELinuxRestoreSecurityFileLabel(in) < 0)) {
                 goto done;
             }
-        } else if (virSecuritySELinuxRestoreSecurityFileLabel(dev->data.file.path) < 0) {
+        } else if (virSecuritySELinuxRestoreSecurityFileLabel(dev_source->data.file.path) < 0) {
             goto done;
         }
         ret = 0;
@@ -1323,7 +1357,7 @@ virSecuritySELinuxRestoreSecurityChardevCallback(virDomainDefPtr def,
         dev->targetType == VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_SERIAL)
         return 0;
 
-    return virSecuritySELinuxRestoreSecurityChardevLabel(def, &dev->source);
+    return virSecuritySELinuxRestoreSecurityChardevLabel(def, dev, &dev->source);
 }
 
 
@@ -1345,7 +1379,7 @@ virSecuritySELinuxRestoreSecuritySmartcardCallback(virDomainDefPtr def,
         return virSecuritySELinuxRestoreSecurityFileLabel(database);
 
     case VIR_DOMAIN_SMARTCARD_TYPE_PASSTHROUGH:
-        return virSecuritySELinuxRestoreSecurityChardevLabel(def, &dev->data.passthru);
+        return virSecuritySELinuxRestoreSecurityChardevLabel(def, NULL, &dev->data.passthru);
 
     default:
         virReportError(VIR_ERR_INTERNAL_ERROR,
@@ -1703,7 +1737,7 @@ virSecuritySELinuxSetSecurityChardevCallback(virDomainDefPtr def,
         dev->targetType == VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_SERIAL)
         return 0;
 
-    return virSecuritySELinuxSetSecurityChardevLabel(def, &dev->source);
+    return virSecuritySELinuxSetSecurityChardevLabel(def, dev, &dev->source);
 }
 
 
@@ -1727,7 +1761,7 @@ virSecuritySELinuxSetSecuritySmartcardCallback(virDomainDefPtr def,
         return virSecuritySELinuxSetFilecon(database, data->content_context);
 
     case VIR_DOMAIN_SMARTCARD_TYPE_PASSTHROUGH:
-        return virSecuritySELinuxSetSecurityChardevLabel(def, &dev->data.passthru);
+        return virSecuritySELinuxSetSecurityChardevLabel(def, NULL, &dev->data.passthru);
 
     default:
         virReportError(VIR_ERR_INTERNAL_ERROR,
-- 
1.7.10.4




More information about the libvir-list mailing list