[libvirt] [PATCH 5/6] qemu: Add support for TLS X.509 path

John Ferlan jferlan at redhat.com
Tue Jun 14 00:40:27 UTC 2016


When building a chardev device string for tcp, add the necessary pieces to
access provide the TLS X.509 path to qemu.  This includes generating the
'tls-creds-x509' object and then adding the 'tls-creds' parameter to the
VIR_DOMAIN_CHR_TYPE_TCP command line.

Since this is providing a new file which the domain will need to read,
make the appropriate security backend adjustments to add the path to the
TLS credential directory.

xxx?? Do we need to add this to the private structure to recreate? xxxx

Finally add the tests for the qemu command line

Signed-off-by: John Ferlan <jferlan at redhat.com>
---
 src/conf/domain_audit.c                            |  2 +
 src/conf/virchrdev.c                               |  1 +
 src/qemu/qemu_command.c                            | 72 ++++++++++++++++++++++
 src/security/security_dac.c                        | 11 +++-
 src/security/security_selinux.c                    | 10 +++
 src/security/virt-aa-helper.c                      | 12 +++-
 .../qemuxml2argv-serial-tcp-tlsx509-chardev.args   | 32 ++++++++++
 tests/qemuxml2argvtest.c                           |  3 +
 8 files changed, 141 insertions(+), 2 deletions(-)
 create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-tlsx509-chardev.args

diff --git a/src/conf/domain_audit.c b/src/conf/domain_audit.c
index 36a3cf6..78bc092 100644
--- a/src/conf/domain_audit.c
+++ b/src/conf/domain_audit.c
@@ -85,6 +85,8 @@ virDomainAuditChardevPath(virDomainChrSourceDefPtr chr)
         return chr->data.nix.path;
 
     case VIR_DOMAIN_CHR_TYPE_TCP:
+        return chr->data.tcp.tlspath;
+
     case VIR_DOMAIN_CHR_TYPE_UDP:
     case VIR_DOMAIN_CHR_TYPE_NULL:
     case VIR_DOMAIN_CHR_TYPE_VC:
diff --git a/src/conf/virchrdev.c b/src/conf/virchrdev.c
index bca9c37..93bc57f 100644
--- a/src/conf/virchrdev.c
+++ b/src/conf/virchrdev.c
@@ -360,6 +360,7 @@ int virChrdevOpen(virChrdevsPtr devs,
     case VIR_DOMAIN_CHR_TYPE_UNIX:
         path = source->data.nix.path;
         break;
+    /* Do I have to do anything for VIR_DOMAIN_CHR_TYPE_TCP: */
     default:
         virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                        _("Unsupported device type '%s'"),
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index 490260f..3656683 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -701,6 +701,58 @@ qemuBuildRBDSecinfoURI(virBufferPtr buf,
 }
 
 
+/* qemuBuildTLSx509BackendProps:
+ * @tlspath: path to the TLS credentials
+ * @listen: boolen listen for client or server setting
+ * @alias: Alias for the parent (this code will add a "_tls0" to alias)
+ * @propsret: json properties to return
+ *
+ * Create a backend string for the tls-creds-x509 object.
+ *
+ * Returns 0 on success, -1 on failure with error set.
+ */
+static int
+qemuBuildTLSx509BackendProps(const char *tlspath,
+                             bool listen,
+                             const char *inalias,
+                             virQEMUCapsPtr qemuCaps,
+                             virJSONValuePtr *propsret)
+{
+    virBuffer buf = VIR_BUFFER_INITIALIZER;
+    char *path = NULL;
+    char *alias = NULL;
+    int ret = -1;
+
+    if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_OBJECT_TLS_CREDS_X509)) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                       _("tls-creds not supported in this QEMU binary"));
+        return -1;
+    }
+
+    qemuBufferEscapeComma(&buf, tlspath);
+    if (virBufferCheckError(&buf) < 0)
+        goto cleanup;
+    path = virBufferContentAndReset(&buf);
+
+    if (virAsprintf(&alias, "obj%s_tls0", inalias) < 0)
+        goto cleanup;
+
+    if (virJSONValueObjectCreate(propsret,
+                                 "s:dir", path,
+                                 "s:endpoint", (listen ? "server": "client"),
+                                 NULL) < 0)
+        goto cleanup;
+
+    ret = 0;
+
+ cleanup:
+    virBufferFreeAndReset(&buf);
+    VIR_FREE(path);
+    VIR_FREE(alias);
+    return ret;
+}
+
+
 #define QEMU_DEFAULT_NBD_PORT "10809"
 
 static char *
