[libvirt] [PATCH v8 0/5] Add native TLS encrypted chardev TCP support

v7: http://www.redhat.com/archives/libvir-list/2016-September/msg00729.html Differences in v8 1. Update to use 2.4.0 instead of 2.3.0 2. Alter text in qemu.conf as requested in review of v7 3. After update to top of branch found one more virDomainChrDefNew in a recent commit that needed a NULL parameter John Ferlan (5): domain: Add optional 'tls' attribute for TCP chardev conf: Introduce {default|chardev}_tls_x509_secret_uuid qemu: Introduce qemuDomainChardevPrivatePtr qemu: Add a secret object to/for a chardev tcp with secret qemu: Add the ability to hotplug a secret object for TCP chardev TLS docs/formatdomain.html.in | 21 +++ docs/schemas/domaincommon.rng | 5 + src/conf/domain_conf.c | 51 ++++++-- src/conf/domain_conf.h | 5 +- src/libxl/libxl_domain.c | 2 +- src/lxc/lxc_native.c | 2 +- src/qemu/libvirtd_qemu.aug | 2 + src/qemu/qemu.conf | 24 ++++ src/qemu/qemu_command.c | 35 ++++- src/qemu/qemu_command.h | 1 + src/qemu/qemu_conf.c | 22 ++++ src/qemu/qemu_conf.h | 3 + src/qemu/qemu_domain.c | 143 ++++++++++++++++++++- src/qemu/qemu_domain.h | 30 ++++- src/qemu/qemu_driver.c | 2 +- src/qemu/qemu_hotplug.c | 64 ++++++++- src/qemu/qemu_hotplug.h | 3 +- src/qemu/qemu_parse_command.c | 4 +- src/qemu/qemu_process.c | 6 +- src/qemu/test_libvirtd_qemu.aug.in | 2 + src/vz/vz_sdk.c | 2 +- src/xenconfig/xen_sxpr.c | 2 +- src/xenconfig/xen_xl.c | 2 +- tests/qemuhotplugtest.c | 2 +- ...emuxml2argv-serial-tcp-tlsx509-chardev-tls.args | 30 +++++ ...qemuxml2argv-serial-tcp-tlsx509-chardev-tls.xml | 50 +++++++ .../qemuxml2argv-serial-tcp-tlsx509-chardev.xml | 2 +- ...xml2argv-serial-tcp-tlsx509-secret-chardev.args | 38 ++++++ ...uxml2argv-serial-tcp-tlsx509-secret-chardev.xml | 50 +++++++ tests/qemuxml2argvtest.c | 22 ++++ ...muxml2xmlout-serial-tcp-tlsx509-chardev-tls.xml | 1 + .../qemuxml2xmlout-serial-tcp-tlsx509-chardev.xml | 2 +- tests/qemuxml2xmltest.c | 1 + 33 files changed, 594 insertions(+), 37 deletions(-) create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-tlsx509-chardev-tls.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-tlsx509-chardev-tls.xml create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-tlsx509-secret-chardev.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-tlsx509-secret-chardev.xml create mode 120000 tests/qemuxml2xmloutdata/qemuxml2xmlout-serial-tcp-tlsx509-chardev-tls.xml -- 2.7.4

