[libvirt] [PATCH v2 0/2] qemu: Forbid qcow/qcow2 native encryption

v2: - add entries to formatdomain.html and formatstorageencryption.html saying that the encryption should not be used. This applies on top of my branch collecting all ACKed postings of recent blockdev-related work. Current version can be fetched by: git fetch git://pipo.sk/pipo/libvirt.git blockdev-staging Peter Krempa (2): qemu: domain: Forbid storage with old QCOW2 encryption qemu: Remove code for setting up disk passphrases docs/formatdomain.html.in | 4 + docs/formatstorageencryption.html.in | 5 +- src/qemu/qemu_domain.c | 10 +++ src/qemu/qemu_monitor.c | 13 --- src/qemu/qemu_monitor.h | 4 - src/qemu/qemu_monitor_json.c | 28 ------ src/qemu/qemu_monitor_json.h | 4 - src/qemu/qemu_process.c | 103 ----------------------- tests/qemumonitorjsontest.c | 2 - tests/qemuxml2argvdata/encrypted-disk-usage.args | 8 +- tests/qemuxml2argvdata/encrypted-disk-usage.xml | 2 +- tests/qemuxml2argvdata/encrypted-disk.args | 8 +- tests/qemuxml2argvdata/encrypted-disk.xml | 2 +- tests/qemuxml2argvtest.c | 4 +- tests/qemuxml2xmloutdata/encrypted-disk.xml | 2 +- tests/qemuxml2xmltest.c | 4 +- 16 files changed, 37 insertions(+), 166 deletions(-) -- 2.16.2

