diff options
-rw-r--r-- | accel/tcg/tcg-runtime-gvec.c | 2 | ||||
-rw-r--r-- | contrib/libvhost-user/libvhost-user.h | 1 | ||||
-rw-r--r-- | docs/interop/vhost-user.txt | 21 | ||||
-rw-r--r-- | gdbstub.c | 3 | ||||
-rw-r--r-- | hw/block/vhost-user-blk.c | 4 | ||||
-rw-r--r-- | hw/vfio/common.c | 11 | ||||
-rw-r--r-- | hw/vfio/trace-events | 1 | ||||
-rw-r--r-- | hw/virtio/vhost-user.c | 22 | ||||
-rw-r--r-- | hw/virtio/vhost.c | 14 | ||||
-rw-r--r-- | include/ui/console.h | 2 | ||||
-rwxr-xr-x | pc-bios/hppa-firmware.img | bin | 215696 -> 215936 bytes | |||
-rw-r--r-- | qemu-doc.texi | 364 | ||||
-rw-r--r-- | qemu-options.hx | 11 | ||||
m--------- | roms/seabios-hppa | 0 | ||||
-rwxr-xr-x | tests/docker/common.rc | 4 | ||||
-rw-r--r-- | tests/docker/dockerfiles/fedora.docker | 13 | ||||
-rwxr-xr-x | tests/docker/run | 2 | ||||
-rw-r--r-- | tests/test-crypto-tlssession.c | 1 | ||||
-rw-r--r-- | tests/test-io-channel-tls.c | 1 | ||||
-rwxr-xr-x | tests/vm/basevm.py | 5 | ||||
-rw-r--r-- | ui/console.c | 15 | ||||
-rw-r--r-- | ui/gtk.c | 4 | ||||
-rw-r--r-- | ui/sdl2-gl.c | 2 | ||||
-rw-r--r-- | ui/sdl2-input.c | 46 |
24 files changed, 390 insertions, 159 deletions
diff --git a/accel/tcg/tcg-runtime-gvec.c b/accel/tcg/tcg-runtime-gvec.c index 8bf8d63912..90340e56e0 100644 --- a/accel/tcg/tcg-runtime-gvec.c +++ b/accel/tcg/tcg-runtime-gvec.c @@ -705,7 +705,7 @@ void HELPER(NAME)(void *d, void *a, void *b, uint32_t desc) \ { \ intptr_t oprsz = simd_oprsz(desc); \ intptr_t i; \ - for (i = 0; i < oprsz; i += sizeof(vec64)) { \ + for (i = 0; i < oprsz; i += sizeof(TYPE)) { \ *(TYPE *)(d + i) = DO_CMP0(*(TYPE *)(a + i) OP *(TYPE *)(b + i)); \ } \ clear_high(d, oprsz, desc); \ diff --git a/contrib/libvhost-user/libvhost-user.h b/contrib/libvhost-user/libvhost-user.h index 79f7a53ee8..b27075ea3b 100644 --- a/contrib/libvhost-user/libvhost-user.h +++ b/contrib/libvhost-user/libvhost-user.h @@ -50,6 +50,7 @@ enum VhostUserProtocolFeature { VHOST_USER_PROTOCOL_F_CROSS_ENDIAN = 6, VHOST_USER_PROTOCOL_F_CRYPTO_SESSION = 7, VHOST_USER_PROTOCOL_F_PAGEFAULT = 8, + VHOST_USER_PROTOCOL_F_CONFIG = 9, VHOST_USER_PROTOCOL_F_MAX }; diff --git a/docs/interop/vhost-user.txt b/docs/interop/vhost-user.txt index c058c407df..534caab18a 100644 --- a/docs/interop/vhost-user.txt +++ b/docs/interop/vhost-user.txt @@ -379,6 +379,7 @@ Protocol features #define VHOST_USER_PROTOCOL_F_CROSS_ENDIAN 6 #define VHOST_USER_PROTOCOL_F_CRYPTO_SESSION 7 #define VHOST_USER_PROTOCOL_F_PAGEFAULT 8 +#define VHOST_USER_PROTOCOL_F_CONFIG 9 Master message types -------------------- @@ -664,7 +665,8 @@ Master message types Master payload: virtio device config space Slave payload: virtio device config space - Submitted by the vhost-user master to fetch the contents of the virtio + When VHOST_USER_PROTOCOL_F_CONFIG is negotiated, this message is + submitted by the vhost-user master to fetch the contents of the virtio device configuration space, vhost-user slave's payload size MUST match master's request, vhost-user slave uses zero length of payload to indicate an error to vhost-user master. The vhost-user master may @@ -677,7 +679,8 @@ Master message types Master payload: virtio device config space Slave payload: N/A - Submitted by the vhost-user master when the Guest changes the virtio + When VHOST_USER_PROTOCOL_F_CONFIG is negotiated, this message is + submitted by the vhost-user master when the Guest changes the virtio device configuration space and also can be used for live migration on the destination host. The vhost-user slave must check the flags field, and slaves MUST NOT accept SET_CONFIG for read-only @@ -766,13 +769,13 @@ Slave message types Slave payload: N/A Master payload: N/A - Vhost-user slave sends such messages to notify that the virtio device's - configuration space has changed, for those host devices which can support - such feature, host driver can send VHOST_USER_GET_CONFIG message to slave - to get the latest content. If VHOST_USER_PROTOCOL_F_REPLY_ACK is - negotiated, and slave set the VHOST_USER_NEED_REPLY flag, master must - respond with zero when operation is successfully completed, or non-zero - otherwise. + When VHOST_USER_PROTOCOL_F_CONFIG is negotiated, vhost-user slave sends + such messages to notify that the virtio device's configuration space has + changed, for those host devices which can support such feature, host + driver can send VHOST_USER_GET_CONFIG message to slave to get the latest + content. If VHOST_USER_PROTOCOL_F_REPLY_ACK is negotiated, and slave set + the VHOST_USER_NEED_REPLY flag, master must respond with zero when + operation is successfully completed, or non-zero otherwise. VHOST_USER_PROTOCOL_F_REPLY_ACK: ------------------------------- @@ -507,6 +507,7 @@ static inline int tohex(int v) return v - 10 + 'a'; } +/* writes 2*len+1 bytes in buf */ static void memtohex(char *buf, const uint8_t *mem, int len) { int i, c; @@ -999,8 +1000,8 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf) const char *p; uint32_t thread; int ch, reg_size, type, res; - char buf[MAX_PACKET_LENGTH]; uint8_t mem_buf[MAX_PACKET_LENGTH]; + char buf[sizeof(mem_buf) + 1 /* trailing NUL */]; uint8_t *registers; target_ulong addr, len; diff --git a/hw/block/vhost-user-blk.c b/hw/block/vhost-user-blk.c index f840f07dfe..262baca432 100644 --- a/hw/block/vhost-user-blk.c +++ b/hw/block/vhost-user-blk.c @@ -259,6 +259,8 @@ static void vhost_user_blk_device_realize(DeviceState *dev, Error **errp) s->dev.vq_index = 0; s->dev.backend_features = 0; + vhost_dev_set_config_notifier(&s->dev, &blk_ops); + ret = vhost_dev_init(&s->dev, &s->chardev, VHOST_BACKEND_TYPE_USER, 0); if (ret < 0) { error_setg(errp, "vhost-user-blk: vhost initialization failed: %s", @@ -277,8 +279,6 @@ static void vhost_user_blk_device_realize(DeviceState *dev, Error **errp) s->blkcfg.num_queues = s->num_queues; } - vhost_dev_set_config_notifier(&s->dev, &blk_ops); - return; vhost_err: diff --git a/hw/vfio/common.c b/hw/vfio/common.c index 5e84716218..07ffa0ba10 100644 --- a/hw/vfio/common.c +++ b/hw/vfio/common.c @@ -548,12 +548,11 @@ static void vfio_listener_region_add(MemoryListener *listener, hwaddr pgmask = (1ULL << ctz64(hostwin->iova_pgsizes)) - 1; if ((iova & pgmask) || (int128_get64(llsize) & pgmask)) { - error_report("Region 0x%"HWADDR_PRIx"..0x%"HWADDR_PRIx - " is not aligned to 0x%"HWADDR_PRIx - " and cannot be mapped for DMA", - section->offset_within_region, - int128_getlo(section->size), - pgmask + 1); + trace_vfio_listener_region_add_no_dma_map( + memory_region_name(section->mr), + section->offset_within_address_space, + int128_getlo(section->size), + pgmask + 1); return; } } diff --git a/hw/vfio/trace-events b/hw/vfio/trace-events index 79f63a2ff6..20109cb758 100644 --- a/hw/vfio/trace-events +++ b/hw/vfio/trace-events @@ -90,6 +90,7 @@ vfio_iommu_map_notify(const char *op, uint64_t iova_start, uint64_t iova_end) "i vfio_listener_region_add_skip(uint64_t start, uint64_t end) "SKIPPING region_add 0x%"PRIx64" - 0x%"PRIx64 vfio_listener_region_add_iommu(uint64_t start, uint64_t end) "region_add [iommu] 0x%"PRIx64" - 0x%"PRIx64 vfio_listener_region_add_ram(uint64_t iova_start, uint64_t iova_end, void *vaddr) "region_add [ram] 0x%"PRIx64" - 0x%"PRIx64" [%p]" +vfio_listener_region_add_no_dma_map(const char *name, uint64_t iova, uint64_t size, uint64_t page_size) "Region \"%s\" 0x%"PRIx64" size=0x%"PRIx64" is not aligned to 0x%"PRIx64" and cannot be mapped for DMA" vfio_listener_region_del_skip(uint64_t start, uint64_t end) "SKIPPING region_del 0x%"PRIx64" - 0x%"PRIx64 vfio_listener_region_del(uint64_t start, uint64_t end) "region_del 0x%"PRIx64" - 0x%"PRIx64 vfio_disconnect_container(int fd) "close container->fd=%d" diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c index 44aea5c0a8..38da8692bb 100644 --- a/hw/virtio/vhost-user.c +++ b/hw/virtio/vhost-user.c @@ -46,6 +46,7 @@ enum VhostUserProtocolFeature { VHOST_USER_PROTOCOL_F_CROSS_ENDIAN = 6, VHOST_USER_PROTOCOL_F_CRYPTO_SESSION = 7, VHOST_USER_PROTOCOL_F_PAGEFAULT = 8, + VHOST_USER_PROTOCOL_F_CONFIG = 9, VHOST_USER_PROTOCOL_F_MAX }; @@ -1211,6 +1212,17 @@ static int vhost_user_init(struct vhost_dev *dev, void *opaque) dev->protocol_features = protocol_features & VHOST_USER_PROTOCOL_FEATURE_MASK; + + if (!dev->config_ops || !dev->config_ops->vhost_dev_config_notifier) { + /* Don't acknowledge CONFIG feature if device doesn't support it */ + dev->protocol_features &= ~(1ULL << VHOST_USER_PROTOCOL_F_CONFIG); + } else if (!(protocol_features & + (1ULL << VHOST_USER_PROTOCOL_F_CONFIG))) { + error_report("Device expects VHOST_USER_PROTOCOL_F_CONFIG " + "but backend does not support it."); + return -1; + } + err = vhost_user_set_protocol_features(dev, dev->protocol_features); if (err < 0) { return err; @@ -1405,6 +1417,11 @@ static int vhost_user_get_config(struct vhost_dev *dev, uint8_t *config, .hdr.size = VHOST_USER_CONFIG_HDR_SIZE + config_len, }; + if (!virtio_has_feature(dev->protocol_features, + VHOST_USER_PROTOCOL_F_CONFIG)) { + return -1; + } + if (config_len > VHOST_USER_MAX_CONFIG_SIZE) { return -1; } @@ -1448,6 +1465,11 @@ static int vhost_user_set_config(struct vhost_dev *dev, const uint8_t *data, .hdr.size = VHOST_USER_CONFIG_HDR_SIZE + size, }; + if (!virtio_has_feature(dev->protocol_features, + VHOST_USER_PROTOCOL_F_CONFIG)) { + return -1; + } + if (reply_supported) { msg.hdr.flags |= VHOST_USER_NEED_REPLY_MASK; } diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c index 27c1ec5fe8..f51bf573d5 100644 --- a/hw/virtio/vhost.c +++ b/hw/virtio/vhost.c @@ -595,10 +595,15 @@ static void vhost_region_add_section(struct vhost_dev *dev, prev_sec->offset_within_address_space, prev_sec->offset_within_region); } else { - error_report("%s: Overlapping but not coherent sections " - "at %"PRIx64, - __func__, mrs_gpa); - return; + /* adjoining regions are fine, but overlapping ones with + * different blocks/offsets shouldn't happen + */ + if (mrs_gpa != prev_gpa_end + 1) { + error_report("%s: Overlapping but not coherent sections " + "at %"PRIx64, + __func__, mrs_gpa); + return; + } } } } @@ -1451,7 +1456,6 @@ int vhost_dev_set_config(struct vhost_dev *hdev, const uint8_t *data, void vhost_dev_set_config_notifier(struct vhost_dev *hdev, const VhostDevConfigOps *ops) { - assert(hdev->vhost_ops); hdev->config_ops = ops; } diff --git a/include/ui/console.h b/include/ui/console.h index 6d2c052068..37a8d68d29 100644 --- a/include/ui/console.h +++ b/include/ui/console.h @@ -99,7 +99,7 @@ void hmp_mouse_set(Monitor *mon, const QDict *qdict); #define QEMU_KEY_CTRL_PAGEDOWN 0xe407 void kbd_put_keysym_console(QemuConsole *s, int keysym); -bool kbd_put_qcode_console(QemuConsole *s, int qcode); +bool kbd_put_qcode_console(QemuConsole *s, int qcode, bool ctrl); void kbd_put_string_console(QemuConsole *s, const char *str, int len); void kbd_put_keysym(int keysym); diff --git a/pc-bios/hppa-firmware.img b/pc-bios/hppa-firmware.img Binary files differindex d2098f1fd9..4ec0dbfc4a 100755 --- a/pc-bios/hppa-firmware.img +++ b/pc-bios/hppa-firmware.img diff --git a/qemu-doc.texi b/qemu-doc.texi index 89fa80518a..5813d27615 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -140,6 +140,7 @@ accelerator is required to use more than one host CPU for emulation. * direct_linux_boot:: Direct Linux Boot * pcsys_usb:: USB emulation * vnc_security:: VNC security +* network_tls:: TLS setup for network services * gdb_usage:: GDB usage * pcsys_os_specific:: Target OS specific information @end menu @@ -1041,7 +1042,6 @@ considerations depending on the deployment scenarios. * vnc_sec_certificate_pw:: * vnc_sec_sasl:: * vnc_sec_certificate_sasl:: -* vnc_generate_cert:: * vnc_setup_sasl:: @end menu @node vnc_sec_none @@ -1161,25 +1161,105 @@ with the aforementioned TLS + x509 options: qemu-system-i386 [...OPTIONS...] -vnc :1,tls,x509,sasl -monitor stdio @end example +@node vnc_setup_sasl -@node vnc_generate_cert -@subsection Generating certificates for VNC +@subsection Configuring SASL mechanisms -The GNU TLS packages provides a command called @code{certtool} which can -be used to generate certificates and keys in PEM format. At a minimum it -is necessary to setup a certificate authority, and issue certificates to -each server. If using certificates for authentication, then each client -will also need to be issued a certificate. The recommendation is for the -server to keep its certificates in either @code{/etc/pki/qemu} or for -unprivileged users in @code{$HOME/.pki/qemu}. +The following documentation assumes use of the Cyrus SASL implementation on a +Linux host, but the principles should apply to any other SASL implementation +or host. When SASL is enabled, the mechanism configuration will be loaded from +system default SASL service config /etc/sasl2/qemu.conf. If running QEMU as an +unprivileged user, an environment variable SASL_CONF_PATH can be used to make +it search alternate locations for the service config file. + +If the TLS option is enabled for VNC, then it will provide session encryption, +otherwise the SASL mechanism will have to provide encryption. In the latter +case the list of possible plugins that can be used is drastically reduced. In +fact only the GSSAPI SASL mechanism provides an acceptable level of security +by modern standards. Previous versions of QEMU referred to the DIGEST-MD5 +mechanism, however, it has multiple serious flaws described in detail in +RFC 6331 and thus should never be used any more. The SCRAM-SHA-1 mechanism +provides a simple username/password auth facility similar to DIGEST-MD5, but +does not support session encryption, so can only be used in combination with +TLS. + +When not using TLS the recommended configuration is + +@example +mech_list: gssapi +keytab: /etc/qemu/krb5.tab +@end example + +This says to use the 'GSSAPI' mechanism with the Kerberos v5 protocol, with +the server principal stored in /etc/qemu/krb5.tab. For this to work the +administrator of your KDC must generate a Kerberos principal for the server, +with a name of 'qemu/somehost.example.com@@EXAMPLE.COM' replacing +'somehost.example.com' with the fully qualified host name of the machine +running QEMU, and 'EXAMPLE.COM' with the Kerberos Realm. + +When using TLS, if username+password authentication is desired, then a +reasonable configuration is + +@example +mech_list: scram-sha-1 +sasldb_path: /etc/qemu/passwd.db +@end example + +The @code{saslpasswd2} program can be used to populate the @code{passwd.db} +file with accounts. + +Other SASL configurations will be left as an exercise for the reader. Note that +all mechanisms, except GSSAPI, should be combined with use of TLS to ensure a +secure data channel. + + +@node network_tls +@section TLS setup for network services + +Almost all network services in QEMU have the ability to use TLS for +session data encryption, along with x509 certificates for simple +client authentication. What follows is a description of how to +generate certificates suitable for usage with QEMU, and applies to +the VNC server, character devices with the TCP backend, NBD server +and client, and migration server and client. + +At a high level, QEMU requires certificates and private keys to be +provided in PEM format. Aside from the core fields, the certificates +should include various extension data sets, including v3 basic +constraints data, key purpose, key usage and subject alt name. + +The GnuTLS package includes a command called @code{certtool} which can +be used to easily generate certificates and keys in the required format +with expected data present. Alternatively a certificate management +service may be used. + +At a minimum it is necessary to setup a certificate authority, and +issue certificates to each server. If using x509 certificates for +authentication, then each client will also need to be issued a +certificate. + +Assuming that the QEMU network services will only ever be exposed to +clients on a private intranet, there is no need to use a commercial +certificate authority to create certificates. A self-signed CA is +sufficient, and in fact likely to be more secure since it removes +the ability of malicious 3rd parties to trick the CA into mis-issuing +certs for impersonating your services. The only likely exception +where a commercial CA might be desirable is if enabling the VNC +websockets server and exposing it directly to remote browser clients. +In such a case it might be useful to use a commercial CA to avoid +needing to install custom CA certs in the web browsers. + +The recommendation is for the server to keep its certificates in either +@code{/etc/pki/qemu} or for unprivileged users in @code{$HOME/.pki/qemu}. @menu -* vnc_generate_ca:: -* vnc_generate_server:: -* vnc_generate_client:: +* tls_generate_ca:: +* tls_generate_server:: +* tls_generate_client:: +* tls_creds_setup:: @end menu -@node vnc_generate_ca -@subsubsection Setup the Certificate Authority +@node tls_generate_ca +@subsection Setup the Certificate Authority This step only needs to be performed once per organization / organizational unit. First the CA needs a private key. This key must be kept VERY secret @@ -1190,11 +1270,10 @@ issued with it is lost. # certtool --generate-privkey > ca-key.pem @end example -A CA needs to have a public certificate. For simplicity it can be a self-signed -certificate, or one issue by a commercial certificate issuing authority. To -generate a self-signed certificate requires one core piece of information, the -name of the organization. - +To generate a self-signed certificate requires one core piece of information, +the name of the organization. A template file @code{ca.info} should be +populated with the desired data to avoid having to deal with interactive +prompts from certtool: @example # cat > ca.info <<EOF cn = Name of your organization @@ -1207,123 +1286,224 @@ EOF --outfile ca-cert.pem @end example -The @code{ca-cert.pem} file should be copied to all servers and clients wishing to utilize -TLS support in the VNC server. The @code{ca-key.pem} must not be disclosed/copied at all. +The @code{ca} keyword in the template sets the v3 basic constraints extension +to indicate this certificate is for a CA, while @code{cert_signing_key} sets +the key usage extension to indicate this will be used for signing other keys. +The generated @code{ca-cert.pem} file should be copied to all servers and +clients wishing to utilize TLS support in the VNC server. The @code{ca-key.pem} +must not be disclosed/copied anywhere except the host responsible for issuing +certificates. -@node vnc_generate_server -@subsubsection Issuing server certificates +@node tls_generate_server +@subsection Issuing server certificates Each server (or host) needs to be issued with a key and certificate. When connecting the certificate is sent to the client which validates it against the CA certificate. -The core piece of information for a server certificate is the hostname. This should -be the fully qualified hostname that the client will connect with, since the client -will typically also verify the hostname in the certificate. On the host holding the -secure CA private key: - -@example -# cat > server.info <<EOF +The core pieces of information for a server certificate are the hostnames and/or IP +addresses that will be used by clients when connecting. The hostname / IP address +that the client specifies when connecting will be validated against the hostname(s) +and IP address(es) recorded in the server certificate, and if no match is found +the client will close the connection. + +Thus it is recommended that the server certificate include both the fully qualified +and unqualified hostnames. If the server will have permanently assigned IP address(es), +and clients are likely to use them when connecting, they may also be included in the +certificate. Both IPv4 and IPv6 addresses are supported. Historically certificates +only included 1 hostname in the @code{CN} field, however, usage of this field for +validation is now deprecated. Instead modern TLS clients will validate against the +Subject Alt Name extension data, which allows for multiple entries. In the future +usage of the @code{CN} field may be discontinued entirely, so providing SAN +extension data is strongly recommended. + +On the host holding the CA, create template files containing the information +for each server, and use it to issue server certificates. + +@example +# cat > server-hostNNN.info <<EOF organization = Name of your organization -cn = server.foo.example.com +cn = hostNNN.foo.example.com +dns_name = hostNNN +dns_name = hostNNN.foo.example.com +ip_address = 10.0.1.87 +ip_address = 192.8.0.92 +ip_address = 2620:0:cafe::87 +ip_address = 2001:24::92 tls_www_server encryption_key signing_key EOF -# certtool --generate-privkey > server-key.pem +# certtool --generate-privkey > server-hostNNN-key.pem # certtool --generate-certificate \ --load-ca-certificate ca-cert.pem \ --load-ca-privkey ca-key.pem \ - --load-privkey server-key.pem \ - --template server.info \ - --outfile server-cert.pem + --load-privkey server-hostNNN-key.pem \ + --template server-hostNNN.info \ + --outfile server-hostNNN-cert.pem @end example -The @code{server-key.pem} and @code{server-cert.pem} files should now be securely copied -to the server for which they were generated. The @code{server-key.pem} is security -sensitive and should be kept protected with file mode 0600 to prevent disclosure. +The @code{dns_name} and @code{ip_address} fields in the template are setting +the subject alt name extension data. The @code{tls_www_server} keyword is the +key purpose extension to indicate this certificate is intended for usage in +a web server. Although QEMU network services are not in fact HTTP servers +(except for VNC websockets), setting this key purpose is still recommended. +The @code{encryption_key} and @code{signing_key} keyword is the key usage +extension to indicate this certificate is intended for usage in the data +session. -@node vnc_generate_client -@subsubsection Issuing client certificates +The @code{server-hostNNN-key.pem} and @code{server-hostNNN-cert.pem} files +should now be securely copied to the server for which they were generated, +and renamed to @code{server-key.pem} and @code{server-cert.pem} when added +to the @code{/etc/pki/qemu} directory on the target host. The @code{server-key.pem} +file is security sensitive and should be kept protected with file mode 0600 +to prevent disclosure. + +@node tls_generate_client +@subsection Issuing client certificates + +The QEMU x509 TLS credential setup defaults to enabling client verification +using certificates, providing a simple authentication mechanism. If this +default is used, each client also needs to be issued a certificate. The client +certificate contains enough metadata to uniquely identify the client with the +scope of the certificate authority. The client certificate would typically +include fields for organization, state, city, building, etc. + +Once again on the host holding the CA, create template files containing the +information for each client, and use it to issue client certificates. -If the QEMU VNC server is to use the @code{x509verify} option to validate client -certificates as its authentication mechanism, each client also needs to be issued -a certificate. The client certificate contains enough metadata to uniquely identify -the client, typically organization, state, city, building, etc. On the host holding -the secure CA private key: @example -# cat > client.info <<EOF +# cat > client-hostNNN.info <<EOF country = GB state = London -locality = London +locality = City Of London organization = Name of your organization -cn = client.foo.example.com +cn = hostNNN.foo.example.com tls_www_client encryption_key signing_key EOF -# certtool --generate-privkey > client-key.pem +# certtool --generate-privkey > client-hostNNN-key.pem # certtool --generate-certificate \ --load-ca-certificate ca-cert.pem \ --load-ca-privkey ca-key.pem \ - --load-privkey client-key.pem \ - --template client.info \ - --outfile client-cert.pem + --load-privkey client-hostNNN-key.pem \ + --template client-hostNNN.info \ + --outfile client-hostNNN-cert.pem +@end example + +The subject alt name extension data is not required for clients, so the +the @code{dns_name} and @code{ip_address} fields are not included. +The @code{tls_www_client} keyword is the key purpose extension to indicate +this certificate is intended for usage in a web client. Although QEMU +network clients are not in fact HTTP clients, setting this key purpose is +still recommended. The @code{encryption_key} and @code{signing_key} keyword +is the key usage extension to indicate this certificate is intended for +usage in the data session. + +The @code{client-hostNNN-key.pem} and @code{client-hostNNN-cert.pem} files +should now be securely copied to the client for which they were generated, +and renamed to @code{client-key.pem} and @code{client-cert.pem} when added +to the @code{/etc/pki/qemu} directory on the target host. The @code{client-key.pem} +file is security sensitive and should be kept protected with file mode 0600 +to prevent disclosure. + +If a single host is going to be using TLS in both a client and server +role, it is possible to create a single certificate to cover both roles. +This would be quite common for the migration and NBD services, where a +QEMU process will be started by accepting a TLS protected incoming migration, +and later itself be migrated out to another host. To generate a single +certificate, simply include the template data from both the client and server +instructions in one. + +@example +# cat > both-hostNNN.info <<EOF +country = GB +state = London +locality = City Of London +organization = Name of your organization +cn = hostNNN.foo.example.com +dns_name = hostNNN +dns_name = hostNNN.foo.example.com +ip_address = 10.0.1.87 +ip_address = 192.8.0.92 +ip_address = 2620:0:cafe::87 +ip_address = 2001:24::92 +tls_www_server +tls_www_client +encryption_key +signing_key +EOF +# certtool --generate-privkey > both-hostNNN-key.pem +# certtool --generate-certificate \ + --load-ca-certificate ca-cert.pem \ + --load-ca-privkey ca-key.pem \ + --load-privkey both-hostNNN-key.pem \ + --template both-hostNNN.info \ + --outfile both-hostNNN-cert.pem @end example -The @code{client-key.pem} and @code{client-cert.pem} files should now be securely -copied to the client for which they were generated. +When copying the PEM files to the target host, save them twice, +once as @code{server-cert.pem} and @code{server-key.pem}, and +again as @code{client-cert.pem} and @code{client-key.pem}. +@node tls_creds_setup +@subsection TLS x509 credential configuration -@node vnc_setup_sasl +QEMU has a standard mechanism for loading x509 credentials that will be +used for network services and clients. It requires specifying the +@code{tls-creds-x509} class name to the @code{--object} command line +argument for the system emulators. Each set of credentials loaded should +be given a unique string identifier via the @code{id} parameter. A single +set of TLS credentials can be used for multiple network backends, so VNC, +migration, NBD, character devices can all share the same credentials. Note, +however, that credentials for use in a client endpoint must be loaded +separately from those used in a server endpoint. -@subsection Configuring SASL mechanisms +When specifying the object, the @code{dir} parameters specifies which +directory contains the credential files. This directory is expected to +contain files with the names mentioned previously, @code{ca-cert.pem}, +@code{server-key.pem}, @code{server-cert.pem}, @code{client-key.pem} +and @code{client-cert.pem} as appropriate. It is also possible to +include a set of pre-generated Diffie-Hellman (DH) parameters in a file +@code{dh-params.pem}, which can be created using the +@code{certtool --generate-dh-params} command. If omitted, QEMU will +dynamically generate DH parameters when loading the credentials. -The following documentation assumes use of the Cyrus SASL implementation on a -Linux host, but the principals should apply to any other SASL impl. When SASL -is enabled, the mechanism configuration will be loaded from system default -SASL service config /etc/sasl2/qemu.conf. If running QEMU as an -unprivileged user, an environment variable SASL_CONF_PATH can be used -to make it search alternate locations for the service config. +The @code{endpoint} parameter indicates whether the credentials will +be used for a network client or server, and determines which PEM +files are loaded. -If the TLS option is enabled for VNC, then it will provide session encryption, -otherwise the SASL mechanism will have to provide encryption. In the latter -case the list of possible plugins that can be used is drastically reduced. In -fact only the GSSAPI SASL mechanism provides an acceptable level of security -by modern standards. Previous versions of QEMU referred to the DIGEST-MD5 -mechanism, however, it has multiple serious flaws described in detail in -RFC 6331 and thus should never be used any more. The SCRAM-SHA-1 mechanism -provides a simple username/password auth facility similar to DIGEST-MD5, but -does not support session encryption, so can only be used in combination with -TLS. +The @code{verify} parameter determines whether x509 certificate +validation should be performed. This defaults to enabled, meaning +clients will always validate the server hostname against the +certificate subject alt name fields and/or CN field. It also +means that servers will request that clients provide a certificate +and validate them. Verification should never be turned off for +client endpoints, however, it may be turned off for server endpoints +if an alternative mechanism is used to authenticate clients. For +example, the VNC server can use SASL to authenticate clients +instead. -When not using TLS the recommended configuration is +To load server credentials with client certificate validation +enabled @example -mech_list: gssapi -keytab: /etc/qemu/krb5.tab +$QEMU -object tls-creds-x509,id=tls0,dir=/etc/pki/qemu,endpoint=server @end example -This says to use the 'GSSAPI' mechanism with the Kerberos v5 protocol, with -the server principal stored in /etc/qemu/krb5.tab. For this to work the -administrator of your KDC must generate a Kerberos principal for the server, -with a name of 'qemu/somehost.example.com@@EXAMPLE.COM' replacing -'somehost.example.com' with the fully qualified host name of the machine -running QEMU, and 'EXAMPLE.COM' with the Kerberos Realm. - -When using TLS, if username+password authentication is desired, then a -reasonable configuration is +while to load client credentials use @example -mech_list: scram-sha-1 -sasldb_path: /etc/qemu/passwd.db +$QEMU -object tls-creds-x509,id=tls0,dir=/etc/pki/qemu,endpoint=client @end example -The saslpasswd2 program can be used to populate the passwd.db file with -accounts. +Network services which support TLS will all have a @code{tls-creds} +parameter which expects the ID of the TLS credentials object. For +example with VNC: -Other SASL configurations will be left as an exercise for the reader. Note that -all mechanisms except GSSAPI, should be combined with use of TLS to ensure a -secure data channel. +@example +$QEMU -vnc 0.0.0.0:0,tls-creds=tls0 +@end example @node gdb_usage @section GDB usage diff --git a/qemu-options.hx b/qemu-options.hx index 3ece30d216..ca4e412f2f 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -4112,7 +4112,7 @@ expensive operation that consumes random pool entropy, so it is recommended that a persistent set of parameters be generated upfront and saved. -@item -object tls-creds-x509,id=@var{id},endpoint=@var{endpoint},dir=@var{/path/to/cred/dir},verify-peer=@var{on|off},passwordid=@var{id} +@item -object tls-creds-x509,id=@var{id},endpoint=@var{endpoint},dir=@var{/path/to/cred/dir},priority=@var{priority},verify-peer=@var{on|off},passwordid=@var{id} Creates a TLS anonymous credentials object, which can be used to provide TLS support on network backends. The @option{id} parameter is a unique @@ -4145,6 +4145,15 @@ version by providing the @var{passwordid} parameter. This provides the ID of a previously created @code{secret} object containing the password for decryption. +The @var{priority} parameter allows to override the global default +priority used by gnutls. This can be useful if the system administrator +needs to use a weaker set of crypto priorities for QEMU without +potentially forcing the weakness onto all applications. Or conversely +if one wants wants a stronger default for QEMU than for all other +applications, they can do this through this parameter. Its format is +a gnutls priority string as described at +@url{https://gnutls.org/manual/html_node/Priority-Strings.html}. + @item -object filter-buffer,id=@var{id},netdev=@var{netdevid},interval=@var{t}[,queue=@var{all|rx|tx}][,status=@var{on|off}] Interval @var{t} can't be 0, this filter batches the packet delivery: all diff --git a/roms/seabios-hppa b/roms/seabios-hppa -Subproject 649e6202b8d65d46c69f542b1380f840fbe8ab1 +Subproject 1ef99a01572c2581c30e16e6fe69e9ea2ef92ce diff --git a/tests/docker/common.rc b/tests/docker/common.rc index 7951555e3f..046f8a5921 100755 --- a/tests/docker/common.rc +++ b/tests/docker/common.rc @@ -30,7 +30,9 @@ build_qemu() $@" echo "Configure options:" echo $config_opts - $QEMU_SRC/configure $config_opts && make $MAKEFLAGS + $QEMU_SRC/configure $config_opts || \ + { cat config.log && test_fail "Failed to run 'configure'"; } + make $MAKEFLAGS } test_fail() diff --git a/tests/docker/dockerfiles/fedora.docker b/tests/docker/dockerfiles/fedora.docker index a00004319e..b706f42405 100644 --- a/tests/docker/dockerfiles/fedora.docker +++ b/tests/docker/dockerfiles/fedora.docker @@ -1,9 +1,16 @@ FROM fedora:27 ENV PACKAGES \ ccache gettext git tar PyYAML sparse flex bison python3 bzip2 hostname \ - glib2-devel pixman-devel zlib-devel SDL-devel libfdt-devel \ - gcc gcc-c++ llvm clang make perl which bc findutils libaio-devel \ - nettle-devel libasan libubsan \ + gcc gcc-c++ llvm clang make perl which bc findutils glib2-devel \ + libaio-devel pixman-devel zlib-devel libfdt-devel libasan libubsan \ + bluez-libs-devel brlapi-devel bzip2-devel \ + device-mapper-multipath-devel glusterfs-api-devel gnutls-devel \ + gtk3-devel libattr-devel libcap-devel libcap-ng-devel libcurl-devel \ + libjpeg-devel libpng-devel librbd-devel libssh2-devel libusbx-devel \ + libxml2-devel lzo-devel ncurses-devel nettle-devel nss-devel \ + numactl-devel SDL2-devel snappy-devel spice-server-devel \ + systemtap-sdt-devel usbredir-devel virglrenderer-devel vte3-devel \ + xen-devel \ mingw32-pixman mingw32-glib2 mingw32-gmp mingw32-SDL mingw32-pkg-config \ mingw32-gtk2 mingw32-gtk3 mingw32-gnutls mingw32-nettle mingw32-libtasn1 \ mingw32-libjpeg-turbo mingw32-libpng mingw32-curl mingw32-libssh2 \ diff --git a/tests/docker/run b/tests/docker/run index 9dd362bb98..7aebf4b569 100755 --- a/tests/docker/run +++ b/tests/docker/run @@ -29,7 +29,7 @@ export TEST_DIR=/tmp/qemu-test mkdir -p $TEST_DIR/{src,build,install} # Extract the source tarballs -tar -C $TEST_DIR/src -xf $BASE/qemu.tar || prep_fail "Failed to untar source" +tar -C $TEST_DIR/src -xf $BASE/qemu.tar || { echo "Failed to untar source"; exit 2; } if test -f $TEST_DIR/src/Makefile; then export FEATURES="$FEATURES dtc" fi diff --git a/tests/test-crypto-tlssession.c b/tests/test-crypto-tlssession.c index 1a4a066d76..82f21c27f2 100644 --- a/tests/test-crypto-tlssession.c +++ b/tests/test-crypto-tlssession.c @@ -75,6 +75,7 @@ static QCryptoTLSCreds *test_tls_creds_create(QCryptoTLSCredsEndpoint endpoint, "server" : "client"), "dir", certdir, "verify-peer", "yes", + "priority", "NORMAL", /* We skip initial sanity checks here because we * want to make sure that problems are being * detected at the TLS session validation stage, diff --git a/tests/test-io-channel-tls.c b/tests/test-io-channel-tls.c index 32743b2c96..bb88ee870f 100644 --- a/tests/test-io-channel-tls.c +++ b/tests/test-io-channel-tls.c @@ -78,6 +78,7 @@ static QCryptoTLSCreds *test_tls_creds_create(QCryptoTLSCredsEndpoint endpoint, "server" : "client"), "dir", certdir, "verify-peer", "yes", + "priority", "NORMAL", /* We skip initial sanity checks here because we * want to make sure that problems are being * detected at the TLS session validation stage, diff --git a/tests/vm/basevm.py b/tests/vm/basevm.py index 686d88decf..3a2d508c35 100755 --- a/tests/vm/basevm.py +++ b/tests/vm/basevm.py @@ -107,10 +107,7 @@ class BaseVM(object): assert not isinstance(cmd, str) ssh_cmd += ["%s@127.0.0.1" % user] + list(cmd) logging.debug("ssh_cmd: %s", " ".join(ssh_cmd)) - r = subprocess.call(ssh_cmd, - stdin=sys.stdin if interactive else self._devnull, - stdout=sys.stdout if interactive else self._stdout, - stderr=sys.stderr if interactive else self._stderr) + r = subprocess.call(ssh_cmd) if check and r != 0: raise Exception("SSH command failed: %s" % cmd) return r diff --git a/ui/console.c b/ui/console.c index 530a491987..3fb2f4e09f 100644 --- a/ui/console.c +++ b/ui/console.c @@ -1191,11 +1191,22 @@ static const int qcode_to_keysym[Q_KEY_CODE__MAX] = { [Q_KEY_CODE_BACKSPACE] = QEMU_KEY_BACKSPACE, }; -bool kbd_put_qcode_console(QemuConsole *s, int qcode) +static const int ctrl_qcode_to_keysym[Q_KEY_CODE__MAX] = { + [Q_KEY_CODE_UP] = QEMU_KEY_CTRL_UP, + [Q_KEY_CODE_DOWN] = QEMU_KEY_CTRL_DOWN, + [Q_KEY_CODE_RIGHT] = QEMU_KEY_CTRL_RIGHT, + [Q_KEY_CODE_LEFT] = QEMU_KEY_CTRL_LEFT, + [Q_KEY_CODE_HOME] = QEMU_KEY_CTRL_HOME, + [Q_KEY_CODE_END] = QEMU_KEY_CTRL_END, + [Q_KEY_CODE_PGUP] = QEMU_KEY_CTRL_PAGEUP, + [Q_KEY_CODE_PGDN] = QEMU_KEY_CTRL_PAGEDOWN, +}; + +bool kbd_put_qcode_console(QemuConsole *s, int qcode, bool ctrl) { int keysym; - keysym = qcode_to_keysym[qcode]; + keysym = ctrl ? ctrl_qcode_to_keysym[qcode] : qcode_to_keysym[qcode]; if (keysym == 0) { return false; } @@ -1197,12 +1197,12 @@ static gboolean gd_text_key_down(GtkWidget *widget, QemuConsole *con = vc->gfx.dcl.con; if (key->keyval == GDK_KEY_Delete) { - kbd_put_qcode_console(con, Q_KEY_CODE_DELETE); + kbd_put_qcode_console(con, Q_KEY_CODE_DELETE, false); } else if (key->length) { kbd_put_string_console(con, key->string, key->length); } else { int qcode = gd_map_keycode(key->hardware_keycode); - kbd_put_qcode_console(con, qcode); + kbd_put_qcode_console(con, qcode, false); } return TRUE; } diff --git a/ui/sdl2-gl.c b/ui/sdl2-gl.c index 5e1073a084..c3683e6b65 100644 --- a/ui/sdl2-gl.c +++ b/ui/sdl2-gl.c @@ -32,8 +32,6 @@ #include "ui/sdl2.h" #include "sysemu/sysemu.h" -#include <epoxy/gl.h> - static void sdl2_set_scanout_mode(struct sdl2_console *scon, bool scanout) { if (scon->scanout_mode == scanout) { diff --git a/ui/sdl2-input.c b/ui/sdl2-input.c index 605d781971..1378b63dd9 100644 --- a/ui/sdl2-input.c +++ b/ui/sdl2-input.c @@ -60,32 +60,8 @@ void sdl2_process_key(struct sdl2_console *scon, qcode = qemu_input_map_usb_to_qcode[ev->keysym.scancode]; - if (!qemu_console_is_graphic(con)) { - if (ev->type == SDL_KEYDOWN) { - switch (ev->keysym.scancode) { - case SDL_SCANCODE_RETURN: - kbd_put_keysym_console(con, '\n'); - break; - case SDL_SCANCODE_BACKSPACE: - kbd_put_keysym_console(con, QEMU_KEY_BACKSPACE); - break; - default: - kbd_put_qcode_console(con, qcode); - break; - } - } - return; - } - + /* modifier state tracking */ switch (ev->keysym.scancode) { -#if 0 - case SDL_SCANCODE_NUMLOCKCLEAR: - case SDL_SCANCODE_CAPSLOCK: - /* SDL does not send the key up event, so we generate it */ - qemu_input_event_send_key_qcode(con, qcode, true); - qemu_input_event_send_key_qcode(con, qcode, false); - return; -#endif case SDL_SCANCODE_LCTRL: case SDL_SCANCODE_LSHIFT: case SDL_SCANCODE_LALT: @@ -99,8 +75,26 @@ void sdl2_process_key(struct sdl2_console *scon, } else { modifiers_state[ev->keysym.scancode] = 1; } - /* fall though */ + break; default: + /* nothing */ + break; + } + + if (!qemu_console_is_graphic(con)) { + bool ctrl = (modifiers_state[SDL_SCANCODE_LCTRL] || + modifiers_state[SDL_SCANCODE_RCTRL]); + if (ev->type == SDL_KEYDOWN) { + switch (ev->keysym.scancode) { + case SDL_SCANCODE_RETURN: + kbd_put_keysym_console(con, '\n'); + break; + default: + kbd_put_qcode_console(con, qcode, ctrl); + break; + } + } + } else { qemu_input_event_send_key_qcode(con, qcode, ev->type == SDL_KEYDOWN); } |