Add an optional "tls='yes'" option for a TCP chardev for the express purpose to enable setting up TLS for the chardev. This will assume that the qemu.conf settings have been adjusted as well as the environment configured properly. Signed-off-by: John Ferlan <jferlan@redhat.com> --- docs/formatdomain.html.in | 21 +++++++++ docs/schemas/domaincommon.rng | 5 +++ src/conf/domain_conf.c | 22 +++++++++- src/conf/domain_conf.h | 1 + src/qemu/qemu_command.c | 3 +- src/qemu/qemu_hotplug.c | 3 +- ...emuxml2argv-serial-tcp-tlsx509-chardev-tls.args | 30 +++++++++++++ ...qemuxml2argv-serial-tcp-tlsx509-chardev-tls.xml | 50 ++++++++++++++++++++++ .../qemuxml2argv-serial-tcp-tlsx509-chardev.xml | 2 +- tests/qemuxml2argvtest.c | 3 ++ ...muxml2xmlout-serial-tcp-tlsx509-chardev-tls.xml | 1 + .../qemuxml2xmlout-serial-tcp-tlsx509-chardev.xml | 2 +- tests/qemuxml2xmltest.c | 1 + 13 files changed, 139 insertions(+), 5 deletions(-) create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-tlsx509-chardev-tls.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-tlsx509-chardev-tls.xml create mode 120000 tests/qemuxml2xmloutdata/qemuxml2xmlout-serial-tcp-tlsx509-chardev-tls.xml diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in index 1266e9d..010530e 100644 --- a/docs/formatdomain.html.in +++ b/docs/formatdomain.html.in @@ -6203,6 +6203,27 @@ qemu-kvm -net nic,model=? /dev/null </devices> ...</pre> + <p> + <span class="since">Since 2.4.0,</span> some hypervisors support using + a TLS X.509 certificate environment in order to encrypt all serial TCP + connections via a hypervisor configuration option. In order to enable + TLS for the domain an optional attribute <code>tls</code> can be set to + "yes". Combined with the hypervisor's capability to utilize the TLS + environment allows for the character device to use the encrypted + communication. If the attribute is not present, then the default + setting is "no". + </p> +<pre> + ... + <devices> + <serial type="tcp"> + <source mode='connect' host="127.0.0.1" service="5555" tls="yes"/> + <protocol type="raw"/> + <target port="0"/> + </serial> + </devices> + ...</pre> + <h6><a name="elementsCharUDP">UDP network console</a></h6> <p> diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng index 6eeb4e9..362b90d 100644 --- a/docs/schemas/domaincommon.rng +++ b/docs/schemas/domaincommon.rng @@ -3453,6 +3453,11 @@ <ref name="virOnOff"/> </attribute> </optional> + <optional> + <attribute name="tls"> + <ref name="virYesNo"/> + </attribute> + </optional> <zeroOrMore> <ref name='devSeclabel'/> </zeroOrMore> diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index f562323..1f7c43f 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -1961,6 +1961,8 @@ virDomainChrSourceDefCopy(virDomainChrSourceDefPtr dest, if (VIR_STRDUP(dest->data.tcp.service, src->data.tcp.service) < 0) return -1; + + dest->data.tcp.haveTLS = src->data.tcp.haveTLS; break; case VIR_DOMAIN_CHR_TYPE_UNIX: @@ -9999,6 +10001,7 @@ virDomainChrSourceDefParseXML(virDomainChrSourceDefPtr def, char *master = NULL; char *slave = NULL; char *append = NULL; + char *haveTLS = NULL; int remaining = 0; while (cur != NULL) { @@ -10006,6 +10009,8 @@ virDomainChrSourceDefParseXML(virDomainChrSourceDefPtr def, if (xmlStrEqual(cur->name, BAD_CAST "source")) { if (!mode) mode = virXMLPropString(cur, "mode"); + if (!haveTLS) + haveTLS = virXMLPropString(cur, "tls"); switch ((virDomainChrType) def->type) { case VIR_DOMAIN_CHR_TYPE_FILE: @@ -10182,6 +10187,15 @@ virDomainChrSourceDefParseXML(virDomainChrSourceDefPtr def, def->data.tcp.listen = true; } + if (haveTLS && + (def->data.tcp.haveTLS = + virTristateBoolTypeFromString(haveTLS)) <= 0) { + virReportError(VIR_ERR_XML_ERROR, + _("unknown chardev 'tls' setting '%s'"), + haveTLS); + goto error; + } + if (!protocol) def->data.tcp.protocol = VIR_DOMAIN_CHR_TCP_PROTOCOL_RAW; else if ((def->data.tcp.protocol = @@ -10266,6 +10280,7 @@ virDomainChrSourceDefParseXML(virDomainChrSourceDefPtr def, VIR_FREE(append); VIR_FREE(logappend); VIR_FREE(logfile); + VIR_FREE(haveTLS); return remaining; @@ -21417,7 +21432,12 @@ virDomainChrSourceDefFormat(virBufferPtr buf, virBufferAsprintf(buf, "<source mode='%s' ", def->data.tcp.listen ? "bind" : "connect"); virBufferEscapeString(buf, "host='%s' ", def->data.tcp.host); - virBufferEscapeString(buf, "service='%s'/>\n", def->data.tcp.service); + virBufferEscapeString(buf, "service='%s'", def->data.tcp.service); + if (def->data.tcp.haveTLS != VIR_TRISTATE_BOOL_ABSENT) + virBufferAsprintf(buf, " tls='%s'", + virTristateBoolTypeToString(def->data.tcp.haveTLS)); + virBufferAddLit(buf, "/>\n"); + virBufferAsprintf(buf, "<protocol type='%s'/>\n", virDomainChrTcpProtocolTypeToString( def->data.tcp.protocol)); diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index a70bc21..da203c3 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -1094,6 +1094,7 @@ struct _virDomainChrSourceDef { bool listen; int protocol; bool tlscreds; + int haveTLS; /* enum virTristateBool */ } tcp; struct { char *bindHost; diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 578ff8b..b290ade 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -5002,7 +5002,8 @@ qemuBuildChrChardevStr(virLogManagerPtr logManager, telnet ? ",telnet" : "", dev->data.tcp.listen ? ",server,nowait" : ""); - if (cfg->chardevTLS) { + if (cfg->chardevTLS && + dev->data.tcp.haveTLS == VIR_TRISTATE_BOOL_YES) { char *objalias = NULL; if (qemuBuildTLSx509CommandLine(cmd, cfg->chardevTLSx509certdir, diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c index 72dd93b..419296e 100644 --- a/src/qemu/qemu_hotplug.c +++ b/src/qemu/qemu_hotplug.c @@ -1677,7 +1677,8 @@ int qemuDomainAttachChrDevice(virQEMUDriverPtr driver, if (qemuDomainChrPreInsert(vmdef, chr) < 0) goto cleanup; - if (cfg->chardevTLS) { + if (cfg->chardevTLS && + dev->data.tcp.haveTLS == VIR_TRISTATE_BOOL_YES) { if (qemuBuildTLSx509BackendProps(cfg->chardevTLSx509certdir, dev->data.tcp.listen, cfg->chardevTLSx509verify, diff --git a/tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-tlsx509-chardev-tls.args b/tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-tlsx509-chardev-tls.args new file mode 100644 index 0000000..cac0d85 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-tlsx509-chardev-tls.args @@ -0,0 +1,30 @@ +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,sockets=1,cores=1,threads=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 \ +-chardev socket,id=charserial1,host=127.0.0.1,port=5555 \ +-device isa-serial,chardev=charserial1,id=serial1 \ +-device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x3 diff --git a/tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-tlsx509-chardev-tls.xml b/tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-tlsx509-chardev-tls.xml new file mode 100644 index 0000000..debc69b --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-tlsx509-chardev-tls.xml @@ -0,0 +1,50 @@ +<domain type='qemu'> + <name>QEMUGuest1</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory unit='KiB'>219136</memory> + <currentMemory unit='KiB'>219136</currentMemory> + <vcpu placement='static'>1</vcpu> + <os> + <type arch='i686' machine='pc'>hvm</type> + <boot dev='hd'/> + </os> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <emulator>/usr/bin/qemu</emulator> + <disk type='block' device='disk'> + <source dev='/dev/HostVG/QEMUGuest1'/> + <target dev='hda' bus='ide'/> + <address type='drive' controller='0' bus='0' target='0' unit='0'/> + </disk> + <controller type='usb' index='0'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x2'/> + </controller> + <controller type='ide' index='0'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/> + </controller> + <controller type='pci' index='0' model='pci-root'/> + <serial type='udp'> + <source mode='bind' host='127.0.0.1' service='1111'/> + <source mode='connect' host='127.0.0.1' service='2222'/> + <target port='0'/> + </serial> + <serial type='tcp'> + <source mode='connect' host='127.0.0.1' service='5555' tls='no'/> + <protocol type='raw'/> + <target port='0'/> + </serial> + <console type='udp'> + <source mode='bind' host='127.0.0.1' service='1111'/> + <source mode='connect' host='127.0.0.1' service='2222'/> + <target type='serial' port='0'/> + </console> + <input type='mouse' bus='ps2'/> + <input type='keyboard' bus='ps2'/> + <memballoon model='virtio'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/> + </memballoon> + </devices> +</domain> diff --git a/tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-tlsx509-chardev.xml b/tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-tlsx509-chardev.xml index 1618b02..1d7896d 100644 --- a/tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-tlsx509-chardev.xml +++ b/tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-tlsx509-chardev.xml @@ -27,7 +27,7 @@ <target port='0'/> </serial> <serial type='tcp'> - <source mode='connect' host='127.0.0.1' service='5555'/> + <source mode='connect' host='127.0.0.1' service='5555' tls='yes'/> <protocol type='raw'/> <target port='0'/> </serial> diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index 4b9ecb8..41adff4 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -1150,6 +1150,9 @@ mymain(void) DO_TEST("serial-tcp-tlsx509-chardev", QEMU_CAPS_CHARDEV, QEMU_CAPS_NODEFCONFIG, QEMU_CAPS_OBJECT_TLS_CREDS_X509); + DO_TEST("serial-tcp-tlsx509-chardev-tls", + QEMU_CAPS_CHARDEV, QEMU_CAPS_NODEFCONFIG, + QEMU_CAPS_OBJECT_TLS_CREDS_X509); driver.config->chardevTLS = 0; VIR_FREE(driver.config->chardevTLSx509certdir); DO_TEST("serial-many-chardev", diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-serial-tcp-tlsx509-chardev-tls.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-serial-tcp-tlsx509-chardev-tls.xml new file mode 120000 index 0000000..3453497 --- /dev/null +++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-serial-tcp-tlsx509-chardev-tls.xml @@ -0,0 +1 @@ +../qemuxml2argvdata/qemuxml2argv-serial-tcp-tlsx509-chardev-tls.xml \ No newline at end of file diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-serial-tcp-tlsx509-chardev.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-serial-tcp-tlsx509-chardev.xml index 832e2a2..23c244b 100644 --- a/tests/qemuxml2xmloutdata/qemuxml2xmlout-serial-tcp-tlsx509-chardev.xml +++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-serial-tcp-tlsx509-chardev.xml @@ -32,7 +32,7 @@ <target port='0'/> </serial> <serial type='tcp'> - <source mode='connect' host='127.0.0.1' service='5555'/> + <source mode='connect' host='127.0.0.1' service='5555' tls='yes'/> <protocol type='raw'/> <target port='0'/> </serial> diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c index 4b58986..02fe32e 100644 --- a/tests/qemuxml2xmltest.c +++ b/tests/qemuxml2xmltest.c @@ -534,6 +534,7 @@ mymain(void) DO_TEST("serial-udp", NONE); DO_TEST("serial-tcp-telnet", NONE); DO_TEST("serial-tcp-tlsx509-chardev", NONE); + DO_TEST("serial-tcp-tlsx509-chardev-tls", NONE); DO_TEST("serial-many", NONE); DO_TEST("serial-spiceport", NONE); DO_TEST("serial-spiceport-nospice", NONE); -- 2.7.4

On Fri, Oct 07, 2016 at 07:00:26AM -0400, John Ferlan wrote:
Add an optional "tls='yes'" option for a TCP chardev for the express purpose to enable setting up TLS for the chardev. This will assume that the qemu.conf settings have been adjusted as well as the environment configured properly.
Signed-off-by: John Ferlan <jferlan@redhat.com> --- docs/formatdomain.html.in | 21 +++++++++ docs/schemas/domaincommon.rng | 5 +++ src/conf/domain_conf.c | 22 +++++++++- src/conf/domain_conf.h | 1 + src/qemu/qemu_command.c | 3 +- src/qemu/qemu_hotplug.c | 3 +- ...emuxml2argv-serial-tcp-tlsx509-chardev-tls.args | 30 +++++++++++++ ...qemuxml2argv-serial-tcp-tlsx509-chardev-tls.xml | 50 ++++++++++++++++++++++ .../qemuxml2argv-serial-tcp-tlsx509-chardev.xml | 2 +- tests/qemuxml2argvtest.c | 3 ++ ...muxml2xmlout-serial-tcp-tlsx509-chardev-tls.xml | 1 + .../qemuxml2xmlout-serial-tcp-tlsx509-chardev.xml | 2 +- tests/qemuxml2xmltest.c | 1 + 13 files changed, 139 insertions(+), 5 deletions(-) create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-tlsx509-chardev-tls.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-tlsx509-chardev-tls.xml create mode 120000 tests/qemuxml2xmloutdata/qemuxml2xmlout-serial-tcp-tlsx509-chardev-tls.xml
diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in index 1266e9d..010530e 100644 --- a/docs/formatdomain.html.in +++ b/docs/formatdomain.html.in @@ -6203,6 +6203,27 @@ qemu-kvm -net nic,model=? /dev/null </devices> ...</pre>
+ <p> + <span class="since">Since 2.4.0,</span> some hypervisors support using + a TLS X.509 certificate environment in order to encrypt all serial TCP + connections via a hypervisor configuration option. In order to enable + TLS for the domain an optional attribute <code>tls</code> can be set to + "yes". Combined with the hypervisor's capability to utilize the TLS + environment allows for the character device to use the encrypted + communication. If the attribute is not present, then the default + setting is "no".
This is not correct in case of QEMU. Before this patch the default was based on chardev_tls from qemu.conf. After this patch the default will be "no" even if you set chardev_tls=1 and that breaks behavior of libvirt. The test case "serial-tcp-tlsx509-chardev-tls" where you had to add tls="yes" should also work without this change. This patch needs to be modified to take chardev_tls=1 in account and add tests to make sure that we don't break it in the future. Pavel
+ </p> +<pre> + ... + <devices> + <serial type="tcp"> + <source mode='connect' host="127.0.0.1" service="5555" tls="yes"/> + <protocol type="raw"/> + <target port="0"/> + </serial> + </devices> + ...</pre> + <h6><a name="elementsCharUDP">UDP network console</a></h6>
<p> diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng index 6eeb4e9..362b90d 100644 --- a/docs/schemas/domaincommon.rng +++ b/docs/schemas/domaincommon.rng @@ -3453,6 +3453,11 @@ <ref name="virOnOff"/> </attribute> </optional> + <optional> + <attribute name="tls"> + <ref name="virYesNo"/> + </attribute> + </optional> <zeroOrMore> <ref name='devSeclabel'/> </zeroOrMore> diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index f562323..1f7c43f 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -1961,6 +1961,8 @@ virDomainChrSourceDefCopy(virDomainChrSourceDefPtr dest,
if (VIR_STRDUP(dest->data.tcp.service, src->data.tcp.service) < 0) return -1; + + dest->data.tcp.haveTLS = src->data.tcp.haveTLS; break;
case VIR_DOMAIN_CHR_TYPE_UNIX: @@ -9999,6 +10001,7 @@ virDomainChrSourceDefParseXML(virDomainChrSourceDefPtr def, char *master = NULL; char *slave = NULL; char *append = NULL; + char *haveTLS = NULL; int remaining = 0;
while (cur != NULL) { @@ -10006,6 +10009,8 @@ virDomainChrSourceDefParseXML(virDomainChrSourceDefPtr def, if (xmlStrEqual(cur->name, BAD_CAST "source")) { if (!mode) mode = virXMLPropString(cur, "mode"); + if (!haveTLS) + haveTLS = virXMLPropString(cur, "tls");
switch ((virDomainChrType) def->type) { case VIR_DOMAIN_CHR_TYPE_FILE: @@ -10182,6 +10187,15 @@ virDomainChrSourceDefParseXML(virDomainChrSourceDefPtr def, def->data.tcp.listen = true; }
+ if (haveTLS && + (def->data.tcp.haveTLS = + virTristateBoolTypeFromString(haveTLS)) <= 0) { + virReportError(VIR_ERR_XML_ERROR, + _("unknown chardev 'tls' setting '%s'"), + haveTLS); + goto error; + } + if (!protocol) def->data.tcp.protocol = VIR_DOMAIN_CHR_TCP_PROTOCOL_RAW; else if ((def->data.tcp.protocol = @@ -10266,6 +10280,7 @@ virDomainChrSourceDefParseXML(virDomainChrSourceDefPtr def, VIR_FREE(append); VIR_FREE(logappend); VIR_FREE(logfile); + VIR_FREE(haveTLS);
return remaining;
@@ -21417,7 +21432,12 @@ virDomainChrSourceDefFormat(virBufferPtr buf, virBufferAsprintf(buf, "<source mode='%s' ", def->data.tcp.listen ? "bind" : "connect"); virBufferEscapeString(buf, "host='%s' ", def->data.tcp.host); - virBufferEscapeString(buf, "service='%s'/>\n", def->data.tcp.service); + virBufferEscapeString(buf, "service='%s'", def->data.tcp.service); + if (def->data.tcp.haveTLS != VIR_TRISTATE_BOOL_ABSENT) + virBufferAsprintf(buf, " tls='%s'", + virTristateBoolTypeToString(def->data.tcp.haveTLS)); + virBufferAddLit(buf, "/>\n"); + virBufferAsprintf(buf, "<protocol type='%s'/>\n", virDomainChrTcpProtocolTypeToString( def->data.tcp.protocol)); diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index a70bc21..da203c3 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -1094,6 +1094,7 @@ struct _virDomainChrSourceDef { bool listen; int protocol; bool tlscreds; + int haveTLS; /* enum virTristateBool */ } tcp; struct { char *bindHost; diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 578ff8b..b290ade 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -5002,7 +5002,8 @@ qemuBuildChrChardevStr(virLogManagerPtr logManager, telnet ? ",telnet" : "", dev->data.tcp.listen ? ",server,nowait" : "");
- if (cfg->chardevTLS) { + if (cfg->chardevTLS && + dev->data.tcp.haveTLS == VIR_TRISTATE_BOOL_YES) { char *objalias = NULL;
if (qemuBuildTLSx509CommandLine(cmd, cfg->chardevTLSx509certdir, diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c index 72dd93b..419296e 100644 --- a/src/qemu/qemu_hotplug.c +++ b/src/qemu/qemu_hotplug.c @@ -1677,7 +1677,8 @@ int qemuDomainAttachChrDevice(virQEMUDriverPtr driver, if (qemuDomainChrPreInsert(vmdef, chr) < 0) goto cleanup;
- if (cfg->chardevTLS) { + if (cfg->chardevTLS && + dev->data.tcp.haveTLS == VIR_TRISTATE_BOOL_YES) { if (qemuBuildTLSx509BackendProps(cfg->chardevTLSx509certdir, dev->data.tcp.listen, cfg->chardevTLSx509verify, diff --git a/tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-tlsx509-chardev-tls.args b/tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-tlsx509-chardev-tls.args new file mode 100644 index 0000000..cac0d85 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-tlsx509-chardev-tls.args @@ -0,0 +1,30 @@ +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,sockets=1,cores=1,threads=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 \ +-chardev socket,id=charserial1,host=127.0.0.1,port=5555 \ +-device isa-serial,chardev=charserial1,id=serial1 \ +-device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x3 diff --git a/tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-tlsx509-chardev-tls.xml b/tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-tlsx509-chardev-tls.xml new file mode 100644 index 0000000..debc69b --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-tlsx509-chardev-tls.xml @@ -0,0 +1,50 @@ +<domain type='qemu'> + <name>QEMUGuest1</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory unit='KiB'>219136</memory> + <currentMemory unit='KiB'>219136</currentMemory> + <vcpu placement='static'>1</vcpu> + <os> + <type arch='i686' machine='pc'>hvm</type> + <boot dev='hd'/> + </os> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <emulator>/usr/bin/qemu</emulator> + <disk type='block' device='disk'> + <source dev='/dev/HostVG/QEMUGuest1'/> + <target dev='hda' bus='ide'/> + <address type='drive' controller='0' bus='0' target='0' unit='0'/> + </disk> + <controller type='usb' index='0'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x2'/> + </controller> + <controller type='ide' index='0'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/> + </controller> + <controller type='pci' index='0' model='pci-root'/> + <serial type='udp'> + <source mode='bind' host='127.0.0.1' service='1111'/> + <source mode='connect' host='127.0.0.1' service='2222'/> + <target port='0'/> + </serial> + <serial type='tcp'> + <source mode='connect' host='127.0.0.1' service='5555' tls='no'/> + <protocol type='raw'/> + <target port='0'/> + </serial> + <console type='udp'> + <source mode='bind' host='127.0.0.1' service='1111'/> + <source mode='connect' host='127.0.0.1' service='2222'/> + <target type='serial' port='0'/> + </console> + <input type='mouse' bus='ps2'/> + <input type='keyboard' bus='ps2'/> + <memballoon model='virtio'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/> + </memballoon> + </devices> +</domain> diff --git a/tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-tlsx509-chardev.xml b/tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-tlsx509-chardev.xml index 1618b02..1d7896d 100644 --- a/tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-tlsx509-chardev.xml +++ b/tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-tlsx509-chardev.xml @@ -27,7 +27,7 @@ <target port='0'/> </serial> <serial type='tcp'> - <source mode='connect' host='127.0.0.1' service='5555'/> + <source mode='connect' host='127.0.0.1' service='5555' tls='yes'/> <protocol type='raw'/> <target port='0'/> </serial> diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index 4b9ecb8..41adff4 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -1150,6 +1150,9 @@ mymain(void) DO_TEST("serial-tcp-tlsx509-chardev", QEMU_CAPS_CHARDEV, QEMU_CAPS_NODEFCONFIG, QEMU_CAPS_OBJECT_TLS_CREDS_X509); + DO_TEST("serial-tcp-tlsx509-chardev-tls", + QEMU_CAPS_CHARDEV, QEMU_CAPS_NODEFCONFIG, + QEMU_CAPS_OBJECT_TLS_CREDS_X509); driver.config->chardevTLS = 0; VIR_FREE(driver.config->chardevTLSx509certdir); DO_TEST("serial-many-chardev", diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-serial-tcp-tlsx509-chardev-tls.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-serial-tcp-tlsx509-chardev-tls.xml new file mode 120000 index 0000000..3453497 --- /dev/null +++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-serial-tcp-tlsx509-chardev-tls.xml @@ -0,0 +1 @@ +../qemuxml2argvdata/qemuxml2argv-serial-tcp-tlsx509-chardev-tls.xml \ No newline at end of file diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-serial-tcp-tlsx509-chardev.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-serial-tcp-tlsx509-chardev.xml index 832e2a2..23c244b 100644 --- a/tests/qemuxml2xmloutdata/qemuxml2xmlout-serial-tcp-tlsx509-chardev.xml +++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-serial-tcp-tlsx509-chardev.xml @@ -32,7 +32,7 @@ <target port='0'/> </serial> <serial type='tcp'> - <source mode='connect' host='127.0.0.1' service='5555'/> + <source mode='connect' host='127.0.0.1' service='5555' tls='yes'/> <protocol type='raw'/> <target port='0'/> </serial> diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c index 4b58986..02fe32e 100644 --- a/tests/qemuxml2xmltest.c +++ b/tests/qemuxml2xmltest.c @@ -534,6 +534,7 @@ mymain(void) DO_TEST("serial-udp", NONE); DO_TEST("serial-tcp-telnet", NONE); DO_TEST("serial-tcp-tlsx509-chardev", NONE); + DO_TEST("serial-tcp-tlsx509-chardev-tls", NONE); DO_TEST("serial-many", NONE); DO_TEST("serial-spiceport", NONE); DO_TEST("serial-spiceport-nospice", NONE); -- 2.7.4
-- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list

On 10/14/2016 09:18 AM, Pavel Hrdina wrote:
On Fri, Oct 07, 2016 at 07:00:26AM -0400, John Ferlan wrote:
Add an optional "tls='yes'" option for a TCP chardev for the express purpose to enable setting up TLS for the chardev. This will assume that the qemu.conf settings have been adjusted as well as the environment configured properly.
Signed-off-by: John Ferlan <jferlan@redhat.com> --- docs/formatdomain.html.in | 21 +++++++++ docs/schemas/domaincommon.rng | 5 +++ src/conf/domain_conf.c | 22 +++++++++- src/conf/domain_conf.h | 1 + src/qemu/qemu_command.c | 3 +- src/qemu/qemu_hotplug.c | 3 +- ...emuxml2argv-serial-tcp-tlsx509-chardev-tls.args | 30 +++++++++++++ ...qemuxml2argv-serial-tcp-tlsx509-chardev-tls.xml | 50 ++++++++++++++++++++++ .../qemuxml2argv-serial-tcp-tlsx509-chardev.xml | 2 +- tests/qemuxml2argvtest.c | 3 ++ ...muxml2xmlout-serial-tcp-tlsx509-chardev-tls.xml | 1 + .../qemuxml2xmlout-serial-tcp-tlsx509-chardev.xml | 2 +- tests/qemuxml2xmltest.c | 1 + 13 files changed, 139 insertions(+), 5 deletions(-) create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-tlsx509-chardev-tls.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-tlsx509-chardev-tls.xml create mode 120000 tests/qemuxml2xmloutdata/qemuxml2xmlout-serial-tcp-tlsx509-chardev-tls.xml
diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in index 1266e9d..010530e 100644 --- a/docs/formatdomain.html.in +++ b/docs/formatdomain.html.in @@ -6203,6 +6203,27 @@ qemu-kvm -net nic,model=? /dev/null </devices> ...</pre>
+ <p> + <span class="since">Since 2.4.0,</span> some hypervisors support using + a TLS X.509 certificate environment in order to encrypt all serial TCP + connections via a hypervisor configuration option. In order to enable + TLS for the domain an optional attribute <code>tls</code> can be set to + "yes". Combined with the hypervisor's capability to utilize the TLS + environment allows for the character device to use the encrypted + communication. If the attribute is not present, then the default + setting is "no".
This is not correct in case of QEMU. Before this patch the default was based on chardev_tls from qemu.conf. After this patch the default will be "no" even if you set chardev_tls=1 and that breaks behavior of libvirt. The test case "serial-tcp-tlsx509-chardev-tls" where you had to add tls="yes" should also work without this change.
This patch needs to be modified to take chardev_tls=1 in account and add tests to make sure that we don't break it in the future.
This change was in response to v5 (and v6) review comments from Daniel : v5: http://www.redhat.com/archives/libvir-list/2016-September/msg00294.html v6: http://www.redhat.com/archives/libvir-list/2016-September/msg00317.html I read those review requests as we need a way to be able to disable TLS on a chardev on a domain by domain and even chardev by chardev basis rather than it being the default enabled for every domain and every chardev in the domain. Could you elaborate how it breaks the behavior of libvirt? Currently a chardev doesn't have any TLS attribute - that qemu.conf change is from already agreed upon changes. This set of changes should have been able to go with those, but they've languished on the least through a release cycle (2.3.0), so while it may appear that something is one way - it in a way isn't. Right now it's just pixie/fairy dust and a pipe dream. John
Pavel
+ </p> +<pre> + ... + <devices> + <serial type="tcp"> + <source mode='connect' host="127.0.0.1" service="5555" tls="yes"/> + <protocol type="raw"/> + <target port="0"/> + </serial> + </devices> + ...</pre> + <h6><a name="elementsCharUDP">UDP network console</a></h6>
<p> diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng index 6eeb4e9..362b90d 100644 --- a/docs/schemas/domaincommon.rng +++ b/docs/schemas/domaincommon.rng @@ -3453,6 +3453,11 @@ <ref name="virOnOff"/> </attribute> </optional> + <optional> + <attribute name="tls"> + <ref name="virYesNo"/> + </attribute> + </optional> <zeroOrMore> <ref name='devSeclabel'/> </zeroOrMore> diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index f562323..1f7c43f 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -1961,6 +1961,8 @@ virDomainChrSourceDefCopy(virDomainChrSourceDefPtr dest,
if (VIR_STRDUP(dest->data.tcp.service, src->data.tcp.service) < 0) return -1; + + dest->data.tcp.haveTLS = src->data.tcp.haveTLS; break;
case VIR_DOMAIN_CHR_TYPE_UNIX: @@ -9999,6 +10001,7 @@ virDomainChrSourceDefParseXML(virDomainChrSourceDefPtr def, char *master = NULL; char *slave = NULL; char *append = NULL; + char *haveTLS = NULL; int remaining = 0;
while (cur != NULL) { @@ -10006,6 +10009,8 @@ virDomainChrSourceDefParseXML(virDomainChrSourceDefPtr def, if (xmlStrEqual(cur->name, BAD_CAST "source")) { if (!mode) mode = virXMLPropString(cur, "mode"); + if (!haveTLS) + haveTLS = virXMLPropString(cur, "tls");
switch ((virDomainChrType) def->type) { case VIR_DOMAIN_CHR_TYPE_FILE: @@ -10182,6 +10187,15 @@ virDomainChrSourceDefParseXML(virDomainChrSourceDefPtr def, def->data.tcp.listen = true; }
+ if (haveTLS && + (def->data.tcp.haveTLS = + virTristateBoolTypeFromString(haveTLS)) <= 0) { + virReportError(VIR_ERR_XML_ERROR, + _("unknown chardev 'tls' setting '%s'"), + haveTLS); + goto error; + } + if (!protocol) def->data.tcp.protocol = VIR_DOMAIN_CHR_TCP_PROTOCOL_RAW; else if ((def->data.tcp.protocol = @@ -10266,6 +10280,7 @@ virDomainChrSourceDefParseXML(virDomainChrSourceDefPtr def, VIR_FREE(append); VIR_FREE(logappend); VIR_FREE(logfile); + VIR_FREE(haveTLS);
return remaining;
@@ -21417,7 +21432,12 @@ virDomainChrSourceDefFormat(virBufferPtr buf, virBufferAsprintf(buf, "<source mode='%s' ", def->data.tcp.listen ? "bind" : "connect"); virBufferEscapeString(buf, "host='%s' ", def->data.tcp.host); - virBufferEscapeString(buf, "service='%s'/>\n", def->data.tcp.service); + virBufferEscapeString(buf, "service='%s'", def->data.tcp.service); + if (def->data.tcp.haveTLS != VIR_TRISTATE_BOOL_ABSENT) + virBufferAsprintf(buf, " tls='%s'", + virTristateBoolTypeToString(def->data.tcp.haveTLS)); + virBufferAddLit(buf, "/>\n"); + virBufferAsprintf(buf, "<protocol type='%s'/>\n", virDomainChrTcpProtocolTypeToString( def->data.tcp.protocol)); diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index a70bc21..da203c3 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -1094,6 +1094,7 @@ struct _virDomainChrSourceDef { bool listen; int protocol; bool tlscreds; + int haveTLS; /* enum virTristateBool */ } tcp; struct { char *bindHost; diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 578ff8b..b290ade 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -5002,7 +5002,8 @@ qemuBuildChrChardevStr(virLogManagerPtr logManager, telnet ? ",telnet" : "", dev->data.tcp.listen ? ",server,nowait" : "");
- if (cfg->chardevTLS) { + if (cfg->chardevTLS && + dev->data.tcp.haveTLS == VIR_TRISTATE_BOOL_YES) { char *objalias = NULL;
if (qemuBuildTLSx509CommandLine(cmd, cfg->chardevTLSx509certdir, diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c index 72dd93b..419296e 100644 --- a/src/qemu/qemu_hotplug.c +++ b/src/qemu/qemu_hotplug.c @@ -1677,7 +1677,8 @@ int qemuDomainAttachChrDevice(virQEMUDriverPtr driver, if (qemuDomainChrPreInsert(vmdef, chr) < 0) goto cleanup;
- if (cfg->chardevTLS) { + if (cfg->chardevTLS && + dev->data.tcp.haveTLS == VIR_TRISTATE_BOOL_YES) { if (qemuBuildTLSx509BackendProps(cfg->chardevTLSx509certdir, dev->data.tcp.listen, cfg->chardevTLSx509verify, diff --git a/tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-tlsx509-chardev-tls.args b/tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-tlsx509-chardev-tls.args new file mode 100644 index 0000000..cac0d85 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-tlsx509-chardev-tls.args @@ -0,0 +1,30 @@ +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,sockets=1,cores=1,threads=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 \ +-chardev socket,id=charserial1,host=127.0.0.1,port=5555 \ +-device isa-serial,chardev=charserial1,id=serial1 \ +-device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x3 diff --git a/tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-tlsx509-chardev-tls.xml b/tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-tlsx509-chardev-tls.xml new file mode 100644 index 0000000..debc69b --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-tlsx509-chardev-tls.xml @@ -0,0 +1,50 @@ +<domain type='qemu'> + <name>QEMUGuest1</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory unit='KiB'>219136</memory> + <currentMemory unit='KiB'>219136</currentMemory> + <vcpu placement='static'>1</vcpu> + <os> + <type arch='i686' machine='pc'>hvm</type> + <boot dev='hd'/> + </os> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <emulator>/usr/bin/qemu</emulator> + <disk type='block' device='disk'> + <source dev='/dev/HostVG/QEMUGuest1'/> + <target dev='hda' bus='ide'/> + <address type='drive' controller='0' bus='0' target='0' unit='0'/> + </disk> + <controller type='usb' index='0'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x2'/> + </controller> + <controller type='ide' index='0'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/> + </controller> + <controller type='pci' index='0' model='pci-root'/> + <serial type='udp'> + <source mode='bind' host='127.0.0.1' service='1111'/> + <source mode='connect' host='127.0.0.1' service='2222'/> + <target port='0'/> + </serial> + <serial type='tcp'> + <source mode='connect' host='127.0.0.1' service='5555' tls='no'/> + <protocol type='raw'/> + <target port='0'/> + </serial> + <console type='udp'> + <source mode='bind' host='127.0.0.1' service='1111'/> + <source mode='connect' host='127.0.0.1' service='2222'/> + <target type='serial' port='0'/> + </console> + <input type='mouse' bus='ps2'/> + <input type='keyboard' bus='ps2'/> + <memballoon model='virtio'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/> + </memballoon> + </devices> +</domain> diff --git a/tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-tlsx509-chardev.xml b/tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-tlsx509-chardev.xml index 1618b02..1d7896d 100644 --- a/tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-tlsx509-chardev.xml +++ b/tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-tlsx509-chardev.xml @@ -27,7 +27,7 @@ <target port='0'/> </serial> <serial type='tcp'> - <source mode='connect' host='127.0.0.1' service='5555'/> + <source mode='connect' host='127.0.0.1' service='5555' tls='yes'/> <protocol type='raw'/> <target port='0'/> </serial> diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index 4b9ecb8..41adff4 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -1150,6 +1150,9 @@ mymain(void) DO_TEST("serial-tcp-tlsx509-chardev", QEMU_CAPS_CHARDEV, QEMU_CAPS_NODEFCONFIG, QEMU_CAPS_OBJECT_TLS_CREDS_X509); + DO_TEST("serial-tcp-tlsx509-chardev-tls", + QEMU_CAPS_CHARDEV, QEMU_CAPS_NODEFCONFIG, + QEMU_CAPS_OBJECT_TLS_CREDS_X509); driver.config->chardevTLS = 0; VIR_FREE(driver.config->chardevTLSx509certdir); DO_TEST("serial-many-chardev", diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-serial-tcp-tlsx509-chardev-tls.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-serial-tcp-tlsx509-chardev-tls.xml new file mode 120000 index 0000000..3453497 --- /dev/null +++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-serial-tcp-tlsx509-chardev-tls.xml @@ -0,0 +1 @@ +../qemuxml2argvdata/qemuxml2argv-serial-tcp-tlsx509-chardev-tls.xml \ No newline at end of file diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-serial-tcp-tlsx509-chardev.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-serial-tcp-tlsx509-chardev.xml index 832e2a2..23c244b 100644 --- a/tests/qemuxml2xmloutdata/qemuxml2xmlout-serial-tcp-tlsx509-chardev.xml +++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-serial-tcp-tlsx509-chardev.xml @@ -32,7 +32,7 @@ <target port='0'/> </serial> <serial type='tcp'> - <source mode='connect' host='127.0.0.1' service='5555'/> + <source mode='connect' host='127.0.0.1' service='5555' tls='yes'/> <protocol type='raw'/> <target port='0'/> </serial> diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c index 4b58986..02fe32e 100644 --- a/tests/qemuxml2xmltest.c +++ b/tests/qemuxml2xmltest.c @@ -534,6 +534,7 @@ mymain(void) DO_TEST("serial-udp", NONE); DO_TEST("serial-tcp-telnet", NONE); DO_TEST("serial-tcp-tlsx509-chardev", NONE); + DO_TEST("serial-tcp-tlsx509-chardev-tls", NONE); DO_TEST("serial-many", NONE); DO_TEST("serial-spiceport", NONE); DO_TEST("serial-spiceport-nospice", NONE); -- 2.7.4
-- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list

On Fri, Oct 14, 2016 at 09:32:45AM -0400, John Ferlan wrote:
On 10/14/2016 09:18 AM, Pavel Hrdina wrote:
On Fri, Oct 07, 2016 at 07:00:26AM -0400, John Ferlan wrote:
Add an optional "tls='yes'" option for a TCP chardev for the express purpose to enable setting up TLS for the chardev. This will assume that the qemu.conf settings have been adjusted as well as the environment configured properly.
Signed-off-by: John Ferlan <jferlan@redhat.com> --- docs/formatdomain.html.in | 21 +++++++++ docs/schemas/domaincommon.rng | 5 +++ src/conf/domain_conf.c | 22 +++++++++- src/conf/domain_conf.h | 1 + src/qemu/qemu_command.c | 3 +- src/qemu/qemu_hotplug.c | 3 +- ...emuxml2argv-serial-tcp-tlsx509-chardev-tls.args | 30 +++++++++++++ ...qemuxml2argv-serial-tcp-tlsx509-chardev-tls.xml | 50 ++++++++++++++++++++++ .../qemuxml2argv-serial-tcp-tlsx509-chardev.xml | 2 +- tests/qemuxml2argvtest.c | 3 ++ ...muxml2xmlout-serial-tcp-tlsx509-chardev-tls.xml | 1 + .../qemuxml2xmlout-serial-tcp-tlsx509-chardev.xml | 2 +- tests/qemuxml2xmltest.c | 1 + 13 files changed, 139 insertions(+), 5 deletions(-) create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-tlsx509-chardev-tls.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-tlsx509-chardev-tls.xml create mode 120000 tests/qemuxml2xmloutdata/qemuxml2xmlout-serial-tcp-tlsx509-chardev-tls.xml
diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in index 1266e9d..010530e 100644 --- a/docs/formatdomain.html.in +++ b/docs/formatdomain.html.in @@ -6203,6 +6203,27 @@ qemu-kvm -net nic,model=? /dev/null </devices> ...</pre>
+ <p> + <span class="since">Since 2.4.0,</span> some hypervisors support using + a TLS X.509 certificate environment in order to encrypt all serial TCP + connections via a hypervisor configuration option. In order to enable + TLS for the domain an optional attribute <code>tls</code> can be set to + "yes". Combined with the hypervisor's capability to utilize the TLS + environment allows for the character device to use the encrypted + communication. If the attribute is not present, then the default + setting is "no".
This is not correct in case of QEMU. Before this patch the default was based on chardev_tls from qemu.conf. After this patch the default will be "no" even if you set chardev_tls=1 and that breaks behavior of libvirt. The test case "serial-tcp-tlsx509-chardev-tls" where you had to add tls="yes" should also work without this change.
This patch needs to be modified to take chardev_tls=1 in account and add tests to make sure that we don't break it in the future.
This change was in response to v5 (and v6) review comments from Daniel :
v5: http://www.redhat.com/archives/libvir-list/2016-September/msg00294.html
v6: http://www.redhat.com/archives/libvir-list/2016-September/msg00317.html
I read those review requests as we need a way to be able to disable TLS on a chardev on a domain by domain and even chardev by chardev basis rather than it being the default enabled for every domain and every chardev in the domain.
Could you elaborate how it breaks the behavior of libvirt? Currently a chardev doesn't have any TLS attribute - that qemu.conf change is from already agreed upon changes. This set of changes should have been able to go with those, but they've languished on the least through a release cycle (2.3.0), so while it may appear that something is one way - it in a way isn't. Right now it's just pixie/fairy dust and a pipe dream.
The thing is that with libvirt-2.3.0 you can set chardev_tls=1 in qemu.conf and therefore all chardevs for all domains uses TLS to encrypt communication. This patch introduces a new 'tls' attribute and its default value is 'no' and that means if the user upgrades from libvirt-2.3.0 to libvirt-2.4.0 all chardevs stop encrypting communication unless he sets tls="yes" for every single chardev in every single domain. The correct solution is: - if chardev_tls is set to 1 and tls attribute is not configured in the XML the default after starting the domain should be tls=yes - if chardev_tls is not set and tls attribute is not configured in the XML the default after starting the domain should be tls=no Pavel
John
Pavel
+ </p> +<pre> + ... + <devices> + <serial type="tcp"> + <source mode='connect' host="127.0.0.1" service="5555" tls="yes"/> + <protocol type="raw"/> + <target port="0"/> + </serial> + </devices> + ...</pre> + <h6><a name="elementsCharUDP">UDP network console</a></h6>
<p> diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng index 6eeb4e9..362b90d 100644 --- a/docs/schemas/domaincommon.rng +++ b/docs/schemas/domaincommon.rng @@ -3453,6 +3453,11 @@ <ref name="virOnOff"/> </attribute> </optional> + <optional> + <attribute name="tls"> + <ref name="virYesNo"/> + </attribute> + </optional> <zeroOrMore> <ref name='devSeclabel'/> </zeroOrMore> diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index f562323..1f7c43f 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -1961,6 +1961,8 @@ virDomainChrSourceDefCopy(virDomainChrSourceDefPtr dest,
if (VIR_STRDUP(dest->data.tcp.service, src->data.tcp.service) < 0) return -1; + + dest->data.tcp.haveTLS = src->data.tcp.haveTLS; break;
case VIR_DOMAIN_CHR_TYPE_UNIX: @@ -9999,6 +10001,7 @@ virDomainChrSourceDefParseXML(virDomainChrSourceDefPtr def, char *master = NULL; char *slave = NULL; char *append = NULL; + char *haveTLS = NULL; int remaining = 0;
while (cur != NULL) { @@ -10006,6 +10009,8 @@ virDomainChrSourceDefParseXML(virDomainChrSourceDefPtr def, if (xmlStrEqual(cur->name, BAD_CAST "source")) { if (!mode) mode = virXMLPropString(cur, "mode"); + if (!haveTLS) + haveTLS = virXMLPropString(cur, "tls");
switch ((virDomainChrType) def->type) { case VIR_DOMAIN_CHR_TYPE_FILE: @@ -10182,6 +10187,15 @@ virDomainChrSourceDefParseXML(virDomainChrSourceDefPtr def, def->data.tcp.listen = true; }
+ if (haveTLS && + (def->data.tcp.haveTLS = + virTristateBoolTypeFromString(haveTLS)) <= 0) { + virReportError(VIR_ERR_XML_ERROR, + _("unknown chardev 'tls' setting '%s'"), + haveTLS); + goto error; + } + if (!protocol) def->data.tcp.protocol = VIR_DOMAIN_CHR_TCP_PROTOCOL_RAW; else if ((def->data.tcp.protocol = @@ -10266,6 +10280,7 @@ virDomainChrSourceDefParseXML(virDomainChrSourceDefPtr def, VIR_FREE(append); VIR_FREE(logappend); VIR_FREE(logfile); + VIR_FREE(haveTLS);
return remaining;
@@ -21417,7 +21432,12 @@ virDomainChrSourceDefFormat(virBufferPtr buf, virBufferAsprintf(buf, "<source mode='%s' ", def->data.tcp.listen ? "bind" : "connect"); virBufferEscapeString(buf, "host='%s' ", def->data.tcp.host); - virBufferEscapeString(buf, "service='%s'/>\n", def->data.tcp.service); + virBufferEscapeString(buf, "service='%s'", def->data.tcp.service); + if (def->data.tcp.haveTLS != VIR_TRISTATE_BOOL_ABSENT) + virBufferAsprintf(buf, " tls='%s'", + virTristateBoolTypeToString(def->data.tcp.haveTLS)); + virBufferAddLit(buf, "/>\n"); + virBufferAsprintf(buf, "<protocol type='%s'/>\n", virDomainChrTcpProtocolTypeToString( def->data.tcp.protocol)); diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index a70bc21..da203c3 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -1094,6 +1094,7 @@ struct _virDomainChrSourceDef { bool listen; int protocol; bool tlscreds; + int haveTLS; /* enum virTristateBool */ } tcp; struct { char *bindHost; diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 578ff8b..b290ade 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -5002,7 +5002,8 @@ qemuBuildChrChardevStr(virLogManagerPtr logManager, telnet ? ",telnet" : "", dev->data.tcp.listen ? ",server,nowait" : "");
- if (cfg->chardevTLS) { + if (cfg->chardevTLS && + dev->data.tcp.haveTLS == VIR_TRISTATE_BOOL_YES) { char *objalias = NULL;
if (qemuBuildTLSx509CommandLine(cmd, cfg->chardevTLSx509certdir, diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c index 72dd93b..419296e 100644 --- a/src/qemu/qemu_hotplug.c +++ b/src/qemu/qemu_hotplug.c @@ -1677,7 +1677,8 @@ int qemuDomainAttachChrDevice(virQEMUDriverPtr driver, if (qemuDomainChrPreInsert(vmdef, chr) < 0) goto cleanup;
- if (cfg->chardevTLS) { + if (cfg->chardevTLS && + dev->data.tcp.haveTLS == VIR_TRISTATE_BOOL_YES) { if (qemuBuildTLSx509BackendProps(cfg->chardevTLSx509certdir, dev->data.tcp.listen, cfg->chardevTLSx509verify, diff --git a/tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-tlsx509-chardev-tls.args b/tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-tlsx509-chardev-tls.args new file mode 100644 index 0000000..cac0d85 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-tlsx509-chardev-tls.args @@ -0,0 +1,30 @@ +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,sockets=1,cores=1,threads=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 \ +-chardev socket,id=charserial1,host=127.0.0.1,port=5555 \ +-device isa-serial,chardev=charserial1,id=serial1 \ +-device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x3 diff --git a/tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-tlsx509-chardev-tls.xml b/tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-tlsx509-chardev-tls.xml new file mode 100644 index 0000000..debc69b --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-tlsx509-chardev-tls.xml @@ -0,0 +1,50 @@ +<domain type='qemu'> + <name>QEMUGuest1</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory unit='KiB'>219136</memory> + <currentMemory unit='KiB'>219136</currentMemory> + <vcpu placement='static'>1</vcpu> + <os> + <type arch='i686' machine='pc'>hvm</type> + <boot dev='hd'/> + </os> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <emulator>/usr/bin/qemu</emulator> + <disk type='block' device='disk'> + <source dev='/dev/HostVG/QEMUGuest1'/> + <target dev='hda' bus='ide'/> + <address type='drive' controller='0' bus='0' target='0' unit='0'/> + </disk> + <controller type='usb' index='0'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x2'/> + </controller> + <controller type='ide' index='0'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/> + </controller> + <controller type='pci' index='0' model='pci-root'/> + <serial type='udp'> + <source mode='bind' host='127.0.0.1' service='1111'/> + <source mode='connect' host='127.0.0.1' service='2222'/> + <target port='0'/> + </serial> + <serial type='tcp'> + <source mode='connect' host='127.0.0.1' service='5555' tls='no'/> + <protocol type='raw'/> + <target port='0'/> + </serial> + <console type='udp'> + <source mode='bind' host='127.0.0.1' service='1111'/> + <source mode='connect' host='127.0.0.1' service='2222'/> + <target type='serial' port='0'/> + </console> + <input type='mouse' bus='ps2'/> + <input type='keyboard' bus='ps2'/> + <memballoon model='virtio'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/> + </memballoon> + </devices> +</domain> diff --git a/tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-tlsx509-chardev.xml b/tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-tlsx509-chardev.xml index 1618b02..1d7896d 100644 --- a/tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-tlsx509-chardev.xml +++ b/tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-tlsx509-chardev.xml @@ -27,7 +27,7 @@ <target port='0'/> </serial> <serial type='tcp'> - <source mode='connect' host='127.0.0.1' service='5555'/> + <source mode='connect' host='127.0.0.1' service='5555' tls='yes'/> <protocol type='raw'/> <target port='0'/> </serial> diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index 4b9ecb8..41adff4 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -1150,6 +1150,9 @@ mymain(void) DO_TEST("serial-tcp-tlsx509-chardev", QEMU_CAPS_CHARDEV, QEMU_CAPS_NODEFCONFIG, QEMU_CAPS_OBJECT_TLS_CREDS_X509); + DO_TEST("serial-tcp-tlsx509-chardev-tls", + QEMU_CAPS_CHARDEV, QEMU_CAPS_NODEFCONFIG, + QEMU_CAPS_OBJECT_TLS_CREDS_X509); driver.config->chardevTLS = 0; VIR_FREE(driver.config->chardevTLSx509certdir); DO_TEST("serial-many-chardev", diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-serial-tcp-tlsx509-chardev-tls.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-serial-tcp-tlsx509-chardev-tls.xml new file mode 120000 index 0000000..3453497 --- /dev/null +++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-serial-tcp-tlsx509-chardev-tls.xml @@ -0,0 +1 @@ +../qemuxml2argvdata/qemuxml2argv-serial-tcp-tlsx509-chardev-tls.xml \ No newline at end of file diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-serial-tcp-tlsx509-chardev.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-serial-tcp-tlsx509-chardev.xml index 832e2a2..23c244b 100644 --- a/tests/qemuxml2xmloutdata/qemuxml2xmlout-serial-tcp-tlsx509-chardev.xml +++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-serial-tcp-tlsx509-chardev.xml @@ -32,7 +32,7 @@ <target port='0'/> </serial> <serial type='tcp'> - <source mode='connect' host='127.0.0.1' service='5555'/> + <source mode='connect' host='127.0.0.1' service='5555' tls='yes'/> <protocol type='raw'/> <target port='0'/> </serial> diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c index 4b58986..02fe32e 100644 --- a/tests/qemuxml2xmltest.c +++ b/tests/qemuxml2xmltest.c @@ -534,6 +534,7 @@ mymain(void) DO_TEST("serial-udp", NONE); DO_TEST("serial-tcp-telnet", NONE); DO_TEST("serial-tcp-tlsx509-chardev", NONE); + DO_TEST("serial-tcp-tlsx509-chardev-tls", NONE); DO_TEST("serial-many", NONE); DO_TEST("serial-spiceport", NONE); DO_TEST("serial-spiceport-nospice", NONE); -- 2.7.4
-- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
-- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list

On 10/14/2016 09:49 AM, Pavel Hrdina wrote:
On Fri, Oct 14, 2016 at 09:32:45AM -0400, John Ferlan wrote:
On 10/14/2016 09:18 AM, Pavel Hrdina wrote:
On Fri, Oct 07, 2016 at 07:00:26AM -0400, John Ferlan wrote:
Add an optional "tls='yes'" option for a TCP chardev for the express purpose to enable setting up TLS for the chardev. This will assume that the qemu.conf settings have been adjusted as well as the environment configured properly.
Signed-off-by: John Ferlan <jferlan@redhat.com> --- docs/formatdomain.html.in | 21 +++++++++ docs/schemas/domaincommon.rng | 5 +++ src/conf/domain_conf.c | 22 +++++++++- src/conf/domain_conf.h | 1 + src/qemu/qemu_command.c | 3 +- src/qemu/qemu_hotplug.c | 3 +- ...emuxml2argv-serial-tcp-tlsx509-chardev-tls.args | 30 +++++++++++++ ...qemuxml2argv-serial-tcp-tlsx509-chardev-tls.xml | 50 ++++++++++++++++++++++ .../qemuxml2argv-serial-tcp-tlsx509-chardev.xml | 2 +- tests/qemuxml2argvtest.c | 3 ++ ...muxml2xmlout-serial-tcp-tlsx509-chardev-tls.xml | 1 + .../qemuxml2xmlout-serial-tcp-tlsx509-chardev.xml | 2 +- tests/qemuxml2xmltest.c | 1 + 13 files changed, 139 insertions(+), 5 deletions(-) create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-tlsx509-chardev-tls.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-tlsx509-chardev-tls.xml create mode 120000 tests/qemuxml2xmloutdata/qemuxml2xmlout-serial-tcp-tlsx509-chardev-tls.xml
diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in index 1266e9d..010530e 100644 --- a/docs/formatdomain.html.in +++ b/docs/formatdomain.html.in @@ -6203,6 +6203,27 @@ qemu-kvm -net nic,model=? /dev/null </devices> ...</pre>
+ <p> + <span class="since">Since 2.4.0,</span> some hypervisors support using + a TLS X.509 certificate environment in order to encrypt all serial TCP + connections via a hypervisor configuration option. In order to enable + TLS for the domain an optional attribute <code>tls</code> can be set to + "yes". Combined with the hypervisor's capability to utilize the TLS + environment allows for the character device to use the encrypted + communication. If the attribute is not present, then the default + setting is "no".
This is not correct in case of QEMU. Before this patch the default was based on chardev_tls from qemu.conf. After this patch the default will be "no" even if you set chardev_tls=1 and that breaks behavior of libvirt. The test case "serial-tcp-tlsx509-chardev-tls" where you had to add tls="yes" should also work without this change.
This patch needs to be modified to take chardev_tls=1 in account and add tests to make sure that we don't break it in the future.
This change was in response to v5 (and v6) review comments from Daniel :
v5: http://www.redhat.com/archives/libvir-list/2016-September/msg00294.html
v6: http://www.redhat.com/archives/libvir-list/2016-September/msg00317.html
I read those review requests as we need a way to be able to disable TLS on a chardev on a domain by domain and even chardev by chardev basis rather than it being the default enabled for every domain and every chardev in the domain.
Could you elaborate how it breaks the behavior of libvirt? Currently a chardev doesn't have any TLS attribute - that qemu.conf change is from already agreed upon changes. This set of changes should have been able to go with those, but they've languished on the least through a release cycle (2.3.0), so while it may appear that something is one way - it in a way isn't. Right now it's just pixie/fairy dust and a pipe dream.
The thing is that with libvirt-2.3.0 you can set chardev_tls=1 in qemu.conf and therefore all chardevs for all domains uses TLS to encrypt communication. This patch introduces a new 'tls' attribute and its default value is 'no' and that means if the user upgrades from libvirt-2.3.0 to libvirt-2.4.0 all chardevs stop encrypting communication unless he sets tls="yes" for every single chardev in every single domain.
UGH... mea culpa - in my mind the TLS hadn't been added to the chardev yet and that was the rest of this series... Of course the rest of this series is adding the passphrase for the environment (<sigh>). If I could have got that review earlier, then this situation wouldn't be a problem (see in my mind it wasn't). If a domain is already running, then encryption is occurring and this setting has no effect except for hotplug. If we were using encryption in 2.3.0... stopped our domain... installed 2.4.0... started our domain, then yes, I see/agree.... Frustrating since there's really no "simple" way to determine this.
The correct solution is:
- if chardev_tls is set to 1 and tls attribute is not configured in the XML the default after starting the domain should be tls=yes
So IOW: + if (cfg->chardevTLS && + dev->data.tcp.haveTLS == VIR_TRISTATE_BOOL_YES) { changes to + if (cfg->chardevTLS && + dev->data.tcp.haveTLS != VIR_TRISTATE_BOOL_NO) { or (haveTLS == YES || haveTLS == ABSENT) This of course is essentially the logic from v6 which said disableTLS on a case by case basis.... All we have now is the positive form... So for both qemuBuildChrChardevStr and qemuDomainAttachChrDevice I'd have a similar change. Does that suffice and do you need to see the change?
- if chardev_tls is not set and tls attribute is not configured in the XML the default after starting the domain should be tls=no
We're not getting anywhere if chardev_tls is not set. John [...]

On Fri, Oct 14, 2016 at 10:16:19AM -0400, John Ferlan wrote:
On 10/14/2016 09:49 AM, Pavel Hrdina wrote:
On Fri, Oct 14, 2016 at 09:32:45AM -0400, John Ferlan wrote:
On 10/14/2016 09:18 AM, Pavel Hrdina wrote:
On Fri, Oct 07, 2016 at 07:00:26AM -0400, John Ferlan wrote:
Add an optional "tls='yes'" option for a TCP chardev for the express purpose to enable setting up TLS for the chardev. This will assume that the qemu.conf settings have been adjusted as well as the environment configured properly.
Signed-off-by: John Ferlan <jferlan@redhat.com> --- docs/formatdomain.html.in | 21 +++++++++ docs/schemas/domaincommon.rng | 5 +++ src/conf/domain_conf.c | 22 +++++++++- src/conf/domain_conf.h | 1 + src/qemu/qemu_command.c | 3 +- src/qemu/qemu_hotplug.c | 3 +- ...emuxml2argv-serial-tcp-tlsx509-chardev-tls.args | 30 +++++++++++++ ...qemuxml2argv-serial-tcp-tlsx509-chardev-tls.xml | 50 ++++++++++++++++++++++ .../qemuxml2argv-serial-tcp-tlsx509-chardev.xml | 2 +- tests/qemuxml2argvtest.c | 3 ++ ...muxml2xmlout-serial-tcp-tlsx509-chardev-tls.xml | 1 + .../qemuxml2xmlout-serial-tcp-tlsx509-chardev.xml | 2 +- tests/qemuxml2xmltest.c | 1 + 13 files changed, 139 insertions(+), 5 deletions(-) create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-tlsx509-chardev-tls.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-tlsx509-chardev-tls.xml create mode 120000 tests/qemuxml2xmloutdata/qemuxml2xmlout-serial-tcp-tlsx509-chardev-tls.xml
diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in index 1266e9d..010530e 100644 --- a/docs/formatdomain.html.in +++ b/docs/formatdomain.html.in @@ -6203,6 +6203,27 @@ qemu-kvm -net nic,model=? /dev/null </devices> ...</pre>
+ <p> + <span class="since">Since 2.4.0,</span> some hypervisors support using + a TLS X.509 certificate environment in order to encrypt all serial TCP + connections via a hypervisor configuration option. In order to enable + TLS for the domain an optional attribute <code>tls</code> can be set to + "yes". Combined with the hypervisor's capability to utilize the TLS + environment allows for the character device to use the encrypted + communication. If the attribute is not present, then the default + setting is "no".
This is not correct in case of QEMU. Before this patch the default was based on chardev_tls from qemu.conf. After this patch the default will be "no" even if you set chardev_tls=1 and that breaks behavior of libvirt. The test case "serial-tcp-tlsx509-chardev-tls" where you had to add tls="yes" should also work without this change.
This patch needs to be modified to take chardev_tls=1 in account and add tests to make sure that we don't break it in the future.
This change was in response to v5 (and v6) review comments from Daniel :
v5: http://www.redhat.com/archives/libvir-list/2016-September/msg00294.html
v6: http://www.redhat.com/archives/libvir-list/2016-September/msg00317.html
I read those review requests as we need a way to be able to disable TLS on a chardev on a domain by domain and even chardev by chardev basis rather than it being the default enabled for every domain and every chardev in the domain.
Could you elaborate how it breaks the behavior of libvirt? Currently a chardev doesn't have any TLS attribute - that qemu.conf change is from already agreed upon changes. This set of changes should have been able to go with those, but they've languished on the least through a release cycle (2.3.0), so while it may appear that something is one way - it in a way isn't. Right now it's just pixie/fairy dust and a pipe dream.
The thing is that with libvirt-2.3.0 you can set chardev_tls=1 in qemu.conf and therefore all chardevs for all domains uses TLS to encrypt communication. This patch introduces a new 'tls' attribute and its default value is 'no' and that means if the user upgrades from libvirt-2.3.0 to libvirt-2.4.0 all chardevs stop encrypting communication unless he sets tls="yes" for every single chardev in every single domain.
UGH... mea culpa - in my mind the TLS hadn't been added to the chardev yet and that was the rest of this series... Of course the rest of this series is adding the passphrase for the environment (<sigh>).
If I could have got that review earlier, then this situation wouldn't be a problem (see in my mind it wasn't).
If a domain is already running, then encryption is occurring and this setting has no effect except for hotplug.
If we were using encryption in 2.3.0... stopped our domain... installed 2.4.0... started our domain, then yes, I see/agree.... Frustrating since there's really no "simple" way to determine this.
The correct solution is:
- if chardev_tls is set to 1 and tls attribute is not configured in the XML the default after starting the domain should be tls=yes
So IOW:
+ if (cfg->chardevTLS && + dev->data.tcp.haveTLS == VIR_TRISTATE_BOOL_YES) {
changes to
+ if (cfg->chardevTLS && + dev->data.tcp.haveTLS != VIR_TRISTATE_BOOL_NO) {
or (haveTLS == YES || haveTLS == ABSENT)
This of course is essentially the logic from v6 which said disableTLS on a case by case basis.... All we have now is the positive form...
So for both qemuBuildChrChardevStr and qemuDomainAttachChrDevice I'd have a similar change. Does that suffice and do you need to see the change?
I think that we should reflect the state in live XML if the attribute exists. Add a code to qemuProcessPrepareDomain() that will set dev->data.tcp.haveTLS to config value if dev->data.tcp.haveTLS == VIR_TRISTATE_BOOL_ABSENT and in qemuBuildChrChardevStr() you can just check if dev->data.tcp.haveTLS == VIR_TRISTATE_BOOL_YES. This will also ensure that the live XML contains the 'tls' attribute. But make sure, that migration works properly for all combinations. I guess a another version would be better if you agree with exposing current state into live XML. Pavel
- if chardev_tls is not set and tls attribute is not configured in the XML the default after starting the domain should be tls=no
We're not getting anywhere if chardev_tls is not set.
John
[...]
-- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list

[...]
UGH... mea culpa - in my mind the TLS hadn't been added to the chardev yet and that was the rest of this series... Of course the rest of this series is adding the passphrase for the environment (<sigh>).
If I could have got that review earlier, then this situation wouldn't be a problem (see in my mind it wasn't).
If a domain is already running, then encryption is occurring and this setting has no effect except for hotplug.
If we were using encryption in 2.3.0... stopped our domain... installed 2.4.0... started our domain, then yes, I see/agree.... Frustrating since there's really no "simple" way to determine this.
The correct solution is:
- if chardev_tls is set to 1 and tls attribute is not configured in the XML the default after starting the domain should be tls=yes
So IOW:
+ if (cfg->chardevTLS && + dev->data.tcp.haveTLS == VIR_TRISTATE_BOOL_YES) {
changes to
+ if (cfg->chardevTLS && + dev->data.tcp.haveTLS != VIR_TRISTATE_BOOL_NO) {
or (haveTLS == YES || haveTLS == ABSENT)
This of course is essentially the logic from v6 which said disableTLS on a case by case basis.... All we have now is the positive form...
So for both qemuBuildChrChardevStr and qemuDomainAttachChrDevice I'd have a similar change. Does that suffice and do you need to see the change?
I think that we should reflect the state in live XML if the attribute exists.
Add a code to qemuProcessPrepareDomain() that will set dev->data.tcp.haveTLS to config value if dev->data.tcp.haveTLS == VIR_TRISTATE_BOOL_ABSENT and in qemuBuildChrChardevStr() you can just check if dev->data.tcp.haveTLS == VIR_TRISTATE_BOOL_YES. This will also ensure that the live XML contains the 'tls' attribute. But make sure, that migration works properly for all combinations.
I don't see the advantage... Altering the running domain would involve messing in qemuProcessAttach and setting the attribute for the domain if chardevTLS is set *BUT* how do we know without a bit of introspection if that domain was started with TLS and is using TLS? (IOW: looking at the running domain for tls-creds-x509). Additionally, someone could have changed the chardevTLS setting in qemu.conf after the domain was initially started and thus it wouldn't have it, so setting it blindly would probably have disastrous results. Altering a domain definition during qemuProcessPrepareDomain (e.g. domain startup time) still has no way of determining if that domain had ever been started using TLS if it's not in the XML. Finally, yeah migration is the final nail in the coffin for this. How does one migrate from 2.4 to 2.3 if 2.3 doesn't have this attribute we just quietly set to YES for them? I think the != NO is the safest solution (plus some adjustment to the formatdomain.html.in in order to describe this situation). John
I guess a another version would be better if you agree with exposing current state into live XML.
Pavel
- if chardev_tls is not set and tls attribute is not configured in the XML the default after starting the domain should be tls=no
We're not getting anywhere if chardev_tls is not set.
John
[...]
-- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list

On Fri, Oct 14, 2016 at 10:58:12AM -0400, John Ferlan wrote:
[...]
UGH... mea culpa - in my mind the TLS hadn't been added to the chardev yet and that was the rest of this series... Of course the rest of this series is adding the passphrase for the environment (<sigh>).
If I could have got that review earlier, then this situation wouldn't be a problem (see in my mind it wasn't).
If a domain is already running, then encryption is occurring and this setting has no effect except for hotplug.
If we were using encryption in 2.3.0... stopped our domain... installed 2.4.0... started our domain, then yes, I see/agree.... Frustrating since there's really no "simple" way to determine this.
The correct solution is:
- if chardev_tls is set to 1 and tls attribute is not configured in the XML the default after starting the domain should be tls=yes
So IOW:
+ if (cfg->chardevTLS && + dev->data.tcp.haveTLS == VIR_TRISTATE_BOOL_YES) {
changes to
+ if (cfg->chardevTLS && + dev->data.tcp.haveTLS != VIR_TRISTATE_BOOL_NO) {
or (haveTLS == YES || haveTLS == ABSENT)
This of course is essentially the logic from v6 which said disableTLS on a case by case basis.... All we have now is the positive form...
So for both qemuBuildChrChardevStr and qemuDomainAttachChrDevice I'd have a similar change. Does that suffice and do you need to see the change?
I think that we should reflect the state in live XML if the attribute exists.
Add a code to qemuProcessPrepareDomain() that will set dev->data.tcp.haveTLS to config value if dev->data.tcp.haveTLS == VIR_TRISTATE_BOOL_ABSENT and in qemuBuildChrChardevStr() you can just check if dev->data.tcp.haveTLS == VIR_TRISTATE_BOOL_YES. This will also ensure that the live XML contains the 'tls' attribute. But make sure, that migration works properly for all combinations.
I don't see the advantage... Altering the running domain would involve
The advantage is in case when the chardevTLS is set but the offline XML doesn't have 'tls' attribute configured. If the domain is started than it's perfectly clear from the live XML that the tls is enabled or not.
messing in qemuProcessAttach and setting the attribute for the domain if chardevTLS is set *BUT* how do we know without a bit of introspection if that domain was started with TLS and is using TLS? (IOW: looking at the running domain for tls-creds-x509). Additionally, someone could have
Well, we do that introspection and we must do it to properly detect what has been used to start that domain. The domain XML should reflect the current state as closely as possible.
changed the chardevTLS setting in qemu.conf after the domain was initially started and thus it wouldn't have it, so setting it blindly
Yes, someone can change the chardevTLS after the domain was started and it won't break anything. If the domain is destroyed and started again, everything works, if the domain is saved and started again it will start with TLS encryption enabled. If someone removes certificates from qemu.conf and completely disable TLS encryption and the domain was saved with TLS encryption configured it's desirable that it should error out while restoring that domain.
would probably have disastrous results.
Altering a domain definition during qemuProcessPrepareDomain (e.g. domain startup time) still has no way of determining if that domain had ever been started using TLS if it's not in the XML.
I don't understand why we need to know if the domain had ever been started using TLS?
Finally, yeah migration is the final nail in the coffin for this. How does one migrate from 2.4 to 2.3 if 2.3 doesn't have this attribute we just quietly set to YES for them?
Well if the attribute is set to YES and the chardevTLS is set to 1 or if the attribute is set to NO and chardevTLS is set to 0 we can safely remove the attribute from migratable XML, because it's on user to ensure that the configuration is properly set on both sides, for other cases that migration should not be allowed because whether the encryption is enabled or not could be changed. Pavel
I think the != NO is the safest solution (plus some adjustment to the formatdomain.html.in in order to describe this situation).
John
I guess a another version would be better if you agree with exposing current state into live XML.
Pavel
- if chardev_tls is not set and tls attribute is not configured in the XML the default after starting the domain should be tls=no
We're not getting anywhere if chardev_tls is not set.
John
[...]
-- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
-- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list

On 10/14/2016 11:30 AM, Pavel Hrdina wrote:
On Fri, Oct 14, 2016 at 10:58:12AM -0400, John Ferlan wrote:
[...]
UGH... mea culpa - in my mind the TLS hadn't been added to the chardev yet and that was the rest of this series... Of course the rest of this series is adding the passphrase for the environment (<sigh>).
If I could have got that review earlier, then this situation wouldn't be a problem (see in my mind it wasn't).
If a domain is already running, then encryption is occurring and this setting has no effect except for hotplug.
If we were using encryption in 2.3.0... stopped our domain... installed 2.4.0... started our domain, then yes, I see/agree.... Frustrating since there's really no "simple" way to determine this.
The correct solution is:
- if chardev_tls is set to 1 and tls attribute is not configured in the XML the default after starting the domain should be tls=yes
So IOW:
+ if (cfg->chardevTLS && + dev->data.tcp.haveTLS == VIR_TRISTATE_BOOL_YES) {
changes to
+ if (cfg->chardevTLS && + dev->data.tcp.haveTLS != VIR_TRISTATE_BOOL_NO) {
or (haveTLS == YES || haveTLS == ABSENT)
This of course is essentially the logic from v6 which said disableTLS on a case by case basis.... All we have now is the positive form...
So for both qemuBuildChrChardevStr and qemuDomainAttachChrDevice I'd have a similar change. Does that suffice and do you need to see the change?
I think that we should reflect the state in live XML if the attribute exists.
Add a code to qemuProcessPrepareDomain() that will set dev->data.tcp.haveTLS to config value if dev->data.tcp.haveTLS == VIR_TRISTATE_BOOL_ABSENT and in qemuBuildChrChardevStr() you can just check if dev->data.tcp.haveTLS == VIR_TRISTATE_BOOL_YES. This will also ensure that the live XML contains the 'tls' attribute. But make sure, that migration works properly for all combinations.
I don't see the advantage... Altering the running domain would involve
The advantage is in case when the chardevTLS is set but the offline XML doesn't have 'tls' attribute configured. If the domain is started than it's perfectly clear from the live XML that the tls is enabled or not.
From which I generated a v6 to "Add an optional "disableTLS='yes'"
Maybe I didn't explain it well enough... I don't see the advantage of modifying qemuProcessPrepareDomain or qemuProcessAttach to try and determine whether we should "enable" this property. I see no need to introspect to inspect a setting in order to then make some assumption whether the property should be enabled or not. We'll get ourselves in trouble doing so. Too much complexity, too much danger for making a bad assumption or decision. I went back to the v5 review and reconsidered Dan's review points: 1. "As default behaviour I think it is desirable that we can turn TLS on for every VM at once - I tend to view it as a host network integration task, rather than a VM configuration task. Same rationale that we use for TLS wth VNC/SPICE." 2. "There's no reason we can't have a tri-state TLS flag against the chardev in the XML too, to override the default behaviour of cfg->chardevTLS" option"... For which Dan points out: "Can we just call this "tls=yes|no" - negative attributes (disableFOO) are kind of ugly IMHO, as they imply that the default status is enabled, which is not really the case - the default is hypervisor specific and undefined." So, now there's a v7 which adds "tls='yes|no'", where the default is no and OK quite rightfully in hindsight is not what was originally requested. That's left unchanged into this v8 until you call it out. So where does that leave me - well the "tls='yes|no'" property still should exist. What changes is that rather than "enforcing" that it gets set to "yes" in order to make something work that worked before without doing so, the default should be that whatever is in qemu.conf takes priority unless someone adds "tls='no'" to the chardev entry. That's what I'll change things to and document in a soon to be posted v9.
messing in qemuProcessAttach and setting the attribute for the domain if chardevTLS is set *BUT* how do we know without a bit of introspection if that domain was started with TLS and is using TLS? (IOW: looking at the running domain for tls-creds-x509). Additionally, someone could have
Well, we do that introspection and we must do it to properly detect what has been used to start that domain. The domain XML should reflect the current state as closely as possible.
changed the chardevTLS setting in qemu.conf after the domain was initially started and thus it wouldn't have it, so setting it blindly
Yes, someone can change the chardevTLS after the domain was started and it won't break anything. If the domain is destroyed and started again, everything works, if the domain is saved and started again it will start with TLS encryption enabled. If someone removes certificates from qemu.conf and completely disable TLS encryption and the domain was saved with TLS encryption configured it's desirable that it should error out while restoring that domain.
would probably have disastrous results.
Altering a domain definition during qemuProcessPrepareDomain (e.g. domain startup time) still has no way of determining if that domain had ever been started using TLS if it's not in the XML.
I don't understand why we need to know if the domain had ever been started using TLS?
I assumed that's what you were asking... The qemuProcessPrepareDomain is called in the qemuProcessStart path. So that to me says there was concern over domain startup.
Finally, yeah migration is the final nail in the coffin for this. How does one migrate from 2.4 to 2.3 if 2.3 doesn't have this attribute we just quietly set to YES for them?
Well if the attribute is set to YES and the chardevTLS is set to 1 or if the attribute is set to NO and chardevTLS is set to 0 we can safely remove the attribute from migratable XML, because it's on user to ensure that the configuration is properly set on both sides, for other cases that migration should not be allowed because whether the encryption is enabled or not could be changed.
I think avoiding touching the migration XML is far more important than trying to figure out all the possible permutations in order to come up with some slick way to modify XML on the fly. John [...]

On Fri, Oct 14, 2016 at 03:49:13PM -0400, John Ferlan wrote:
On 10/14/2016 11:30 AM, Pavel Hrdina wrote:
On Fri, Oct 14, 2016 at 10:58:12AM -0400, John Ferlan wrote:
[...]
UGH... mea culpa - in my mind the TLS hadn't been added to the chardev yet and that was the rest of this series... Of course the rest of this series is adding the passphrase for the environment (<sigh>).
If I could have got that review earlier, then this situation wouldn't be a problem (see in my mind it wasn't).
If a domain is already running, then encryption is occurring and this setting has no effect except for hotplug.
If we were using encryption in 2.3.0... stopped our domain... installed 2.4.0... started our domain, then yes, I see/agree.... Frustrating since there's really no "simple" way to determine this.
The correct solution is:
- if chardev_tls is set to 1 and tls attribute is not configured in the XML the default after starting the domain should be tls=yes
So IOW:
+ if (cfg->chardevTLS && + dev->data.tcp.haveTLS == VIR_TRISTATE_BOOL_YES) {
changes to
+ if (cfg->chardevTLS && + dev->data.tcp.haveTLS != VIR_TRISTATE_BOOL_NO) {
or (haveTLS == YES || haveTLS == ABSENT)
This of course is essentially the logic from v6 which said disableTLS on a case by case basis.... All we have now is the positive form...
So for both qemuBuildChrChardevStr and qemuDomainAttachChrDevice I'd have a similar change. Does that suffice and do you need to see the change?
I think that we should reflect the state in live XML if the attribute exists.
Add a code to qemuProcessPrepareDomain() that will set dev->data.tcp.haveTLS to config value if dev->data.tcp.haveTLS == VIR_TRISTATE_BOOL_ABSENT and in qemuBuildChrChardevStr() you can just check if dev->data.tcp.haveTLS == VIR_TRISTATE_BOOL_YES. This will also ensure that the live XML contains the 'tls' attribute. But make sure, that migration works properly for all combinations.
I don't see the advantage... Altering the running domain would involve
The advantage is in case when the chardevTLS is set but the offline XML doesn't have 'tls' attribute configured. If the domain is started than it's perfectly clear from the live XML that the tls is enabled or not.
Maybe I didn't explain it well enough... I don't see the advantage of modifying qemuProcessPrepareDomain or qemuProcessAttach to try and determine whether we should "enable" this property. I see no need to introspect to inspect a setting in order to then make some assumption whether the property should be enabled or not. We'll get ourselves in trouble doing so. Too much complexity, too much danger for making a bad assumption or decision.
There is a small complexity but noting danger and nothing slick - in qemuProcessPrepareDomain: if (dev->data.tcp.haveTLS == VIR_TRISTATE_BOOL_ABSENT) { dev->data.tcp.haveTLS = cfg->chardevTLS; dev->data.tcp.tlsFromConfig = true; } - in qemuProcessAttach: the detection of TCP chardev is broken and doesn't even work, but if someone fix it than it's also simple if (opt && strstr(opt, "tls-creds")) dev->data.tcp.haveTLS = true; NOTE: this domain was executed outside of libvirt so it was not based on config - in virDomainChrSourceDefParseXML: add code to parse "fromConfig" if (flags & VIR_DOMAIN_DEF_PARSE_STATUS) - in virDomainChrSourceDefFormat: if (def->data.tcp.haveTLS != VIR_TRISTATE_BOOL_ABSENT && !(flags & VIR_DOMAIN_DEF_FORMAT_MIGRATABLE && def->data.tcp.tlsFromConfig)) virBufferAsprintf(buf, " tls='%s'", virTristateBoolTypeToString(def->data.tcp.haveTLS)); if (flags & VIR_DOMAIN_DEF_FORMAT_STATUS) virBufferAsprintf(buf, " fromConfig='%d'", def->data.tcp.tlsFromConfig); I can see that someone may not like this approach, but this is how it works in libvirt. It's our mess that we introduce a feature and in next release we introduce an attribute to control/reflect that feature via XML. Try to look at it from user POV, there is a config option that can enable TLS encryption for all domains and all chardevs, but there is also 'tls' attribute that can be used to disable TLS encryption if it's set in qemu.conf or enable TLS encryption if only proper certificates are set in qemu.conf. So if someone looks at the live XML, if there is an 'tls' attribute, it's clear, but if the attribute is missing, I would have to remember/check some different place to see whether TLS encryption is configured or not. I would not like this and I would asking a question why libvirt cannot reflect this case in live XML? [...]
Finally, yeah migration is the final nail in the coffin for this. How does one migrate from 2.4 to 2.3 if 2.3 doesn't have this attribute we just quietly set to YES for them?
Well if the attribute is set to YES and the chardevTLS is set to 1 or if the attribute is set to NO and chardevTLS is set to 0 we can safely remove the attribute from migratable XML, because it's on user to ensure that the configuration is properly set on both sides, for other cases that migration should not be allowed because whether the encryption is enabled or not could be changed.
I think avoiding touching the migration XML is far more important than trying to figure out all the possible permutations in order to come up with some slick way to modify XML on the fly.
I don't agree and we already do a lot of stuff to create a proper migratable XML that is backward compatible if no new feature was used. Unfortunately the 'tls' attribute isn't a new feature, the feature already exists in previous libvirt release and therefore we have to handle it properly to not break migration. Pavel

On 10/15/2016 09:37 AM, Pavel Hrdina wrote:
On Fri, Oct 14, 2016 at 03:49:13PM -0400, John Ferlan wrote:
On 10/14/2016 11:30 AM, Pavel Hrdina wrote:
On Fri, Oct 14, 2016 at 10:58:12AM -0400, John Ferlan wrote:
[...]
UGH... mea culpa - in my mind the TLS hadn't been added to the chardev yet and that was the rest of this series... Of course the rest of this series is adding the passphrase for the environment (<sigh>).
If I could have got that review earlier, then this situation wouldn't be a problem (see in my mind it wasn't).
If a domain is already running, then encryption is occurring and this setting has no effect except for hotplug.
If we were using encryption in 2.3.0... stopped our domain... installed 2.4.0... started our domain, then yes, I see/agree.... Frustrating since there's really no "simple" way to determine this.
> > The correct solution is: > > - if chardev_tls is set to 1 and tls attribute is not configured in the XML > the default after starting the domain should be tls=yes
So IOW:
+ if (cfg->chardevTLS && + dev->data.tcp.haveTLS == VIR_TRISTATE_BOOL_YES) {
changes to
+ if (cfg->chardevTLS && + dev->data.tcp.haveTLS != VIR_TRISTATE_BOOL_NO) {
or (haveTLS == YES || haveTLS == ABSENT)
This of course is essentially the logic from v6 which said disableTLS on a case by case basis.... All we have now is the positive form...
So for both qemuBuildChrChardevStr and qemuDomainAttachChrDevice I'd have a similar change. Does that suffice and do you need to see the change?
I think that we should reflect the state in live XML if the attribute exists.
Add a code to qemuProcessPrepareDomain() that will set dev->data.tcp.haveTLS to config value if dev->data.tcp.haveTLS == VIR_TRISTATE_BOOL_ABSENT and in qemuBuildChrChardevStr() you can just check if dev->data.tcp.haveTLS == VIR_TRISTATE_BOOL_YES. This will also ensure that the live XML contains the 'tls' attribute. But make sure, that migration works properly for all combinations.
I don't see the advantage... Altering the running domain would involve
The advantage is in case when the chardevTLS is set but the offline XML doesn't have 'tls' attribute configured. If the domain is started than it's perfectly clear from the live XML that the tls is enabled or not.
Maybe I didn't explain it well enough... I don't see the advantage of modifying qemuProcessPrepareDomain or qemuProcessAttach to try and determine whether we should "enable" this property. I see no need to introspect to inspect a setting in order to then make some assumption whether the property should be enabled or not. We'll get ourselves in trouble doing so. Too much complexity, too much danger for making a bad assumption or decision.
I believe I already agreed that the concept of this patch was wrong given that it's enabling a feature that could already be enabled. Like I pointed out - my mindset was geared toward what the code was in September before we had a release with the host wide changes incorporated... The initial 'disableTLS' was written right after the code was pushed and rewritten to tls='yes|no' model after review. In any case, I think it does point out a reason/need to be sure patches are considered in a timely manner! Not any one person's fault - it just something to be more diligent about. I could have pinged a little harder too! With v9, the concept of enabling a feature that's already enabled is no longer the methodology used. Rather it's disable a feature on a case by case basis, by choice. Still what's written below shouldn't be lost because I think it's very valuable for the next person that falls into the same trap needing to do adjust a feature that could already be 'in use'. I would hope that something could be added to the hacking page or a wiki page for things that need to be considered...
There is a small complexity but noting danger and nothing slick
- in qemuProcessPrepareDomain: if (dev->data.tcp.haveTLS == VIR_TRISTATE_BOOL_ABSENT) { dev->data.tcp.haveTLS = cfg->chardevTLS; dev->data.tcp.tlsFromConfig = true; }
- in qemuProcessAttach: the detection of TCP chardev is broken and doesn't even work, but if someone fix it than it's also simple
if (opt && strstr(opt, "tls-creds")) dev->data.tcp.haveTLS = true;
FWIW: A quick look in qemuProcessAttach doesn't have 'opt'... But then again isn't this for the qemu-attach processing, not the same path used when a new libvirtd starts and finds the currently running domains. My brain hurts every time I dig into that code.
NOTE: this domain was executed outside of libvirt so it was not based on config
- in virDomainChrSourceDefParseXML: add code to parse "fromConfig" if (flags & VIR_DOMAIN_DEF_PARSE_STATUS)
- in virDomainChrSourceDefFormat: if (def->data.tcp.haveTLS != VIR_TRISTATE_BOOL_ABSENT && !(flags & VIR_DOMAIN_DEF_FORMAT_MIGRATABLE && def->data.tcp.tlsFromConfig)) virBufferAsprintf(buf, " tls='%s'", virTristateBoolTypeToString(def->data.tcp.haveTLS));
if (flags & VIR_DOMAIN_DEF_FORMAT_STATUS) virBufferAsprintf(buf, " fromConfig='%d'", def->data.tcp.tlsFromConfig);
I can see that someone may not like this approach, but this is how it works in libvirt. It's our mess that we introduce a feature and in next release we introduce an attribute to control/reflect that feature via XML.
Like or dislike, it's not exactly what "simply" comes to mind when adding a new attribute... There is a bit of complexity and knowledge perhaps gained from having done this before that makes it easier the second, third, fourth, etc. time around... Hence why I suggest a wiki/hacking entry to describe what needs to be considered.
Try to look at it from user POV, there is a config option that can enable TLS encryption for all domains and all chardevs, but there is also 'tls' attribute that can be used to disable TLS encryption if it's set in qemu.conf or enable TLS encryption if only proper certificates are set in qemu.conf. So if someone looks at the live XML, if there is an 'tls' attribute, it's clear, but if the attribute is missing, I would have to remember/check some different place to see whether TLS encryption is configured or not. I would not like this and I would asking a question why libvirt cannot reflect this case in live XML?
I get it - again my POV wasn't from the perspective that a release could already have TLS enabled for a domain... Do you think this still applies given v9 logic to add the disable attribute? User sets chardev_tls = 1 in qemu.conf... User is happy. One day user realizes that I have this domain that I don't want that. User finds the tls flag for their <serial type='tcp'> <source ...> chardev. User sets attribute tls='no' on that chardev and is happy again. Is there a live XML concern with tls='no' ('yes' and 'absent' follow the host setting).
[...]
Finally, yeah migration is the final nail in the coffin for this. How does one migrate from 2.4 to 2.3 if 2.3 doesn't have this attribute we just quietly set to YES for them?
Well if the attribute is set to YES and the chardevTLS is set to 1 or if the attribute is set to NO and chardevTLS is set to 0 we can safely remove the attribute from migratable XML, because it's on user to ensure that the configuration is properly set on both sides, for other cases that migration should not be allowed because whether the encryption is enabled or not could be changed.
I think avoiding touching the migration XML is far more important than trying to figure out all the possible permutations in order to come up with some slick way to modify XML on the fly.
I don't agree and we already do a lot of stuff to create a proper migratable XML that is backward compatible if no new feature was used. Unfortunately the 'tls' attribute isn't a new feature, the feature already exists in previous libvirt release and therefore we have to handle it properly to not break migration.
Again, in the mindset of tls='no' has to be set - is there a concern still? One concern I can think of is if hostA is using TLS via qemu.conf, we migrate the domain to hostB which hasn't configure TLS - now what? Something to dig into on Monday... John

Add a new qemu.conf variables to store the UUID for the secret that could be used to present credentials to access the TLS chardev. Since this will be a server level and it's possible to use some sort of default, introduce both the default and chardev logic at the same time making the setting of the chardev check for it's own value, then if not present checking whether the default value had been set. The chardevTLSx509haveUUID bool will be used as the marker for whether the chardevTLSx509secretUUID was successfully read. In the future this is how it'd determined whether to add the secret object for a TLS object. Signed-off-by: John Ferlan <jferlan@redhat.com> --- src/qemu/libvirtd_qemu.aug | 2 ++ src/qemu/qemu.conf | 24 ++++++++++++++++++++++++ src/qemu/qemu_conf.c | 22 ++++++++++++++++++++++ src/qemu/qemu_conf.h | 3 +++ src/qemu/test_libvirtd_qemu.aug.in | 2 ++ 5 files changed, 53 insertions(+) diff --git a/src/qemu/libvirtd_qemu.aug b/src/qemu/libvirtd_qemu.aug index 988201e..73ebeda 100644 --- a/src/qemu/libvirtd_qemu.aug +++ b/src/qemu/libvirtd_qemu.aug @@ -29,6 +29,7 @@ module Libvirtd_qemu = (* Config entry grouped by function - same order as example config *) let default_tls_entry = str_entry "default_tls_x509_cert_dir" | bool_entry "default_tls_x509_verify" + | str_entry "default_tls_x509_secret_uuid" let vnc_entry = str_entry "vnc_listen" | bool_entry "vnc_auto_unix_socket" @@ -51,6 +52,7 @@ module Libvirtd_qemu = let chardev_entry = bool_entry "chardev_tls" | str_entry "chardev_tls_x509_cert_dir" | bool_entry "chardev_tls_x509_verify" + | str_entry "chardev_tls_x509_secret_uuid" let nogfx_entry = bool_entry "nographics_allow_host_audio" diff --git a/src/qemu/qemu.conf b/src/qemu/qemu.conf index e4c2aae..f136fa9 100644 --- a/src/qemu/qemu.conf +++ b/src/qemu/qemu.conf @@ -28,6 +28,20 @@ # #default_tls_x509_verify = 1 +# +# Libvirt assumes the server-key.pem file is unencrypted by default. +# To use an encrypted server-key.pem file, the password to decrypt the +# the PEM file is requird. This can be provided by creating a secret +# object in libvirt and then uncommenting this setting to set the UUID +# UUID of the secret. +# +# NB This default all-zeros UUID will not work. Replace it with the +# output from the UUID for the TLS secret from a 'virsh secret-list' +# command and then uncomment the entry +# +#default_tls_x509_secret_uuid = "00000000-0000-0000-0000-000000000000" + + # VNC is configured to listen on 127.0.0.1 by default. # To make it listen on all public interfaces, uncomment # this next option. @@ -214,6 +228,16 @@ #chardev_tls_x509_verify = 1 +# Uncomment and use the following option to override the default secret +# uuid provided in the default_tls_x509_secret_uuid parameter. +# +# NB This default all-zeros UUID will not work. Replace it with the +# output from the UUID for the TLS secret from a 'virsh secret-list' +# command and then uncomment the entry +# +#chardev_tls_x509_secret_uuid = "00000000-0000-0000-0000-000000000000" + + # By default, if no graphical front end is configured, libvirt will disable # QEMU audio output since directly talking to alsa/pulseaudio may not work # with various security settings. If you know what you're doing, enable diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c index 635fa27..c650961 100644 --- a/src/qemu/qemu_conf.c +++ b/src/qemu/qemu_conf.c @@ -365,6 +365,7 @@ static void virQEMUDriverConfigDispose(void *obj) VIR_FREE(cfg->nvramDir); VIR_FREE(cfg->defaultTLSx509certdir); + VIR_FREE(cfg->defaultTLSx509secretUUID); VIR_FREE(cfg->vncTLSx509certdir); VIR_FREE(cfg->vncListen); @@ -377,6 +378,7 @@ static void virQEMUDriverConfigDispose(void *obj) VIR_FREE(cfg->spiceSASLdir); VIR_FREE(cfg->chardevTLSx509certdir); + VIR_FREE(cfg->chardevTLSx509secretUUID); while (cfg->nhugetlbfs) { cfg->nhugetlbfs--; @@ -424,6 +426,7 @@ int virQEMUDriverConfigLoadFile(virQEMUDriverConfigPtr cfg, int ret = -1; int rv; size_t i, j; + bool defaultTLSx509haveUUID; char *stdioHandler = NULL; char *user = NULL, *group = NULL; char **controllers = NULL; @@ -446,6 +449,12 @@ int virQEMUDriverConfigLoadFile(virQEMUDriverConfigPtr cfg, goto cleanup; if (virConfGetValueBool(conf, "default_tls_x509_verify", &cfg->defaultTLSx509verify) < 0) goto cleanup; + if ((rv = virConfGetValueString(conf, "default_tls_x509_secret_uuid", + &cfg->defaultTLSx509secretUUID)) < 0) + goto cleanup; + if (rv == 1) + defaultTLSx509haveUUID = true; + if (virConfGetValueBool(conf, "vnc_auto_unix_socket", &cfg->vncAutoUnixSocket) < 0) goto cleanup; if (virConfGetValueBool(conf, "vnc_tls", &cfg->vncTLS) < 0) @@ -513,6 +522,19 @@ int virQEMUDriverConfigLoadFile(virQEMUDriverConfigPtr cfg, goto cleanup; if (rv == 0) cfg->chardevTLSx509verify = cfg->defaultTLSx509verify; + if ((rv = virConfGetValueString(conf, "chardev_tls_x509_secret_uuid", + &cfg->chardevTLSx509secretUUID)) < 0) + goto cleanup; + if (rv == 1) { + cfg->chardevTLSx509haveUUID = true; + } else { + if (defaultTLSx509haveUUID) { + if (VIR_STRDUP(cfg->chardevTLSx509secretUUID, + cfg->defaultTLSx509secretUUID) < 0) + goto cleanup; + cfg->chardevTLSx509haveUUID = true; + } + } if (virConfGetValueUInt(conf, "remote_websocket_port_min", &cfg->webSocketPortMin) < 0) goto cleanup; diff --git a/src/qemu/qemu_conf.h b/src/qemu/qemu_conf.h index d32689a..a7b01c9 100644 --- a/src/qemu/qemu_conf.h +++ b/src/qemu/qemu_conf.h @@ -111,6 +111,7 @@ struct _virQEMUDriverConfig { char *defaultTLSx509certdir; bool defaultTLSx509verify; + char *defaultTLSx509secretUUID; bool vncAutoUnixSocket; bool vncTLS; @@ -132,6 +133,8 @@ struct _virQEMUDriverConfig { bool chardevTLS; char *chardevTLSx509certdir; bool chardevTLSx509verify; + bool chardevTLSx509haveUUID; + char *chardevTLSx509secretUUID; unsigned int remotePortMin; unsigned int remotePortMax; diff --git a/src/qemu/test_libvirtd_qemu.aug.in b/src/qemu/test_libvirtd_qemu.aug.in index cd162ae..805fa0e 100644 --- a/src/qemu/test_libvirtd_qemu.aug.in +++ b/src/qemu/test_libvirtd_qemu.aug.in @@ -4,6 +4,7 @@ module Test_libvirtd_qemu = test Libvirtd_qemu.lns get conf = { "default_tls_x509_cert_dir" = "/etc/pki/qemu" } { "default_tls_x509_verify" = "1" } +{ "default_tls_x509_secret_uuid" = "00000000-0000-0000-0000-000000000000" } { "vnc_listen" = "0.0.0.0" } { "vnc_auto_unix_socket" = "1" } { "vnc_tls" = "1" } @@ -23,6 +24,7 @@ module Test_libvirtd_qemu = { "chardev_tls" = "1" } { "chardev_tls_x509_cert_dir" = "/etc/pki/libvirt-chardev" } { "chardev_tls_x509_verify" = "1" } +{ "chardev_tls_x509_secret_uuid" = "00000000-0000-0000-0000-000000000000" } { "nographics_allow_host_audio" = "1" } { "remote_display_port_min" = "5900" } { "remote_display_port_max" = "65535" } -- 2.7.4

On Fri, Oct 07, 2016 at 07:00:27AM -0400, John Ferlan wrote:
Add a new qemu.conf variables to store the UUID for the secret that could be used to present credentials to access the TLS chardev. Since this will be a server level and it's possible to use some sort of default, introduce both the default and chardev logic at the same time making the setting of the chardev check for it's own value, then if not present checking whether the default value had been set.
The chardevTLSx509haveUUID bool will be used as the marker for whether the chardevTLSx509secretUUID was successfully read. In the future this is how it'd determined whether to add the secret object for a TLS object.
Signed-off-by: John Ferlan <jferlan@redhat.com> --- src/qemu/libvirtd_qemu.aug | 2 ++ src/qemu/qemu.conf | 24 ++++++++++++++++++++++++ src/qemu/qemu_conf.c | 22 ++++++++++++++++++++++ src/qemu/qemu_conf.h | 3 +++ src/qemu/test_libvirtd_qemu.aug.in | 2 ++ 5 files changed, 53 insertions(+)
diff --git a/src/qemu/libvirtd_qemu.aug b/src/qemu/libvirtd_qemu.aug index 988201e..73ebeda 100644 --- a/src/qemu/libvirtd_qemu.aug +++ b/src/qemu/libvirtd_qemu.aug @@ -29,6 +29,7 @@ module Libvirtd_qemu = (* Config entry grouped by function - same order as example config *) let default_tls_entry = str_entry "default_tls_x509_cert_dir" | bool_entry "default_tls_x509_verify" + | str_entry "default_tls_x509_secret_uuid"
let vnc_entry = str_entry "vnc_listen" | bool_entry "vnc_auto_unix_socket" @@ -51,6 +52,7 @@ module Libvirtd_qemu = let chardev_entry = bool_entry "chardev_tls" | str_entry "chardev_tls_x509_cert_dir" | bool_entry "chardev_tls_x509_verify" + | str_entry "chardev_tls_x509_secret_uuid"
let nogfx_entry = bool_entry "nographics_allow_host_audio"
diff --git a/src/qemu/qemu.conf b/src/qemu/qemu.conf index e4c2aae..f136fa9 100644 --- a/src/qemu/qemu.conf +++ b/src/qemu/qemu.conf @@ -28,6 +28,20 @@ # #default_tls_x509_verify = 1
+# +# Libvirt assumes the server-key.pem file is unencrypted by default. +# To use an encrypted server-key.pem file, the password to decrypt the
s/ the//
+# the PEM file is requird. This can be provided by creating a secret +# object in libvirt and then uncommenting this setting to set the UUID +# UUID of the secret. +# +# NB This default all-zeros UUID will not work. Replace it with the +# output from the UUID for the TLS secret from a 'virsh secret-list' +# command and then uncomment the entry +# +#default_tls_x509_secret_uuid = "00000000-0000-0000-0000-000000000000" + + # VNC is configured to listen on 127.0.0.1 by default. # To make it listen on all public interfaces, uncomment # this next option. @@ -214,6 +228,16 @@ #chardev_tls_x509_verify = 1
+# Uncomment and use the following option to override the default secret +# uuid provided in the default_tls_x509_secret_uuid parameter. +# +# NB This default all-zeros UUID will not work. Replace it with the +# output from the UUID for the TLS secret from a 'virsh secret-list' +# command and then uncomment the entry +# +#chardev_tls_x509_secret_uuid = "00000000-0000-0000-0000-000000000000" + + # By default, if no graphical front end is configured, libvirt will disable # QEMU audio output since directly talking to alsa/pulseaudio may not work # with various security settings. If you know what you're doing, enable diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c index 635fa27..c650961 100644 --- a/src/qemu/qemu_conf.c +++ b/src/qemu/qemu_conf.c @@ -365,6 +365,7 @@ static void virQEMUDriverConfigDispose(void *obj) VIR_FREE(cfg->nvramDir);
VIR_FREE(cfg->defaultTLSx509certdir); + VIR_FREE(cfg->defaultTLSx509secretUUID);
VIR_FREE(cfg->vncTLSx509certdir); VIR_FREE(cfg->vncListen); @@ -377,6 +378,7 @@ static void virQEMUDriverConfigDispose(void *obj) VIR_FREE(cfg->spiceSASLdir);
VIR_FREE(cfg->chardevTLSx509certdir); + VIR_FREE(cfg->chardevTLSx509secretUUID);
while (cfg->nhugetlbfs) { cfg->nhugetlbfs--; @@ -424,6 +426,7 @@ int virQEMUDriverConfigLoadFile(virQEMUDriverConfigPtr cfg, int ret = -1; int rv; size_t i, j; + bool defaultTLSx509haveUUID; char *stdioHandler = NULL; char *user = NULL, *group = NULL; char **controllers = NULL; @@ -446,6 +449,12 @@ int virQEMUDriverConfigLoadFile(virQEMUDriverConfigPtr cfg, goto cleanup; if (virConfGetValueBool(conf, "default_tls_x509_verify", &cfg->defaultTLSx509verify) < 0) goto cleanup; + if ((rv = virConfGetValueString(conf, "default_tls_x509_secret_uuid", + &cfg->defaultTLSx509secretUUID)) < 0) + goto cleanup; + if (rv == 1) + defaultTLSx509haveUUID = true;
I don't see any reason to use the extra bool variable. Function virConfGetValueString() has this logic: -1 - we error out 0 - string was not found, value is set to NULL 1 - string was found, value is set IOW you can just use defaultTLSx509secretUUID to detect whether there is something configured or not. The same applies to chardevTLSx509haveUUID.
+ if (virConfGetValueBool(conf, "vnc_auto_unix_socket", &cfg->vncAutoUnixSocket) < 0) goto cleanup; if (virConfGetValueBool(conf, "vnc_tls", &cfg->vncTLS) < 0) @@ -513,6 +522,19 @@ int virQEMUDriverConfigLoadFile(virQEMUDriverConfigPtr cfg, goto cleanup; if (rv == 0) cfg->chardevTLSx509verify = cfg->defaultTLSx509verify; + if ((rv = virConfGetValueString(conf, "chardev_tls_x509_secret_uuid", + &cfg->chardevTLSx509secretUUID)) < 0) + goto cleanup; + if (rv == 1) { + cfg->chardevTLSx509haveUUID = true; + } else { + if (defaultTLSx509haveUUID) { + if (VIR_STRDUP(cfg->chardevTLSx509secretUUID, + cfg->defaultTLSx509secretUUID) < 0) + goto cleanup; + cfg->chardevTLSx509haveUUID = true; + }
Copying the defaultTLSx509secretUUID should be done only in case rv == 0, otherwise we need to call goto cleanup; Pavel
+ }
if (virConfGetValueUInt(conf, "remote_websocket_port_min", &cfg->webSocketPortMin) < 0) goto cleanup; diff --git a/src/qemu/qemu_conf.h b/src/qemu/qemu_conf.h index d32689a..a7b01c9 100644 --- a/src/qemu/qemu_conf.h +++ b/src/qemu/qemu_conf.h @@ -111,6 +111,7 @@ struct _virQEMUDriverConfig {
char *defaultTLSx509certdir; bool defaultTLSx509verify; + char *defaultTLSx509secretUUID;
bool vncAutoUnixSocket; bool vncTLS; @@ -132,6 +133,8 @@ struct _virQEMUDriverConfig { bool chardevTLS; char *chardevTLSx509certdir; bool chardevTLSx509verify; + bool chardevTLSx509haveUUID; + char *chardevTLSx509secretUUID;
unsigned int remotePortMin; unsigned int remotePortMax; diff --git a/src/qemu/test_libvirtd_qemu.aug.in b/src/qemu/test_libvirtd_qemu.aug.in index cd162ae..805fa0e 100644 --- a/src/qemu/test_libvirtd_qemu.aug.in +++ b/src/qemu/test_libvirtd_qemu.aug.in @@ -4,6 +4,7 @@ module Test_libvirtd_qemu = test Libvirtd_qemu.lns get conf = { "default_tls_x509_cert_dir" = "/etc/pki/qemu" } { "default_tls_x509_verify" = "1" } +{ "default_tls_x509_secret_uuid" = "00000000-0000-0000-0000-000000000000" } { "vnc_listen" = "0.0.0.0" } { "vnc_auto_unix_socket" = "1" } { "vnc_tls" = "1" } @@ -23,6 +24,7 @@ module Test_libvirtd_qemu = { "chardev_tls" = "1" } { "chardev_tls_x509_cert_dir" = "/etc/pki/libvirt-chardev" } { "chardev_tls_x509_verify" = "1" } +{ "chardev_tls_x509_secret_uuid" = "00000000-0000-0000-0000-000000000000" } { "nographics_allow_host_audio" = "1" } { "remote_display_port_min" = "5900" } { "remote_display_port_max" = "65535" } -- 2.7.4
-- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list

On 10/14/2016 10:53 AM, Pavel Hrdina wrote:
On Fri, Oct 07, 2016 at 07:00:27AM -0400, John Ferlan wrote:
Add a new qemu.conf variables to store the UUID for the secret that could be used to present credentials to access the TLS chardev. Since this will be a server level and it's possible to use some sort of default, introduce both the default and chardev logic at the same time making the setting of the chardev check for it's own value, then if not present checking whether the default value had been set.
The chardevTLSx509haveUUID bool will be used as the marker for whether the chardevTLSx509secretUUID was successfully read. In the future this is how it'd determined whether to add the secret object for a TLS object.
Signed-off-by: John Ferlan <jferlan@redhat.com> --- src/qemu/libvirtd_qemu.aug | 2 ++ src/qemu/qemu.conf | 24 ++++++++++++++++++++++++ src/qemu/qemu_conf.c | 22 ++++++++++++++++++++++ src/qemu/qemu_conf.h | 3 +++ src/qemu/test_libvirtd_qemu.aug.in | 2 ++ 5 files changed, 53 insertions(+)
diff --git a/src/qemu/libvirtd_qemu.aug b/src/qemu/libvirtd_qemu.aug index 988201e..73ebeda 100644 --- a/src/qemu/libvirtd_qemu.aug +++ b/src/qemu/libvirtd_qemu.aug @@ -29,6 +29,7 @@ module Libvirtd_qemu = (* Config entry grouped by function - same order as example config *) let default_tls_entry = str_entry "default_tls_x509_cert_dir" | bool_entry "default_tls_x509_verify" + | str_entry "default_tls_x509_secret_uuid"
let vnc_entry = str_entry "vnc_listen" | bool_entry "vnc_auto_unix_socket" @@ -51,6 +52,7 @@ module Libvirtd_qemu = let chardev_entry = bool_entry "chardev_tls" | str_entry "chardev_tls_x509_cert_dir" | bool_entry "chardev_tls_x509_verify" + | str_entry "chardev_tls_x509_secret_uuid"
let nogfx_entry = bool_entry "nographics_allow_host_audio"
diff --git a/src/qemu/qemu.conf b/src/qemu/qemu.conf index e4c2aae..f136fa9 100644 --- a/src/qemu/qemu.conf +++ b/src/qemu/qemu.conf @@ -28,6 +28,20 @@ # #default_tls_x509_verify = 1
+# +# Libvirt assumes the server-key.pem file is unencrypted by default. +# To use an encrypted server-key.pem file, the password to decrypt the
s/ the//
OK
+# the PEM file is requird. This can be provided by creating a secret
Fixed required too..
+# object in libvirt and then uncommenting this setting to set the UUID
changed uncommenting to "to uncomment"
+# UUID of the secret. +# +# NB This default all-zeros UUID will not work. Replace it with the +# output from the UUID for the TLS secret from a 'virsh secret-list' +# command and then uncomment the entry +# +#default_tls_x509_secret_uuid = "00000000-0000-0000-0000-000000000000" + + # VNC is configured to listen on 127.0.0.1 by default. # To make it listen on all public interfaces, uncomment # this next option. @@ -214,6 +228,16 @@ #chardev_tls_x509_verify = 1
+# Uncomment and use the following option to override the default secret +# uuid provided in the default_tls_x509_secret_uuid parameter. +# +# NB This default all-zeros UUID will not work. Replace it with the +# output from the UUID for the TLS secret from a 'virsh secret-list' +# command and then uncomment the entry +# +#chardev_tls_x509_secret_uuid = "00000000-0000-0000-0000-000000000000" + + # By default, if no graphical front end is configured, libvirt will disable # QEMU audio output since directly talking to alsa/pulseaudio may not work # with various security settings. If you know what you're doing, enable diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c index 635fa27..c650961 100644 --- a/src/qemu/qemu_conf.c +++ b/src/qemu/qemu_conf.c @@ -365,6 +365,7 @@ static void virQEMUDriverConfigDispose(void *obj) VIR_FREE(cfg->nvramDir);
VIR_FREE(cfg->defaultTLSx509certdir); + VIR_FREE(cfg->defaultTLSx509secretUUID);
VIR_FREE(cfg->vncTLSx509certdir); VIR_FREE(cfg->vncListen); @@ -377,6 +378,7 @@ static void virQEMUDriverConfigDispose(void *obj) VIR_FREE(cfg->spiceSASLdir);
VIR_FREE(cfg->chardevTLSx509certdir); + VIR_FREE(cfg->chardevTLSx509secretUUID);
while (cfg->nhugetlbfs) { cfg->nhugetlbfs--; @@ -424,6 +426,7 @@ int virQEMUDriverConfigLoadFile(virQEMUDriverConfigPtr cfg, int ret = -1; int rv; size_t i, j; + bool defaultTLSx509haveUUID; char *stdioHandler = NULL; char *user = NULL, *group = NULL; char **controllers = NULL; @@ -446,6 +449,12 @@ int virQEMUDriverConfigLoadFile(virQEMUDriverConfigPtr cfg, goto cleanup; if (virConfGetValueBool(conf, "default_tls_x509_verify", &cfg->defaultTLSx509verify) < 0) goto cleanup; + if ((rv = virConfGetValueString(conf, "default_tls_x509_secret_uuid", + &cfg->defaultTLSx509secretUUID)) < 0) + goto cleanup; + if (rv == 1) + defaultTLSx509haveUUID = true;
I don't see any reason to use the extra bool variable. Function virConfGetValueString() has this logic:
-1 - we error out 0 - string was not found, value is set to NULL 1 - string was found, value is set
IOW you can just use defaultTLSx509secretUUID to detect whether there is something configured or not. The same applies to chardevTLSx509haveUUID.
Well it's been so long I have no idea what I was thinking, but yeah the booleans are unnecessary. I'll remove them.
+ if (virConfGetValueBool(conf, "vnc_auto_unix_socket", &cfg->vncAutoUnixSocket) < 0) goto cleanup; if (virConfGetValueBool(conf, "vnc_tls", &cfg->vncTLS) < 0) @@ -513,6 +522,19 @@ int virQEMUDriverConfigLoadFile(virQEMUDriverConfigPtr cfg, goto cleanup; if (rv == 0) cfg->chardevTLSx509verify = cfg->defaultTLSx509verify; + if ((rv = virConfGetValueString(conf, "chardev_tls_x509_secret_uuid", + &cfg->chardevTLSx509secretUUID)) < 0) + goto cleanup; + if (rv == 1) { + cfg->chardevTLSx509haveUUID = true; + } else { + if (defaultTLSx509haveUUID) { + if (VIR_STRDUP(cfg->chardevTLSx509secretUUID, + cfg->defaultTLSx509secretUUID) < 0) + goto cleanup; + cfg->chardevTLSx509haveUUID = true; + }
Copying the defaultTLSx509secretUUID should be done only in case rv == 0, otherwise we need to call goto cleanup;
This is changed to: if (!cfg->chardevTLSx509secretUUID && cfg->defaultTLSx509secretUUID) { IOW: We didn't find a chardev specific UUID, but do have a default one, so copy it. The setting affects patch 4 as well (since chardevTLSx509haveUUID would be removed). Tks - John [...]

Modeled after the qemuDomainHostdevPrivatePtr (commit id '27726d8c'), create a privateData pointer in the _virDomainChardevDef to allow storage of private data for a hypervisor in order to at least temporarily store secret data for usage during qemuBuildCommandLine. NB: Since the qemu_parse_command (qemuParseCommandLine) code is not expecting to restore the secret data, there's no need to add code code to handle this new structure there. Signed-off-by: John Ferlan <jferlan@redhat.com> --- src/conf/domain_conf.c | 29 ++++++++++++++++++++-------- src/conf/domain_conf.h | 4 +++- src/libxl/libxl_domain.c | 2 +- src/lxc/lxc_native.c | 2 +- src/qemu/qemu_domain.c | 44 +++++++++++++++++++++++++++++++++++++++++++ src/qemu/qemu_domain.h | 14 ++++++++++++++ src/qemu/qemu_parse_command.c | 4 ++-- src/vz/vz_sdk.c | 2 +- src/xenconfig/xen_sxpr.c | 2 +- src/xenconfig/xen_xl.c | 2 +- 10 files changed, 89 insertions(+), 16 deletions(-) diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 1f7c43f..c52144f 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -2091,6 +2091,8 @@ void virDomainChrDefFree(virDomainChrDefPtr def) VIR_FREE(def->seclabels); } + virObjectUnref(def->privateData); + VIR_FREE(def); } @@ -10294,7 +10296,7 @@ virDomainChrSourceDefParseXML(virDomainChrSourceDefPtr def, * default port. */ virDomainChrDefPtr -virDomainChrDefNew(void) +virDomainChrDefNew(virDomainXMLOptionPtr xmlopt) { virDomainChrDefPtr def = NULL; @@ -10302,6 +10304,11 @@ virDomainChrDefNew(void) return NULL; def->target.port = -1; + + if (xmlopt && xmlopt->privateData.chardevNew && + !(def->privateData = xmlopt->privateData.chardevNew())) + VIR_FREE(def); + return def; } @@ -10349,7 +10356,8 @@ virDomainChrDefNew(void) * */ static virDomainChrDefPtr -virDomainChrDefParseXML(xmlXPathContextPtr ctxt, +virDomainChrDefParseXML(virDomainXMLOptionPtr xmlopt, + xmlXPathContextPtr ctxt, xmlNodePtr node, virSecurityLabelDefPtr* vmSeclabels, int nvmSeclabels, @@ -10361,7 +10369,7 @@ virDomainChrDefParseXML(xmlXPathContextPtr ctxt, virDomainChrDefPtr def; bool seenTarget = false; - if (!(def = virDomainChrDefNew())) + if (!(def = virDomainChrDefNew(xmlopt))) return NULL; type = virXMLPropString(node, "type"); @@ -13538,7 +13546,8 @@ virDomainDeviceDefParse(const char *xmlStr, goto error; break; case VIR_DOMAIN_DEVICE_CHR: - if (!(dev->data.chr = virDomainChrDefParseXML(ctxt, + if (!(dev->data.chr = virDomainChrDefParseXML(xmlopt, + ctxt, node, def->seclabels, def->nseclabels, @@ -17160,7 +17169,8 @@ virDomainDefParseXML(xmlDocPtr xml, goto error; for (i = 0; i < n; i++) { - virDomainChrDefPtr chr = virDomainChrDefParseXML(ctxt, + virDomainChrDefPtr chr = virDomainChrDefParseXML(xmlopt, + ctxt, nodes[i], def->seclabels, def->nseclabels, @@ -17187,7 +17197,8 @@ virDomainDefParseXML(xmlDocPtr xml, goto error; for (i = 0; i < n; i++) { - virDomainChrDefPtr chr = virDomainChrDefParseXML(ctxt, + virDomainChrDefPtr chr = virDomainChrDefParseXML(xmlopt, + ctxt, nodes[i], def->seclabels, def->nseclabels, @@ -17216,7 +17227,8 @@ virDomainDefParseXML(xmlDocPtr xml, goto error; for (i = 0; i < n; i++) { - virDomainChrDefPtr chr = virDomainChrDefParseXML(ctxt, + virDomainChrDefPtr chr = virDomainChrDefParseXML(xmlopt, + ctxt, nodes[i], def->seclabels, def->nseclabels, @@ -17235,7 +17247,8 @@ virDomainDefParseXML(xmlDocPtr xml, goto error; for (i = 0; i < n; i++) { - virDomainChrDefPtr chr = virDomainChrDefParseXML(ctxt, + virDomainChrDefPtr chr = virDomainChrDefParseXML(xmlopt, + ctxt, nodes[i], def->seclabels, def->nseclabels, diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index da203c3..4769144 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -1118,6 +1118,7 @@ struct _virDomainChrSourceDef { /* A complete character device, both host and domain views. */ struct _virDomainChrDef { int deviceType; /* enum virDomainChrDeviceType */ + virObjectPtr privateData; bool targetTypeAttr; int targetType; /* enum virDomainChrConsoleTargetType || @@ -2447,6 +2448,7 @@ struct _virDomainXMLPrivateDataCallbacks { virDomainXMLPrivateDataNewFunc diskNew; virDomainXMLPrivateDataNewFunc hostdevNew; virDomainXMLPrivateDataNewFunc vcpuNew; + virDomainXMLPrivateDataNewFunc chardevNew; virDomainXMLPrivateDataFormatFunc format; virDomainXMLPrivateDataParseFunc parse; }; @@ -2580,7 +2582,7 @@ bool virDomainDefHasDeviceAddress(virDomainDefPtr def, void virDomainDefFree(virDomainDefPtr vm); -virDomainChrDefPtr virDomainChrDefNew(void); +virDomainChrDefPtr virDomainChrDefNew(virDomainXMLOptionPtr xmlopt); virDomainDefPtr virDomainDefNew(void); virDomainDefPtr virDomainDefNewFull(const char *name, diff --git a/src/libxl/libxl_domain.c b/src/libxl/libxl_domain.c index db2c1dc..617e13c 100644 --- a/src/libxl/libxl_domain.c +++ b/src/libxl/libxl_domain.c @@ -389,7 +389,7 @@ libxlDomainDefPostParse(virDomainDefPtr def, if (def->os.type != VIR_DOMAIN_OSTYPE_HVM && def->nconsoles == 0) { virDomainChrDefPtr chrdef; - if (!(chrdef = virDomainChrDefNew())) + if (!(chrdef = virDomainChrDefNew(NULL))) return -1; chrdef->source.type = VIR_DOMAIN_CHR_TYPE_PTY; diff --git a/src/lxc/lxc_native.c b/src/lxc/lxc_native.c index 76b7922..b6d26b2 100644 --- a/src/lxc/lxc_native.c +++ b/src/lxc/lxc_native.c @@ -703,7 +703,7 @@ lxcCreateConsoles(virDomainDefPtr def, virConfPtr properties) def->nconsoles = nbttys; for (i = 0; i < nbttys; i++) { - if (!(console = virDomainChrDefNew())) + if (!(console = virDomainChrDefNew(NULL))) goto error; console->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE; diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index 2b24c01..ad1e4bc 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -864,6 +864,49 @@ qemuDomainVcpuPrivateDispose(void *obj) } +static virClassPtr qemuDomainChardevPrivateClass; +static void qemuDomainChardevPrivateDispose(void *obj); + +static int +qemuDomainChardevPrivateOnceInit(void) +{ + qemuDomainChardevPrivateClass = + virClassNew(virClassForObject(), + "qemuDomainChardevPrivate", + sizeof(qemuDomainChardevPrivate), + qemuDomainChardevPrivateDispose); + if (!qemuDomainChardevPrivateClass) + return -1; + else + return 0; +} + +VIR_ONCE_GLOBAL_INIT(qemuDomainChardevPrivate) + +static virObjectPtr +qemuDomainChardevPrivateNew(void) +{ + qemuDomainChardevPrivatePtr priv; + + if (qemuDomainChardevPrivateInitialize() < 0) + return NULL; + + if (!(priv = virObjectNew(qemuDomainChardevPrivateClass))) + return NULL; + + return (virObjectPtr) priv; +} + + +static void +qemuDomainChardevPrivateDispose(void *obj) +{ + qemuDomainChardevPrivatePtr priv = obj; + + qemuDomainSecretInfoFree(&priv->secinfo); +} + + /* qemuDomainSecretPlainSetup: * @conn: Pointer to connection * @secinfo: Pointer to secret info @@ -1767,6 +1810,7 @@ virDomainXMLPrivateDataCallbacks virQEMUDriverPrivateDataCallbacks = { .diskNew = qemuDomainDiskPrivateNew, .vcpuNew = qemuDomainVcpuPrivateNew, .hostdevNew = qemuDomainHostdevPrivateNew, + .chardevNew = qemuDomainChardevPrivateNew, .parse = qemuDomainObjPrivateXMLParse, .format = qemuDomainObjPrivateXMLFormat, }; diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h index 521531b..54ec5b8 100644 --- a/src/qemu/qemu_domain.h +++ b/src/qemu/qemu_domain.h @@ -352,6 +352,20 @@ struct _qemuDomainHostdevPrivate { qemuDomainSecretInfoPtr secinfo; }; +# define QEMU_DOMAIN_CHARDEV_PRIVATE(chardev) \ + ((qemuDomainChardevPrivatePtr) (chardev)->privateData) + +typedef struct _qemuDomainChardevPrivate qemuDomainChardevPrivate; +typedef qemuDomainChardevPrivate *qemuDomainChardevPrivatePtr; +struct _qemuDomainChardevPrivate { + virObject parent; + + /* for char devices using secret + * NB: *not* to be written to qemu domain object XML */ + qemuDomainSecretInfoPtr secinfo; +}; + + typedef enum { QEMU_PROCESS_EVENT_WATCHDOG = 0, QEMU_PROCESS_EVENT_GUESTPANIC, diff --git a/src/qemu/qemu_parse_command.c b/src/qemu/qemu_parse_command.c index 279f3da..331ab36 100644 --- a/src/qemu/qemu_parse_command.c +++ b/src/qemu/qemu_parse_command.c @@ -2189,7 +2189,7 @@ qemuParseCommandLine(virCapsPtr caps, if (STRNEQ(val, "none")) { virDomainChrDefPtr chr; - if (!(chr = virDomainChrDefNew())) + if (!(chr = virDomainChrDefNew(NULL))) goto error; if (qemuParseCommandLineChr(&chr->source, val) < 0) { @@ -2208,7 +2208,7 @@ qemuParseCommandLine(virCapsPtr caps, if (STRNEQ(val, "none")) { virDomainChrDefPtr chr; - if (!(chr = virDomainChrDefNew())) + if (!(chr = virDomainChrDefNew(NULL))) goto error; if (qemuParseCommandLineChr(&chr->source, val) < 0) { diff --git a/src/vz/vz_sdk.c b/src/vz/vz_sdk.c index f2a5c96..b5b0197 100644 --- a/src/vz/vz_sdk.c +++ b/src/vz/vz_sdk.c @@ -1214,7 +1214,7 @@ prlsdkAddSerialInfo(PRL_HANDLE sdkdom, ret = PrlVmCfg_GetSerialPort(sdkdom, i, &serialPort); prlsdkCheckRetGoto(ret, cleanup); - if (!(chr = virDomainChrDefNew())) + if (!(chr = virDomainChrDefNew(NULL))) goto cleanup; if (prlsdkGetSerialInfo(serialPort, chr)) diff --git a/src/xenconfig/xen_sxpr.c b/src/xenconfig/xen_sxpr.c index 0b04fc8..990c4ef 100644 --- a/src/xenconfig/xen_sxpr.c +++ b/src/xenconfig/xen_sxpr.c @@ -190,7 +190,7 @@ xenParseSxprChar(const char *value, char *tmp; virDomainChrDefPtr def; - if (!(def = virDomainChrDefNew())) + if (!(def = virDomainChrDefNew(NULL))) return NULL; prefix = value; diff --git a/src/xenconfig/xen_xl.c b/src/xenconfig/xen_xl.c index a06983e..4316c25 100644 --- a/src/xenconfig/xen_xl.c +++ b/src/xenconfig/xen_xl.c @@ -737,7 +737,7 @@ xenParseXLChannel(virConfPtr conf, virDomainDefPtr def) key = nextkey; } - if (!(channel = virDomainChrDefNew())) + if (!(channel = virDomainChrDefNew(NULL))) goto cleanup; if (STRPREFIX(type, "socket")) { -- 2.7.4

Add the secret object prior to the chardev tcp so the 'passwordid=' can be added if the domain XML has a <secret> for the chardev TLS. Signed-off-by: John Ferlan <jferlan@redhat.com> --- src/qemu/qemu_command.c | 32 ++++++- src/qemu/qemu_command.h | 1 + src/qemu/qemu_domain.c | 99 +++++++++++++++++++++- src/qemu/qemu_domain.h | 16 +++- src/qemu/qemu_hotplug.c | 1 + src/qemu/qemu_process.c | 6 +- ...xml2argv-serial-tcp-tlsx509-secret-chardev.args | 38 +++++++++ ...uxml2argv-serial-tcp-tlsx509-secret-chardev.xml | 50 +++++++++++ tests/qemuxml2argvtest.c | 19 +++++ 9 files changed, 253 insertions(+), 9 deletions(-) create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-tlsx509-secret-chardev.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-tlsx509-secret-chardev.xml diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index b290ade..a6e1762 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -683,6 +683,7 @@ qemuBuildRBDSecinfoURI(virBufferPtr buf, * @tlspath: path to the TLS credentials * @listen: boolen listen for client or server setting * @verifypeer: boolean to enable peer verification (form of authorization) + * @secalias: if one exists, the alias of the security object for passwordid * @qemuCaps: capabilities * @propsret: json properties to return * @@ -694,6 +695,7 @@ int qemuBuildTLSx509BackendProps(const char *tlspath, bool isListen, bool verifypeer, + const char *secalias, virQEMUCapsPtr qemuCaps, virJSONValuePtr *propsret) { @@ -719,6 +721,10 @@ qemuBuildTLSx509BackendProps(const char *tlspath, NULL) < 0) goto cleanup; + if (secalias && + virJSONValueObjectAdd(*propsret, "s:passwordid", secalias, NULL) < 0) + goto cleanup; + ret = 0; cleanup: @@ -733,6 +739,7 @@ qemuBuildTLSx509BackendProps(const char *tlspath, * @tlspath: path to the TLS credentials * @listen: boolen listen for client or server setting * @verifypeer: boolean to enable peer verification (form of authorization) + * @addpasswordid: boolean to handle adding passwordid to object * @inalias: Alias for the parent to generate object alias * @qemuCaps: capabilities * @@ -745,6 +752,7 @@ qemuBuildTLSx509CommandLine(virCommandPtr cmd, const char *tlspath, bool isListen, bool verifypeer, + bool addpasswordid, const char *inalias, virQEMUCapsPtr qemuCaps) { @@ -752,11 +760,16 @@ qemuBuildTLSx509CommandLine(virCommandPtr cmd, char *objalias = NULL; virJSONValuePtr props = NULL; char *tmp = NULL; + char *secalias = NULL; - if (qemuBuildTLSx509BackendProps(tlspath, isListen, verifypeer, - qemuCaps, &props) < 0) + if (addpasswordid && + !(secalias = qemuDomainGetSecretAESAlias(inalias, false))) return -1; + if (qemuBuildTLSx509BackendProps(tlspath, isListen, verifypeer, secalias, + qemuCaps, &props) < 0) + goto cleanup; + if (!(objalias = qemuAliasTLSObjFromChardevAlias(inalias))) goto cleanup; @@ -772,6 +785,7 @@ qemuBuildTLSx509CommandLine(virCommandPtr cmd, virJSONValueFree(props); VIR_FREE(objalias); VIR_FREE(tmp); + VIR_FREE(secalias); return ret; } @@ -5009,6 +5023,7 @@ qemuBuildChrChardevStr(virLogManagerPtr logManager, if (qemuBuildTLSx509CommandLine(cmd, cfg->chardevTLSx509certdir, dev->data.tcp.listen, cfg->chardevTLSx509verify, + cfg->chardevTLSx509haveUUID, alias, qemuCaps) < 0) goto error; @@ -8534,6 +8549,19 @@ qemuBuildSerialCommandLine(virLogManagerPtr logManager, /* Use -chardev with -device if they are available */ if (virQEMUCapsSupportsChardev(def, qemuCaps, serial)) { + qemuDomainChardevPrivatePtr chardevPriv = + QEMU_DOMAIN_CHARDEV_PRIVATE(serial); + qemuDomainSecretInfoPtr secinfo = chardevPriv->secinfo; + + /* Add the secret object first if necessary. The + * secinfo is added only to a TCP serial device during + * qemuDomainSecretChardevPrepare. Subsequent called + * functions can just check the config fields */ + if (cfg->chardevTLS && cfg->chardevTLSx509haveUUID && + serial->source.type == VIR_DOMAIN_CHR_TYPE_TCP && + qemuBuildObjectSecretCommandLine(cmd, secinfo) < 0) + return -1; + if (!(devstr = qemuBuildChrChardevStr(logManager, cmd, cfg, def, &serial->source, serial->info.alias, diff --git a/src/qemu/qemu_command.h b/src/qemu/qemu_command.h index 2f2a6ff..a793fb6 100644 --- a/src/qemu/qemu_command.h +++ b/src/qemu/qemu_command.h @@ -69,6 +69,7 @@ int qemuBuildSecretInfoProps(qemuDomainSecretInfoPtr secinfo, int qemuBuildTLSx509BackendProps(const char *tlspath, bool isListen, bool verifypeer, + const char *secalias, virQEMUCapsPtr qemuCaps, virJSONValuePtr *propsret); diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index ad1e4bc..ad0f9c3 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -1042,7 +1042,8 @@ qemuDomainSecretSetup(virConnectPtr conn, if (virCryptoHaveCipher(VIR_CRYPTO_CIPHER_AES256CBC) && virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_OBJECT_SECRET) && (secretUsageType == VIR_SECRET_USAGE_TYPE_CEPH || - secretUsageType == VIR_SECRET_USAGE_TYPE_VOLUME)) { + secretUsageType == VIR_SECRET_USAGE_TYPE_VOLUME || + secretUsageType == VIR_SECRET_USAGE_TYPE_TLS)) { if (qemuDomainSecretAESSetup(conn, priv, secinfo, srcalias, secretUsageType, username, seclookupdef, isLuks) < 0) @@ -1223,6 +1224,91 @@ qemuDomainSecretHostdevPrepare(virConnectPtr conn, } +/* qemuDomainSecretChardevDestroy: + * @disk: Pointer to a chardev definition + * + * Clear and destroy memory associated with the secret + */ +void +qemuDomainSecretChardevDestroy(virDomainChrDefPtr chardev) +{ + qemuDomainChardevPrivatePtr chardevPriv = + QEMU_DOMAIN_CHARDEV_PRIVATE(chardev); + + if (!chardevPriv || !chardevPriv->secinfo) + return; + + qemuDomainSecretInfoFree(&chardevPriv->secinfo); +} + + +/* qemuDomainSecretChardevPrepare: + * @conn: Pointer to connection + * @driver: Pointer to driver object + * @priv: pointer to domain private object + * @chardev: Pointer to a chardev definition + * + * For a serial TCP character device, generate a qemuDomainSecretInfo to be + * used by the command line code to generate the secret for the tls-creds + * to use. + * + * Returns 0 on success, -1 on failure + */ +int +qemuDomainSecretChardevPrepare(virConnectPtr conn, + virQEMUDriverPtr driver, + qemuDomainObjPrivatePtr priv, + virDomainChrDefPtr chardev) +{ + virQEMUDriverConfigPtr cfg; + virSecretLookupTypeDef seclookupdef = {0}; + qemuDomainSecretInfoPtr secinfo = NULL; + + if (!conn || chardev->deviceType != VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL || + chardev->source.type != VIR_DOMAIN_CHR_TYPE_TCP) + return 0; + + cfg = virQEMUDriverGetConfig(driver); + if (cfg->chardevTLS && cfg->chardevTLSx509haveUUID) { + qemuDomainChardevPrivatePtr chardevPriv = + QEMU_DOMAIN_CHARDEV_PRIVATE(chardev); + + if (virUUIDParse(cfg->chardevTLSx509secretUUID, + seclookupdef.u.uuid) < 0) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("malformed chardev TLS secret uuid in qemu.conf")); + goto error; + } + seclookupdef.type = VIR_SECRET_LOOKUP_TYPE_UUID; + + if (VIR_ALLOC(secinfo) < 0) + goto error; + + if (qemuDomainSecretSetup(conn, priv, secinfo, chardev->info.alias, + VIR_SECRET_USAGE_TYPE_TLS, NULL, + &seclookupdef, false) < 0) + goto error; + + if (secinfo->type == VIR_DOMAIN_SECRET_INFO_TYPE_PLAIN) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("TLS X.509 requires encrypted secrets " + "to be supported")); + goto error; + } + + chardevPriv->secinfo = secinfo; + } + + virObjectUnref(cfg); + return 0; + + error: + virObjectUnref(cfg); + qemuDomainSecretInfoFree(&secinfo); + return -1; +} + + /* qemuDomainSecretDestroy: * @vm: Domain object * @@ -1239,11 +1325,15 @@ qemuDomainSecretDestroy(virDomainObjPtr vm) for (i = 0; i < vm->def->nhostdevs; i++) qemuDomainSecretHostdevDestroy(vm->def->hostdevs[i]); + + for (i = 0; i < vm->def->nserials; i++) + qemuDomainSecretChardevDestroy(vm->def->serials[i]); } /* qemuDomainSecretPrepare: * @conn: Pointer to connection + * @driver: Pointer to driver object * @vm: Domain object * * For any objects that may require an auth/secret setup, create a @@ -1256,6 +1346,7 @@ qemuDomainSecretDestroy(virDomainObjPtr vm) */ int qemuDomainSecretPrepare(virConnectPtr conn, + virQEMUDriverPtr driver, virDomainObjPtr vm) { qemuDomainObjPrivatePtr priv = vm->privateData; @@ -1272,6 +1363,12 @@ qemuDomainSecretPrepare(virConnectPtr conn, return -1; } + for (i = 0; i < vm->def->nserials; i++) { + if (qemuDomainSecretChardevPrepare(conn, driver, priv, + vm->def->serials[i]) < 0) + return -1; + } + return 0; } diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h index 54ec5b8..0c8fcb3 100644 --- a/src/qemu/qemu_domain.h +++ b/src/qemu/qemu_domain.h @@ -726,11 +726,23 @@ int qemuDomainSecretHostdevPrepare(virConnectPtr conn, virDomainHostdevDefPtr hostdev) ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3); +void qemuDomainSecretChardevDestroy(virDomainChrDefPtr chardev) + ATTRIBUTE_NONNULL(1); + +int qemuDomainSecretChardevPrepare(virConnectPtr conn, + virQEMUDriverPtr driver, + qemuDomainObjPrivatePtr priv, + virDomainChrDefPtr chardev) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3) + ATTRIBUTE_NONNULL(4); + void qemuDomainSecretDestroy(virDomainObjPtr vm) ATTRIBUTE_NONNULL(1); -int qemuDomainSecretPrepare(virConnectPtr conn, virDomainObjPtr vm) - ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); +int qemuDomainSecretPrepare(virConnectPtr conn, + virQEMUDriverPtr driver, + virDomainObjPtr vm) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3); int qemuDomainDefValidateDiskLunSource(const virStorageSource *src) ATTRIBUTE_NONNULL(1); diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c index 419296e..8e4057c 100644 --- a/src/qemu/qemu_hotplug.c +++ b/src/qemu/qemu_hotplug.c @@ -1682,6 +1682,7 @@ int qemuDomainAttachChrDevice(virQEMUDriverPtr driver, if (qemuBuildTLSx509BackendProps(cfg->chardevTLSx509certdir, dev->data.tcp.listen, cfg->chardevTLSx509verify, + NULL, priv->qemuCaps, &tlsProps) < 0) goto cleanup; diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index a4bc082..ee33f10 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -5044,7 +5044,6 @@ qemuProcessPrepareDomain(virConnectPtr conn, size_t i; char *nodeset = NULL; qemuDomainObjPrivatePtr priv = vm->privateData; - virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver); virCapsPtr caps; if (!(caps = virQEMUDriverGetCapabilities(driver, false))) @@ -5110,8 +5109,8 @@ qemuProcessPrepareDomain(virConnectPtr conn, if (qemuDomainMasterKeyCreate(vm) < 0) goto cleanup; - VIR_DEBUG("Add secrets to disks and hostdevs"); - if (qemuDomainSecretPrepare(conn, vm) < 0) + VIR_DEBUG("Add secrets to disks, hostdevs, and chardevs"); + if (qemuDomainSecretPrepare(conn, driver, vm) < 0) goto cleanup; for (i = 0; i < vm->def->nchannels; i++) { @@ -5140,7 +5139,6 @@ qemuProcessPrepareDomain(virConnectPtr conn, cleanup: VIR_FREE(nodeset); virObjectUnref(caps); - virObjectUnref(cfg); return ret; } diff --git a/tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-tlsx509-secret-chardev.args b/tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-tlsx509-secret-chardev.args new file mode 100644 index 0000000..5859c74 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-tlsx509-secret-chardev.args @@ -0,0 +1,38 @@ +LC_ALL=C \ +PATH=/bin \ +HOME=/home/test \ +USER=test \ +LOGNAME=test \ +QEMU_AUDIO_DRV=none \ +/usr/bin/qemu \ +-name QEMUGuest1 \ +-S \ +-object secret,id=masterKey0,format=raw,\ +file=/tmp/lib/domain--1-QEMUGuest1/master-key.aes \ +-M pc \ +-m 214 \ +-smp 1,sockets=1,cores=1,threads=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 secret,id=serial1-secret0,\ +data=9eao5F8qtkGt+seB1HYivWIxbtwUu6MQtg1zpj/oDtUsPr1q8wBYM91uEHCn6j/1,\ +keyid=masterKey0,iv=AAECAwQFBgcICQoLDA0ODw==,format=base64 \ +-object tls-creds-x509,id=objserial1_tls0,dir=/etc/pki/libvirt-chardev,\ +endpoint=client,verify-peer=yes,passwordid=serial1-secret0 \ +-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/qemuxml2argvdata/qemuxml2argv-serial-tcp-tlsx509-secret-chardev.xml b/tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-tlsx509-secret-chardev.xml new file mode 100644 index 0000000..23c244b --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-serial-tcp-tlsx509-secret-chardev.xml @@ -0,0 +1,50 @@ +<domain type='qemu'> + <name>QEMUGuest1</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory unit='KiB'>219136</memory> + <currentMemory unit='KiB'>219136</currentMemory> + <vcpu placement='static'>1</vcpu> + <os> + <type arch='i686' machine='pc'>hvm</type> + <boot dev='hd'/> + </os> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <emulator>/usr/bin/qemu</emulator> + <disk type='block' device='disk'> + <source dev='/dev/HostVG/QEMUGuest1'/> + <target dev='hda' bus='ide'/> + <address type='drive' controller='0' bus='0' target='0' unit='0'/> + </disk> + <controller type='usb' index='0'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x2'/> + </controller> + <controller type='ide' index='0'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/> + </controller> + <controller type='pci' index='0' model='pci-root'/> + <serial type='udp'> + <source mode='bind' host='127.0.0.1' service='1111'/> + <source mode='connect' host='127.0.0.1' service='2222'/> + <target port='0'/> + </serial> + <serial type='tcp'> + <source mode='connect' host='127.0.0.1' service='5555' tls='yes'/> + <protocol type='raw'/> + <target port='0'/> + </serial> + <console type='udp'> + <source mode='bind' host='127.0.0.1' service='1111'/> + <source mode='connect' host='127.0.0.1' service='2222'/> + <target type='serial' port='0'/> + </console> + <input type='mouse' bus='ps2'/> + <input type='keyboard' bus='ps2'/> + <memballoon model='virtio'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/> + </memballoon> + </devices> +</domain> diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index 41adff4..6e538eb 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -1153,6 +1153,25 @@ mymain(void) DO_TEST("serial-tcp-tlsx509-chardev-tls", QEMU_CAPS_CHARDEV, QEMU_CAPS_NODEFCONFIG, QEMU_CAPS_OBJECT_TLS_CREDS_X509); + VIR_FREE(driver.config->chardevTLSx509certdir); + if (VIR_STRDUP_QUIET(driver.config->chardevTLSx509certdir, "/etc/pki/libvirt-chardev") < 0) + return EXIT_FAILURE; + driver.config->chardevTLSx509verify = 1; + if (VIR_STRDUP_QUIET(driver.config->chardevTLSx509secretUUID, + "6fd3f62d-9fe7-4a4e-a869-7acd6376d8ea") < 0) + return EXIT_FAILURE; + driver.config->chardevTLSx509haveUUID = true; +# ifdef HAVE_GNUTLS_CIPHER_ENCRYPT + DO_TEST("serial-tcp-tlsx509-secret-chardev", + QEMU_CAPS_CHARDEV, QEMU_CAPS_NODEFCONFIG, + QEMU_CAPS_OBJECT_SECRET, + QEMU_CAPS_OBJECT_TLS_CREDS_X509); +# else + DO_TEST_FAILURE("serial-tcp-tlsx509-secret-chardev", + QEMU_CAPS_CHARDEV, QEMU_CAPS_NODEFCONFIG, + QEMU_CAPS_OBJECT_SECRET, + QEMU_CAPS_OBJECT_TLS_CREDS_X509); +# endif driver.config->chardevTLS = 0; VIR_FREE(driver.config->chardevTLSx509certdir); DO_TEST("serial-many-chardev", -- 2.7.4

https://bugzilla.redhat.com/show_bug.cgi?id=1300776 Complete the implementation of support for TLS encryption on chardev TCP transports by adding the hotplug ability of a secret to generate the passwordid for the TLS object Likewise, add the ability to hot unplug that secret object as well Signed-off-by: John Ferlan <jferlan@redhat.com> --- src/qemu/qemu_driver.c | 2 +- src/qemu/qemu_hotplug.c | 62 +++++++++++++++++++++++++++++++++++++++++++++---- src/qemu/qemu_hotplug.h | 3 ++- tests/qemuhotplugtest.c | 2 +- 4 files changed, 61 insertions(+), 8 deletions(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 29a7e3f..aa2a974 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -7569,7 +7569,7 @@ qemuDomainAttachDeviceLive(virDomainObjPtr vm, break; case VIR_DOMAIN_DEVICE_CHR: - ret = qemuDomainAttachChrDevice(driver, vm, + ret = qemuDomainAttachChrDevice(conn, driver, vm, dev->data.chr); if (!ret) { alias = dev->data.chr->info.alias; diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c index 8e4057c..31a822d 100644 --- a/src/qemu/qemu_hotplug.c +++ b/src/qemu/qemu_hotplug.c @@ -1638,7 +1638,8 @@ qemuDomainAttachChrDeviceAssignAddr(virDomainDefPtr def, return ret; } -int qemuDomainAttachChrDevice(virQEMUDriverPtr driver, +int qemuDomainAttachChrDevice(virConnectPtr conn, + virQEMUDriverPtr driver, virDomainObjPtr vm, virDomainChrDefPtr chr) { @@ -1652,8 +1653,11 @@ int qemuDomainAttachChrDevice(virQEMUDriverPtr driver, char *charAlias = NULL; bool chardevAttached = false; bool tlsobjAdded = false; + bool secobjAdded = false; virJSONValuePtr tlsProps = NULL; char *tlsAlias = NULL; + virJSONValuePtr secProps = NULL; + char *secAlias = NULL; bool need_release = false; if (chr->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_CHANNEL && @@ -1677,12 +1681,30 @@ int qemuDomainAttachChrDevice(virQEMUDriverPtr driver, if (qemuDomainChrPreInsert(vmdef, chr) < 0) goto cleanup; + if (qemuDomainSecretChardevPrepare(conn, driver, priv, chr) < 0) + goto cleanup; + if (cfg->chardevTLS && dev->data.tcp.haveTLS == VIR_TRISTATE_BOOL_YES) { + qemuDomainChardevPrivatePtr chardevPriv = + QEMU_DOMAIN_CHARDEV_PRIVATE(chr); + qemuDomainSecretInfoPtr secinfo = chardevPriv->secinfo; + + /* Add a secret object in order to access the TLS environment. + * The secinfo will only be created for serial TCP device. */ + if (secinfo) { + if (qemuBuildSecretInfoProps(secinfo, &secProps) < 0) + goto cleanup; + + if (!(secAlias = qemuDomainGetSecretAESAlias(chr->info.alias, + false))) + goto cleanup; + } + if (qemuBuildTLSx509BackendProps(cfg->chardevTLSx509certdir, dev->data.tcp.listen, cfg->chardevTLSx509verify, - NULL, + secAlias, priv->qemuCaps, &tlsProps) < 0) goto cleanup; @@ -1693,6 +1715,15 @@ int qemuDomainAttachChrDevice(virQEMUDriverPtr driver, } qemuDomainObjEnterMonitor(driver, vm); + if (secAlias) { + rc = qemuMonitorAddObject(priv->mon, "secret", + secAlias, secProps); + secProps = NULL; + if (rc < 0) + goto exit_monitor; + secobjAdded = true; + } + if (tlsAlias) { rc = qemuMonitorAddObject(priv->mon, "tls-creds-x509", tlsAlias, tlsProps); @@ -1723,6 +1754,8 @@ int qemuDomainAttachChrDevice(virQEMUDriverPtr driver, qemuDomainReleaseDeviceAddress(vm, &chr->info, NULL); VIR_FREE(tlsAlias); virJSONValueFree(tlsProps); + VIR_FREE(secAlias); + virJSONValueFree(secProps); VIR_FREE(charAlias); VIR_FREE(devstr); virObjectUnref(cfg); @@ -1730,6 +1763,8 @@ int qemuDomainAttachChrDevice(virQEMUDriverPtr driver, exit_monitor: orig_err = virSaveLastError(); + if (secobjAdded) + ignore_value(qemuMonitorDelObject(priv->mon, secAlias)); if (tlsobjAdded) ignore_value(qemuMonitorDelObject(priv->mon, tlsAlias)); /* detach associated chardev on error */ @@ -4319,6 +4354,7 @@ int qemuDomainDetachChrDevice(virQEMUDriverPtr driver, virDomainDefPtr vmdef = vm->def; virDomainChrDefPtr tmpChr; char *objAlias = NULL; + char *secAlias = NULL; char *devstr = NULL; if (!(tmpChr = virDomainChrFind(vmdef, chr))) { @@ -4332,9 +4368,21 @@ int qemuDomainDetachChrDevice(virQEMUDriverPtr driver, sa_assert(tmpChr->info.alias); - if (cfg->chardevTLS && - !(objAlias = qemuAliasTLSObjFromChardevAlias(tmpChr->info.alias))) - goto cleanup; + if (cfg->chardevTLS) { + if (!(objAlias = qemuAliasTLSObjFromChardevAlias(tmpChr->info.alias))) + goto cleanup; + + /* Best shot at this as the secinfo is destroyed after process launch + * and this path does not recreate it. Thus, if the config has the + * secret UUID and we have a serial TCP chardev, then formulate a + * secAlias which we'll attempt to destroy. */ + if (cfg->chardevTLSx509haveUUID && + tmpChr->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL && + tmpChr->source.type == VIR_DOMAIN_CHR_TYPE_TCP && + !(secAlias = qemuDomainGetSecretAESAlias(tmpChr->info.alias, + false))) + goto cleanup; + } if (qemuBuildChrDeviceStr(&devstr, vmdef, chr, priv->qemuCaps) < 0) goto cleanup; @@ -4348,6 +4396,10 @@ int qemuDomainDetachChrDevice(virQEMUDriverPtr driver, if (objAlias && qemuMonitorDelObject(priv->mon, objAlias) < 0) goto exit_monitor; + /* If it fails, then so be it - it was a best shot */ + if (secAlias) + ignore_value(qemuMonitorDelObject(priv->mon, secAlias)); + if (qemuDomainObjExitMonitor(driver, vm) < 0) goto cleanup; diff --git a/src/qemu/qemu_hotplug.h b/src/qemu/qemu_hotplug.h index b048cf4..8f23176 100644 --- a/src/qemu/qemu_hotplug.h +++ b/src/qemu/qemu_hotplug.h @@ -92,7 +92,8 @@ int qemuDomainAttachLease(virQEMUDriverPtr driver, int qemuDomainDetachLease(virQEMUDriverPtr driver, virDomainObjPtr vm, virDomainLeaseDefPtr lease); -int qemuDomainAttachChrDevice(virQEMUDriverPtr driver, +int qemuDomainAttachChrDevice(virConnectPtr conn, + virQEMUDriverPtr driver, virDomainObjPtr vm, virDomainChrDefPtr chr); int qemuDomainDetachChrDevice(virQEMUDriverPtr driver, diff --git a/tests/qemuhotplugtest.c b/tests/qemuhotplugtest.c index 43eb1cf..14561a8 100644 --- a/tests/qemuhotplugtest.c +++ b/tests/qemuhotplugtest.c @@ -118,7 +118,7 @@ testQemuHotplugAttach(virDomainObjPtr vm, ret = qemuDomainAttachDeviceDiskLive(NULL, &driver, vm, dev); break; case VIR_DOMAIN_DEVICE_CHR: - ret = qemuDomainAttachChrDevice(&driver, vm, dev->data.chr); + ret = qemuDomainAttachChrDevice(NULL, &driver, vm, dev->data.chr); break; default: VIR_TEST_VERBOSE("device type '%s' cannot be attached\n", -- 2.7.4
participants (2)
-
John Ferlan
-
Pavel Hrdina