The encryption was buggy and qemu actually dropped it upstream. Forbid it for all versions since it would cause other problems too. Problems with the old encryption include weak crypto, corruption of images with blockjobs and a lot of usability problems. This requires changing of the encryption type for the encrypted disk tests. Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- docs/formatdomain.html.in | 4 ++++ docs/formatstorageencryption.html.in | 5 ++--- src/qemu/qemu_domain.c | 10 ++++++++++ tests/qemuxml2argvdata/encrypted-disk-usage.args | 8 +++++++- tests/qemuxml2argvdata/encrypted-disk-usage.xml | 2 +- tests/qemuxml2argvdata/encrypted-disk.args | 8 +++++++- tests/qemuxml2argvdata/encrypted-disk.xml | 2 +- tests/qemuxml2argvtest.c | 4 ++-- tests/qemuxml2xmloutdata/encrypted-disk.xml | 2 +- tests/qemuxml2xmltest.c | 4 ++-- 10 files changed, 37 insertions(+), 12 deletions(-) diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in index b5a6e33bfe..b64a843fb4 100644 --- a/docs/formatdomain.html.in +++ b/docs/formatdomain.html.in @@ -2974,6 +2974,10 @@ See the <a href="formatstorageencryption.html">Storage Encryption</a> page for more information. + <p/> + Note that the 'qcow' format of encryption is broken and thus is no + longer supported for use with disk images. + (<span class="since">Since libvirt 4.5.0</span>) </dd> <dt><code>reservations</code></dt> <dd><span class="since">Since libvirt 4.4.0</span>, the diff --git a/docs/formatstorageencryption.html.in b/docs/formatstorageencryption.html.in index 23efbf932e..434bdb609e 100644 --- a/docs/formatstorageencryption.html.in +++ b/docs/formatstorageencryption.html.in @@ -53,9 +53,8 @@ The <code>qcow</code> format specifies that the built-in encryption support in <code>qcow</code>- or <code>qcow2</code>-formatted volume images should be used. A single - <code><secret type='passphrase'></code> element is expected. If - the <code>secret</code> element is not present during volume creation, - a secret is automatically generated and attached to the volume. + <code><secret type='passphrase'></code> element is expected. Note + that this encryption is inherently broken and should not be used any more. </p> <h3><a id="StorageEncryptionLuks">"luks" format</a></h3> <p> diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index 873bcec50d..f10bbf39c0 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -4483,6 +4483,16 @@ qemuDomainValidateStorageSource(virStorageSourcePtr src, return -1; } + if ((src->format == VIR_STORAGE_FILE_QCOW || + src->format == VIR_STORAGE_FILE_QCOW2) && + src->encryption && + (src->encryption->format == VIR_STORAGE_ENCRYPTION_FORMAT_DEFAULT || + src->encryption->format == VIR_STORAGE_ENCRYPTION_FORMAT_QCOW)) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("old qcow/qcow2 encryption is not supported")); + return -1; + } + if (src->format == VIR_STORAGE_FILE_QCOW2 && src->encryption && src->encryption->format == VIR_STORAGE_ENCRYPTION_FORMAT_LUKS && diff --git a/tests/qemuxml2argvdata/encrypted-disk-usage.args b/tests/qemuxml2argvdata/encrypted-disk-usage.args index 8c7ce3d653..32307cea71 100644 --- a/tests/qemuxml2argvdata/encrypted-disk-usage.args +++ b/tests/qemuxml2argvdata/encrypted-disk-usage.args @@ -7,6 +7,8 @@ QEMU_AUDIO_DRV=none \ /usr/bin/qemu-system-i686 \ -name encryptdisk \ -S \ +-object secret,id=masterKey0,format=raw,\ +file=/tmp/lib/domain--1-encryptdisk/master-key.aes \ -machine pc,accel=tcg,usb=off,dump-guest-core=off \ -m 1024 \ -smp 1,sockets=1,cores=1,threads=1 \ @@ -22,7 +24,11 @@ path=/tmp/lib/domain--1-encryptdisk/monitor.sock,server,nowait \ -no-acpi \ -boot c \ -usb \ --drive file=/storage/guest_disks/encryptdisk,format=qcow2,if=none,\ +-object secret,id=virtio-disk0-luks-secret0,\ +data=9eao5F8qtkGt+seB1HYivWIxbtwUu6MQtg1zpj/oDtUsPr1q8wBYM91uEHCn6j/1,\ +keyid=masterKey0,iv=AAECAwQFBgcICQoLDA0ODw==,format=base64 \ +-drive file=/storage/guest_disks/encryptdisk,encrypt.format=luks,\ +encrypt.key-secret=virtio-disk0-luks-secret0,format=qcow2,if=none,\ id=drive-virtio-disk0 \ -device virtio-blk-pci,bus=pci.0,addr=0x4,drive=drive-virtio-disk0,\ id=virtio-disk0 \ diff --git a/tests/qemuxml2argvdata/encrypted-disk-usage.xml b/tests/qemuxml2argvdata/encrypted-disk-usage.xml index ad8f17e3df..205283b59d 100644 --- a/tests/qemuxml2argvdata/encrypted-disk-usage.xml +++ b/tests/qemuxml2argvdata/encrypted-disk-usage.xml @@ -18,7 +18,7 @@ <driver name='qemu' type='qcow2'/> <source file='/storage/guest_disks/encryptdisk'/> <target dev='vda' bus='virtio'/> - <encryption format='qcow'> + <encryption format='luks'> <secret type='passphrase' usage='/storage/guest_disks/encryptdisk'/> </encryption> <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/> diff --git a/tests/qemuxml2argvdata/encrypted-disk.args b/tests/qemuxml2argvdata/encrypted-disk.args index 8c7ce3d653..32307cea71 100644 --- a/tests/qemuxml2argvdata/encrypted-disk.args +++ b/tests/qemuxml2argvdata/encrypted-disk.args @@ -7,6 +7,8 @@ QEMU_AUDIO_DRV=none \ /usr/bin/qemu-system-i686 \ -name encryptdisk \ -S \ +-object secret,id=masterKey0,format=raw,\ +file=/tmp/lib/domain--1-encryptdisk/master-key.aes \ -machine pc,accel=tcg,usb=off,dump-guest-core=off \ -m 1024 \ -smp 1,sockets=1,cores=1,threads=1 \ @@ -22,7 +24,11 @@ path=/tmp/lib/domain--1-encryptdisk/monitor.sock,server,nowait \ -no-acpi \ -boot c \ -usb \ --drive file=/storage/guest_disks/encryptdisk,format=qcow2,if=none,\ +-object secret,id=virtio-disk0-luks-secret0,\ +data=9eao5F8qtkGt+seB1HYivWIxbtwUu6MQtg1zpj/oDtUsPr1q8wBYM91uEHCn6j/1,\ +keyid=masterKey0,iv=AAECAwQFBgcICQoLDA0ODw==,format=base64 \ +-drive file=/storage/guest_disks/encryptdisk,encrypt.format=luks,\ +encrypt.key-secret=virtio-disk0-luks-secret0,format=qcow2,if=none,\ id=drive-virtio-disk0 \ -device virtio-blk-pci,bus=pci.0,addr=0x4,drive=drive-virtio-disk0,\ id=virtio-disk0 \ diff --git a/tests/qemuxml2argvdata/encrypted-disk.xml b/tests/qemuxml2argvdata/encrypted-disk.xml index 391461b200..275724bdaf 100644 --- a/tests/qemuxml2argvdata/encrypted-disk.xml +++ b/tests/qemuxml2argvdata/encrypted-disk.xml @@ -18,7 +18,7 @@ <driver name='qemu' type='qcow2'/> <source file='/storage/guest_disks/encryptdisk'/> <target dev='vda' bus='virtio'/> - <encryption format='qcow'> + <encryption format='luks'> <secret type='passphrase' uuid='0a81f5b2-8403-7b23-c8d6-21ccc2f80d6f'/> </encryption> <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/> diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index 2d41f78f8b..64d112be36 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -1651,8 +1651,8 @@ mymain(void) DO_TEST("cpu-tsc-frequency", QEMU_CAPS_KVM); qemuTestSetHostCPU(driver.caps, NULL); - DO_TEST("encrypted-disk", NONE); - DO_TEST("encrypted-disk-usage", NONE); + DO_TEST("encrypted-disk", QEMU_CAPS_QCOW2_LUKS, QEMU_CAPS_OBJECT_SECRET); + DO_TEST("encrypted-disk-usage", QEMU_CAPS_QCOW2_LUKS, QEMU_CAPS_OBJECT_SECRET); # ifdef WITH_GNUTLS DO_TEST("luks-disks", QEMU_CAPS_OBJECT_SECRET); DO_TEST("luks-disks-source", QEMU_CAPS_OBJECT_SECRET); diff --git a/tests/qemuxml2xmloutdata/encrypted-disk.xml b/tests/qemuxml2xmloutdata/encrypted-disk.xml index 45b9fcca55..3c9d2fbafc 100644 --- a/tests/qemuxml2xmloutdata/encrypted-disk.xml +++ b/tests/qemuxml2xmloutdata/encrypted-disk.xml @@ -18,7 +18,7 @@ <driver name='qemu' type='qcow2'/> <source file='/storage/guest_disks/encryptdisk'/> <target dev='vda' bus='virtio'/> - <encryption format='qcow'> + <encryption format='luks'> <secret type='passphrase' uuid='0a81f5b2-8403-7b23-c8d6-21ccc2f80d6f'/> </encryption> <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/> diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c index 57b4c3eb0a..f53f9a7db5 100644 --- a/tests/qemuxml2xmltest.c +++ b/tests/qemuxml2xmltest.c @@ -482,8 +482,8 @@ mymain(void) DO_TEST("pci-rom-disabled-invalid", NONE); DO_TEST("pci-serial-dev-chardev", NONE); - DO_TEST("encrypted-disk", NONE); - DO_TEST("encrypted-disk-usage", NONE); + DO_TEST("encrypted-disk", QEMU_CAPS_QCOW2_LUKS); + DO_TEST("encrypted-disk-usage", QEMU_CAPS_QCOW2_LUKS); DO_TEST("luks-disks", NONE); DO_TEST("luks-disks-source", NONE); DO_TEST("memtune", NONE); -- 2.16.2

On Fri, Jun 01, 2018 at 02:06:37PM +0200, Peter Krempa wrote:
The encryption was buggy and qemu actually dropped it upstream. Forbid it for all versions since it would cause other problems too.
Problems with the old encryption include weak crypto, corruption of images with blockjobs and a lot of usability problems.
This requires changing of the encryption type for the encrypted disk tests.
Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- docs/formatdomain.html.in | 4 ++++ docs/formatstorageencryption.html.in | 5 ++--- src/qemu/qemu_domain.c | 10 ++++++++++ tests/qemuxml2argvdata/encrypted-disk-usage.args | 8 +++++++- tests/qemuxml2argvdata/encrypted-disk-usage.xml | 2 +- tests/qemuxml2argvdata/encrypted-disk.args | 8 +++++++- tests/qemuxml2argvdata/encrypted-disk.xml | 2 +- tests/qemuxml2argvtest.c | 4 ++-- tests/qemuxml2xmloutdata/encrypted-disk.xml | 2 +- tests/qemuxml2xmltest.c | 4 ++-- 10 files changed, 37 insertions(+), 12 deletions(-)
Reviewed-by: Ján Tomko <jtomko@redhat.com> Jano

Now that the old qcow2 encryption is removed we can safely delete all this code since it's not needed any more. Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- src/qemu/qemu_monitor.c | 13 ------ src/qemu/qemu_monitor.h | 4 -- src/qemu/qemu_monitor_json.c | 28 ------------ src/qemu/qemu_monitor_json.h | 4 -- src/qemu/qemu_process.c | 103 ------------------------------------------- tests/qemumonitorjsontest.c | 2 - 6 files changed, 154 deletions(-) diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c index 876157437a..b0c63c68d3 100644 --- a/src/qemu/qemu_monitor.c +++ b/src/qemu/qemu_monitor.c @@ -3118,19 +3118,6 @@ qemuMonitorAddDrive(qemuMonitorPtr mon, } -int -qemuMonitorSetDrivePassphrase(qemuMonitorPtr mon, - const char *alias, - const char *passphrase) -{ - VIR_DEBUG("alias=%s passphrase=%p(value hidden)", alias, passphrase); - - QEMU_CHECK_MONITOR(mon); - - return qemuMonitorJSONSetDrivePassphrase(mon, alias, passphrase); -} - - int qemuMonitorCreateSnapshot(qemuMonitorPtr mon, const char *name) { diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h index d6e5a2239e..9894eba4d0 100644 --- a/src/qemu/qemu_monitor.h +++ b/src/qemu/qemu_monitor.h @@ -819,10 +819,6 @@ int qemuMonitorAddDrive(qemuMonitorPtr mon, int qemuMonitorDriveDel(qemuMonitorPtr mon, const char *drivestr); -int qemuMonitorSetDrivePassphrase(qemuMonitorPtr mon, - const char *alias, - const char *passphrase); - int qemuMonitorCreateSnapshot(qemuMonitorPtr mon, const char *name); int qemuMonitorLoadSnapshot(qemuMonitorPtr mon, const char *name); int qemuMonitorDeleteSnapshot(qemuMonitorPtr mon, const char *name); diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index 7522eaeef0..42d7b9c5e9 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -4055,34 +4055,6 @@ int qemuMonitorJSONDelObject(qemuMonitorPtr mon, } -int qemuMonitorJSONSetDrivePassphrase(qemuMonitorPtr mon, - const char *alias, - const char *passphrase) -{ - int ret = -1; - virJSONValuePtr cmd; - virJSONValuePtr reply = NULL; - - cmd = qemuMonitorJSONMakeCommand("block_passwd", - "s:device", alias, - "s:password", passphrase, - NULL); - if (!cmd) - return -1; - - if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0) - goto cleanup; - - if (qemuMonitorJSONCheckError(cmd, reply) < 0) - goto cleanup; - - ret = 0; - cleanup: - virJSONValueFree(cmd); - virJSONValueFree(reply); - return ret; -} - int qemuMonitorJSONDiskSnapshot(qemuMonitorPtr mon, virJSONValuePtr actions, const char *device, const char *file, diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h index 5fc51b1d6b..2ae0faad74 100644 --- a/src/qemu/qemu_monitor_json.h +++ b/src/qemu/qemu_monitor_json.h @@ -235,10 +235,6 @@ int qemuMonitorJSONAddObject(qemuMonitorPtr mon, int qemuMonitorJSONDelObject(qemuMonitorPtr mon, const char *objalias); -int qemuMonitorJSONSetDrivePassphrase(qemuMonitorPtr mon, - const char *alias, - const char *passphrase); - int qemuMonitorJSONDiskSnapshot(qemuMonitorPtr mon, virJSONValuePtr actions, const char *device, diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index 30cc5904e0..07d8cb6d49 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -371,74 +371,6 @@ qemuProcessFindDomainDiskByAlias(virDomainObjPtr vm, return NULL; } -static int -qemuProcessGetVolumeQcowPassphrase(virDomainDiskDefPtr disk, - char **secretRet, - size_t *secretLen) -{ - virConnectPtr conn = NULL; - char *passphrase; - unsigned char *data; - size_t size; - int ret = -1; - virStorageEncryptionPtr enc; - - if (!disk->src->encryption) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("disk %s does not have any encryption information"), - disk->src->path); - return -1; - } - enc = disk->src->encryption; - - if (!(conn = virGetConnectSecret())) - goto cleanup; - - if (enc->format != VIR_STORAGE_ENCRYPTION_FORMAT_QCOW || - enc->nsecrets != 1 || - enc->secrets[0]->type != - VIR_STORAGE_ENCRYPTION_SECRET_TYPE_PASSPHRASE) { - virReportError(VIR_ERR_XML_ERROR, - _("invalid <encryption> for volume %s"), - virDomainDiskGetSource(disk)); - goto cleanup; - } - - if (virSecretGetSecretString(conn, &enc->secrets[0]->seclookupdef, - VIR_SECRET_USAGE_TYPE_VOLUME, - &data, &size) < 0) - goto cleanup; - - if (memchr(data, '\0', size) != NULL) { - memset(data, 0, size); - VIR_FREE(data); - virReportError(VIR_ERR_XML_ERROR, - _("format='qcow' passphrase for %s must not contain a " - "'\\0'"), virDomainDiskGetSource(disk)); - goto cleanup; - } - - if (VIR_ALLOC_N(passphrase, size + 1) < 0) { - memset(data, 0, size); - VIR_FREE(data); - goto cleanup; - } - memcpy(passphrase, data, size); - passphrase[size] = '\0'; - - memset(data, 0, size); - VIR_FREE(data); - - *secretRet = passphrase; - *secretLen = size; - - ret = 0; - - cleanup: - virObjectUnref(conn); - return ret; -} - static int qemuProcessHandleReset(qemuMonitorPtr mon ATTRIBUTE_UNUSED, virDomainObjPtr vm, @@ -2729,11 +2661,8 @@ qemuProcessInitPasswords(virQEMUDriverPtr driver, int asyncJob) { int ret = 0; - qemuDomainObjPrivatePtr priv = vm->privateData; virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver); size_t i; - char *alias = NULL; - char *secret = NULL; for (i = 0; i < vm->def->ngraphics; ++i) { virDomainGraphicsDefPtr graphics = vm->def->graphics[i]; @@ -2755,39 +2684,7 @@ qemuProcessInitPasswords(virQEMUDriverPtr driver, goto cleanup; } - for (i = 0; i < vm->def->ndisks; i++) { - size_t secretLen; - - if (!vm->def->disks[i]->src->encryption || - !virDomainDiskGetSource(vm->def->disks[i])) - continue; - - if (vm->def->disks[i]->src->encryption->format != - VIR_STORAGE_ENCRYPTION_FORMAT_DEFAULT && - vm->def->disks[i]->src->encryption->format != - VIR_STORAGE_ENCRYPTION_FORMAT_QCOW) - continue; - - VIR_FREE(secret); - if (qemuProcessGetVolumeQcowPassphrase(vm->def->disks[i], - &secret, &secretLen) < 0) - goto cleanup; - - VIR_FREE(alias); - if (!(alias = qemuAliasFromDisk(vm->def->disks[i]))) - goto cleanup; - if (qemuDomainObjEnterMonitorAsync(driver, vm, asyncJob) < 0) - goto cleanup; - ret = qemuMonitorSetDrivePassphrase(priv->mon, alias, secret); - if (qemuDomainObjExitMonitor(driver, vm) < 0) - ret = -1; - if (ret < 0) - goto cleanup; - } - cleanup: - VIR_FREE(alias); - VIR_FREE(secret); virObjectUnref(cfg); return ret; } diff --git a/tests/qemumonitorjsontest.c b/tests/qemumonitorjsontest.c index add5ff0f19..3b494a1dba 100644 --- a/tests/qemumonitorjsontest.c +++ b/tests/qemumonitorjsontest.c @@ -1343,7 +1343,6 @@ GEN_TEST_FUNC(qemuMonitorJSONAddNetdev, "id=net0,type=test") GEN_TEST_FUNC(qemuMonitorJSONRemoveNetdev, "net0") GEN_TEST_FUNC(qemuMonitorJSONDelDevice, "ide0") GEN_TEST_FUNC(qemuMonitorJSONAddDevice, "some_dummy_devicestr") -GEN_TEST_FUNC(qemuMonitorJSONSetDrivePassphrase, "drive-vda", "secret_passhprase") GEN_TEST_FUNC(qemuMonitorJSONDriveMirror, "vdb", "/foo/bar", NULL, 1024, 0, 0, VIR_DOMAIN_BLOCK_REBASE_SHALLOW | VIR_DOMAIN_BLOCK_REBASE_REUSE_EXT) GEN_TEST_FUNC(qemuMonitorJSONBlockCommit, "vdb", "/foo/bar1", "/foo/bar2", NULL, 1024) @@ -2967,7 +2966,6 @@ mymain(void) DO_TEST_GEN(qemuMonitorJSONRemoveNetdev); DO_TEST_GEN(qemuMonitorJSONDelDevice); DO_TEST_GEN(qemuMonitorJSONAddDevice); - DO_TEST_GEN(qemuMonitorJSONSetDrivePassphrase); DO_TEST_GEN(qemuMonitorJSONDriveMirror); DO_TEST_GEN(qemuMonitorJSONBlockCommit); DO_TEST_GEN(qemuMonitorJSONDrivePivot); -- 2.16.2

On Fri, Jun 01, 2018 at 02:06:38PM +0200, Peter Krempa wrote:
Now that the old qcow2 encryption is removed we can safely delete all this code since it's not needed any more.
Signed-off-by: Peter Krempa <pkrempa@redhat.com> --- src/qemu/qemu_monitor.c | 13 ------ src/qemu/qemu_monitor.h | 4 -- src/qemu/qemu_monitor_json.c | 28 ------------ src/qemu/qemu_monitor_json.h | 4 -- src/qemu/qemu_process.c | 103 ------------------------------------------- tests/qemumonitorjsontest.c | 2 - 6 files changed, 154 deletions(-)
Beautiful diffstat. Reviewed-by: Ján Tomko <jtomko@redhat.com> Jano
participants (2)
-
Ján Tomko
-
Peter Krempa