@@ -4657,6 +4709,7 @@ qemuBuildChrChardevFileStr(virLogManagerPtr logManager,
     return 0;
 }
 
+
 /* This function outputs a -chardev command line option which describes only the
  * host side of the character device */
 static char *
@@ -4668,6 +4721,7 @@ qemuBuildChrChardevStr(virLogManagerPtr logManager,
                        virQEMUCapsPtr qemuCaps)
 {
     virBuffer buf = VIR_BUFFER_INITIALIZER;
+    virJSONValuePtr props = NULL;
     bool telnet;
 
     switch (dev->type) {
@@ -4744,6 +4798,23 @@ qemuBuildChrChardevStr(virLogManagerPtr logManager,
                           dev->data.tcp.service,
                           telnet ? ",telnet" : "",
                           dev->data.tcp.listen ? ",server,nowait" : "");
+
+        if (dev->data.tcp.tlspath) {
+            char *tmp;
+            if (qemuBuildTLSx509BackendStr(dev->data.tcp.tlspath,
+                                           dev->data.tcp.listen,
+                                           alias, qemuCaps, &props) < 0)
+                goto error;
+
+            if (!(tmp = virQEMUBuildObjectCommandlineFromJSON("tls-creds-x509",
+                                                              alias, props)))
+                goto error;
+
+            virCommandAddArgList(cmd, "-object", tmp, NULL);
+            VIR_FREE(tmp);
+
+            virBufferAsprintf(&buf, ",tls-creds=obj%s_tls0", alias);
+        }
         break;
 
     case VIR_DOMAIN_CHR_TYPE_UNIX:
@@ -4799,6 +4870,7 @@ qemuBuildChrChardevStr(virLogManagerPtr logManager,
 
  error:
     virBufferFreeAndReset(&buf);
+    virJSONValueFree(props);
     return NULL;
 }
 
diff --git a/src/security/security_dac.c b/src/security/security_dac.c
index 442ce70..a2c971b 100644
--- a/src/security/security_dac.c
+++ b/src/security/security_dac.c
@@ -881,13 +881,22 @@ virSecurityDACSetChardevLabel(virSecurityManagerPtr mgr,
         ret = 0;
         break;
 
+    case VIR_DOMAIN_CHR_TYPE_TCP:
+        if (!dev_source->data.nix.listen && dev_source->data.tcp.tlspath) {
+            if (virSecurityDACSetOwnership(priv, NULL,
+                                           dev_source->data.tcp.tlspath,
+                                           user, group) < 0)
+                goto done;
+        }
+        ret = 0;
+        break;
+
     case VIR_DOMAIN_CHR_TYPE_SPICEPORT:
     case VIR_DOMAIN_CHR_TYPE_NULL:
     case VIR_DOMAIN_CHR_TYPE_VC:
     case VIR_DOMAIN_CHR_TYPE_PTY:
     case VIR_DOMAIN_CHR_TYPE_STDIO:
     case VIR_DOMAIN_CHR_TYPE_UDP:
-    case VIR_DOMAIN_CHR_TYPE_TCP:
     case VIR_DOMAIN_CHR_TYPE_SPICEVMC:
     case VIR_DOMAIN_CHR_TYPE_NMDM:
     case VIR_DOMAIN_CHR_TYPE_LAST:
diff --git a/src/security/security_selinux.c b/src/security/security_selinux.c
index aa61767..1793a76 100644
--- a/src/security/security_selinux.c
+++ b/src/security/security_selinux.c
@@ -1831,6 +1831,16 @@ virSecuritySELinuxSetChardevLabel(virSecurityManagerPtr mgr,
         ret = 0;
         break;
 
+    case VIR_DOMAIN_CHR_TYPE_TCP:
+        if (!dev_source->data.nix.listen && dev_source->data.tcp.tlspath) {
+            if (virSecuritySELinuxSetFilecon(mgr,
+                                             dev_source->data.tcp.tlspath,
+                                             imagelabel) < 0)
+                goto done;
+        }
+        ret = 0;
+        break;
+
     case VIR_DOMAIN_CHR_TYPE_PIPE:
         if ((virAsprintf(&in, "%s.in", dev_source->data.file.path) < 0) ||
             (virAsprintf(&out, "%s.out", dev_source->data.file.path) < 0))
diff --git a/src/security/virt-aa-helper.c b/src/security/virt-aa-helper.c
index 9eafaee..200e5ed 100644
--- a/src/security/virt-aa-helper.c
+++ b/src/security/virt-aa-helper.c
@@ -924,7 +924,7 @@ get_files(vahControl * ctl)
             goto cleanup;
     }
 
-    for (i = 0; i < ctl->def->nserials; i++)
+    for (i = 0; i < ctl->def->nserials; i++) {
         if (ctl->def->serials[i] &&
             (ctl->def->serials[i]->source.type == VIR_DOMAIN_CHR_TYPE_PTY ||
              ctl->def->serials[i]->source.type == VIR_DOMAIN_CHR_TYPE_DEV ||
@@ -938,6 +938,16 @@ get_files(vahControl * ctl)
                                      "rw",
                                      ctl->def->serials[i]->source.type) != 0)
                 goto cleanup;
+        if (ctl->def->serials[i] &&
+            ctl->def->serials[i]->source.type == VIR_DOMAIN_CHR_TYPE_TCP &&
+            ctl->def->serials[i]->source.data.tcp.tlspath &&
+            ctl->def->serials[i]->source.data.tcp.tlspath[0] != '\0')
+            if (vah_add_file_chardev(&buf,
+                                     ctl->def->serials[i]->source.data.tcp.tlspath,
+                                     "rw",
+                                     ctl->def->serials[i]->source.type) != 0)
+                goto cleanup;
+    }
 
     for (i = 0; i < ctl->def->nconsoles; i++)
         if (ctl->def->consoles[i] &&
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-tlsx509-chardev.args b/tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-tlsx509-chardev.args
new file mode 100644
index 0000000..83841f1
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-tlsx509-chardev.args
@@ -0,0 +1,32 @@
+LC_ALL=C \
+PATH=/bin \
+HOME=/home/test \
+USER=test \
+LOGNAME=test \
+QEMU_AUDIO_DRV=none \
+/usr/bin/qemu \
+-name QEMUGuest1 \
+-S \
+-M pc \
+-m 214 \
+-smp 1 \
+-uuid c7a5fdbd-edaf-9455-926a-d65c16db1809 \
+-nographic \
+-nodefconfig \
+-nodefaults \
+-chardev socket,id=charmonitor,path=/tmp/lib/domain--1-QEMUGuest1/monitor.sock,\
+server,nowait \
+-mon chardev=charmonitor,id=monitor,mode=readline \
+-no-acpi \
+-boot c \
+-usb \
+-drive file=/dev/HostVG/QEMUGuest1,format=raw,if=none,id=drive-ide0-0-0 \
+-device ide-drive,bus=ide.0,unit=0,drive=drive-ide0-0-0,id=ide0-0-0 \
+-chardev udp,id=charserial0,host=127.0.0.1,port=2222,localaddr=127.0.0.1,\
+localport=1111 \
+-device isa-serial,chardev=charserial0,id=serial0 \
+-object tls-creds-x509,id=objserial1_tls0,dir=/tmp/x509/certdir,endpoint=client \
+-chardev socket,id=charserial1,host=127.0.0.1,port=5555,\
+tls-creds=objserial1_tls0 \
+-device isa-serial,chardev=charserial1,id=serial1 \
+-device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x3
diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c
index 573162f..55c58a9 100644
--- a/tests/qemuxml2argvtest.c
+++ b/tests/qemuxml2argvtest.c
@@ -1069,6 +1069,9 @@ mymain(void)
             QEMU_CAPS_CHARDEV, QEMU_CAPS_NODEFCONFIG);
     DO_TEST("serial-tcp-telnet-chardev",
             QEMU_CAPS_CHARDEV, QEMU_CAPS_NODEFCONFIG);
+    DO_TEST("serial-tcp-tlsx509-chardev",
+            QEMU_CAPS_CHARDEV, QEMU_CAPS_NODEFCONFIG,
+            QEMU_CAPS_OBJECT_TLS_CREDS_X509);
     DO_TEST("serial-many-chardev",
             QEMU_CAPS_CHARDEV, QEMU_CAPS_NODEFCONFIG);
     DO_TEST("parallel-tcp-chardev",
-- 
2.5.5




More information about the libvir-list mailing list