[libvirt] [PATCH v2 15/15] qemu: Add luks support for domain disk

John Ferlan jferlan at redhat.com
Thu Jun 23 17:29:11 UTC 2016


Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1301021

Generate the luks command line using the AES secret key to encrypt the
luks secret. A luks secret object will be in addition to a an AES secret.

For hotplug, check if the encinfo exists and if so, add the AES secret
for the passphrase for the secret object used to decrypt the device.

Add tests for sample output

Signed-off-by: John Ferlan <jferlan at redhat.com>
---
 src/qemu/qemu_command.c                            | 12 +++-
 src/qemu/qemu_domain.c                             | 50 +++++++++++------
 src/qemu/qemu_hotplug.c                            | 65 +++++++++++++++++++---
 .../qemuxml2argv-luks-disk-cipher.args             | 36 ++++++++++++
 .../qemuxml2argvdata/qemuxml2argv-luks-disks.args  | 36 ++++++++++++
 tests/qemuxml2argvtest.c                           | 11 +++-
 6 files changed, 182 insertions(+), 28 deletions(-)
 create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-luks-disk-cipher.args
 create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-luks-disks.args

diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index 5d82a4d..6ba9607 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -1098,6 +1098,7 @@ qemuBuildDriveStr(virDomainDiskDefPtr disk,
     int actualType = virStorageSourceGetActualType(disk->src);
     qemuDomainDiskPrivatePtr diskPriv = QEMU_DOMAIN_DISK_PRIVATE(disk);
     qemuDomainSecretInfoPtr secinfo = diskPriv->secinfo;
+    qemuDomainSecretInfoPtr encinfo = diskPriv->encinfo;
     bool emitDeviceSyntax = qemuDiskBusNeedsDeviceArg(disk->bus);
 
     if (idx < 0) {
@@ -1232,10 +1233,13 @@ qemuBuildDriveStr(virDomainDiskDefPtr disk,
         qemuBufferEscapeComma(&opt, source);
         virBufferAddLit(&opt, ",");
 
-        if (secinfo && secinfo->type == VIR_DOMAIN_SECRET_INFO_TYPE_AES) {
+        if (secinfo && secinfo->type == VIR_DOMAIN_SECRET_INFO_TYPE_AES)
             virBufferAsprintf(&opt, "password-secret=%s,",
                               secinfo->s.aes.alias);
-        }
+
+        if (encinfo)
+            virQEMUBuildLuksOpts(&opt, disk->src->encryption,
+                                 encinfo->s.aes.alias);
 
         if (disk->src->format > 0 &&
             disk->src->type != VIR_STORAGE_TYPE_DIR)
@@ -1939,6 +1943,7 @@ qemuBuildDiskDriveCommandLine(virCommandPtr cmd,
         virDomainDiskDefPtr disk = def->disks[i];
         qemuDomainDiskPrivatePtr diskPriv = QEMU_DOMAIN_DISK_PRIVATE(disk);
         qemuDomainSecretInfoPtr secinfo = diskPriv->secinfo;
+        qemuDomainSecretInfoPtr encinfo = diskPriv->encinfo;
 
         /* PowerPC pseries based VMs do not support floppy device */
         if ((disk->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY) &&
@@ -1968,6 +1973,9 @@ qemuBuildDiskDriveCommandLine(virCommandPtr cmd,
         if (qemuBuildDiskSecinfoCommandLine(cmd, secinfo) < 0)
             return -1;
 
+        if (qemuBuildDiskSecinfoCommandLine(cmd, encinfo) < 0)
+            return -1;
+
         virCommandAddArg(cmd, "-drive");
 
         optstr = qemuBuildDriveStr(disk,
diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
index dca8970..53744c9 100644
--- a/src/qemu/qemu_domain.c
+++ b/src/qemu/qemu_domain.c
@@ -941,7 +941,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_CEPH ||
+         secretUsageType == VIR_SECRET_USAGE_TYPE_PASSPHRASE)) {
         if (qemuDomainSecretAESSetup(conn, priv, secinfo, srcalias,
                                      secretUsageType, username,
                                      seclookupdef) < 0)
@@ -989,27 +990,42 @@ qemuDomainSecretDiskPrepare(virConnectPtr conn,
     virStorageSourcePtr src = disk->src;
     qemuDomainSecretInfoPtr secinfo = NULL;
 
-    if (conn && !virStorageSourceIsEmpty(src) &&
-        virStorageSourceGetActualType(src) == VIR_STORAGE_TYPE_NETWORK &&
-        src->auth &&
-        (src->protocol == VIR_STORAGE_NET_PROTOCOL_ISCSI ||
-         src->protocol == VIR_STORAGE_NET_PROTOCOL_RBD)) {
-
-        virSecretUsageType secretUsageType = VIR_SECRET_USAGE_TYPE_ISCSI;
+    if (conn && !virStorageSourceIsEmpty(src)) {
         qemuDomainDiskPrivatePtr diskPriv = QEMU_DOMAIN_DISK_PRIVATE(disk);
 
-        if (VIR_ALLOC(secinfo) < 0)
-            return -1;
+        if (virStorageSourceGetActualType(src) == VIR_STORAGE_TYPE_NETWORK &&
+            src->auth &&
+            (src->protocol == VIR_STORAGE_NET_PROTOCOL_ISCSI ||
+             src->protocol == VIR_STORAGE_NET_PROTOCOL_RBD)) {
 
-        if (src->protocol == VIR_STORAGE_NET_PROTOCOL_RBD)
-            secretUsageType = VIR_SECRET_USAGE_TYPE_CEPH;
+            virSecretUsageType secretUsageType = VIR_SECRET_USAGE_TYPE_ISCSI;
 
-        if (qemuDomainSecretSetup(conn, priv, secinfo, disk->info.alias,
-                                  secretUsageType, src->auth->username,
-                                  &src->auth->seclookupdef) < 0)
-            goto error;
+            if (src->protocol == VIR_STORAGE_NET_PROTOCOL_RBD)
+                secretUsageType = VIR_SECRET_USAGE_TYPE_CEPH;
 
-        diskPriv->secinfo = secinfo;
+            if (VIR_ALLOC(secinfo) < 0)
+                return -1;
+
+            if (qemuDomainSecretSetup(conn, priv, secinfo, disk->info.alias,
+                                      secretUsageType, src->auth->username,
+                                      &src->auth->seclookupdef) < 0)
+                goto error;
+
+            diskPriv->secinfo = secinfo;
+        }
+
+        if (src->encryption && src->format == VIR_STORAGE_FILE_LUKS) {
+
+            if (VIR_ALLOC(secinfo) < 0)
+                return -1;
+
+            if (qemuDomainSecretSetup(conn, priv, secinfo, disk->info.alias,
+                                      VIR_SECRET_USAGE_TYPE_PASSPHRASE, NULL,
+                                      &src->encryption->secrets[0]->seclookupdef) < 0)
+                goto error;
+
+            diskPriv->encinfo = secinfo;
+        }
     }
 
     return 0;
diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c
index 235cb73..ab8fd38 100644
--- a/src/qemu/qemu_hotplug.c
+++ b/src/qemu/qemu_hotplug.c
@@ -311,8 +311,10 @@ qemuDomainAttachVirtioDiskDevice(virConnectPtr conn,
     virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
     const char *src = virDomainDiskGetSource(disk);
     virJSONValuePtr secobjProps = NULL;
+    virJSONValuePtr encProps = NULL;
     qemuDomainDiskPrivatePtr diskPriv;
     qemuDomainSecretInfoPtr secinfo;
+    qemuDomainSecretInfoPtr encinfo;
 
     if (!disk->info.type) {
         if (qemuDomainMachineIsS390CCW(vm->def) &&
@@ -352,6 +354,10 @@ qemuDomainAttachVirtioDiskDevice(virConnectPtr conn,
             goto error;
     }
 
+    encinfo = diskPriv->encinfo;
+    if (encinfo && qemuBuildSecretInfoProps(encinfo, &encProps) < 0)
+        goto error;
+
     if (!(drivestr = qemuBuildDriveStr(disk, false, priv->qemuCaps)))
         goto error;
 
@@ -364,7 +370,7 @@ qemuDomainAttachVirtioDiskDevice(virConnectPtr conn,
     if (VIR_REALLOC_N(vm->def->disks, vm->def->ndisks+1) < 0)
         goto error;
 
-    /* Attach the device - possible 3 step process */
+    /* Attach the device - possible 4 step process */
     qemuDomainObjEnterMonitor(driver, vm);
 
     if (secobjProps && qemuMonitorAddObject(priv->mon, "secret",
@@ -373,6 +379,12 @@ qemuDomainAttachVirtioDiskDevice(virConnectPtr conn,
         goto failaddobjsecret;
     secobjProps = NULL;
 
+    if (encProps && qemuMonitorAddObject(priv->mon, "secret",
+                                         encinfo->s.aes.alias,
+                                         encProps) < 0)
+        goto failaddencsecret;
+    encProps = NULL;
+
     if (qemuMonitorAddDrive(priv->mon, drivestr) < 0)
         goto failadddrive;
 
@@ -391,6 +403,7 @@ qemuDomainAttachVirtioDiskDevice(virConnectPtr conn,
 
  cleanup:
     virJSONValueFree(secobjProps);
+    virJSONValueFree(encProps);
     qemuDomainSecretDiskDestroy(disk);
     VIR_FREE(devstr);
     VIR_FREE(drivestr);
@@ -410,8 +423,13 @@ qemuDomainAttachVirtioDiskDevice(virConnectPtr conn,
     }
 
  failadddrive:
+    if (encProps)
+        ignore_value(qemuMonitorDelObject(priv->mon, encinfo->s.aes.alias));
+
+ failaddencsecret:
     if (secobjProps)
         ignore_value(qemuMonitorDelObject(priv->mon, secinfo->s.aes.alias));
+    encProps = NULL; /* qemuMonitorAddObject consumes props on failure too */
 
  failaddobjsecret:
     if (qemuDomainObjExitMonitor(driver, vm) < 0)
@@ -571,6 +589,9 @@ qemuDomainAttachSCSIDisk(virConnectPtr conn,
     char *devstr = NULL;
     int ret = -1;
     virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
+    virJSONValuePtr encProps = NULL;
+    qemuDomainDiskPrivatePtr diskPriv;
+    qemuDomainSecretInfoPtr encinfo;
 
     if (qemuDomainPrepareDisk(driver, vm, disk, NULL, false) < 0)
         goto cleanup;
@@ -589,6 +610,11 @@ qemuDomainAttachSCSIDisk(virConnectPtr conn,
     if (qemuDomainSecretDiskPrepare(conn, priv, disk) < 0)
         goto error;
 
+    diskPriv = QEMU_DOMAIN_DISK_PRIVATE(disk);
+    encinfo = diskPriv->encinfo;
+    if (encinfo && qemuBuildSecretInfoProps(encinfo, &encProps) < 0)
+        goto error;
+
     if (!(devstr = qemuBuildDriveDevStr(vm->def, disk, 0, priv->qemuCaps)))
         goto error;
 
@@ -598,9 +624,15 @@ qemuDomainAttachSCSIDisk(virConnectPtr conn,
     if (VIR_REALLOC_N(vm->def->disks, vm->def->ndisks+1) < 0)
         goto error;
 
-    /* Attach the device - 2 step process */
+    /* Attach the device - possible 3 step process */
     qemuDomainObjEnterMonitor(driver, vm);
 
+    if (encProps && qemuMonitorAddObject(priv->mon, "secret",
+                                         encinfo->s.aes.alias,
+                                         encProps) < 0)
+        goto failaddencsecret;
+    encProps = NULL;
+
     if (qemuMonitorAddDrive(priv->mon, drivestr) < 0)
         goto failadddrive;
 
@@ -627,7 +659,12 @@ qemuDomainAttachSCSIDisk(virConnectPtr conn,
     VIR_WARN("qemuMonitorAddDevice failed on %s (%s)", drivestr, devstr);
 
  failadddrive:
+    if (encProps)
+        ignore_value(qemuMonitorDelObject(priv->mon, encinfo->s.aes.alias));
+
+ failaddencsecret:
     ignore_value(qemuDomainObjExitMonitor(driver, vm));
+    encProps = NULL; /* qemuMonitorAddObject consumes props on failure too */
 
  failexitmonitor:
     virDomainAuditDisk(vm, NULL, disk->src, "attach", false);
@@ -3413,6 +3450,7 @@ qemuDomainDetachVirtioDiskDevice(virQEMUDriverPtr driver,
     qemuDomainObjPrivatePtr priv = vm->privateData;
     qemuDomainDiskPrivatePtr diskPriv = QEMU_DOMAIN_DISK_PRIVATE(detach);
     qemuDomainSecretInfoPtr secinfo = diskPriv->secinfo;
+    qemuDomainSecretInfoPtr encinfo = diskPriv->encinfo;
 
     if (qemuIsMultiFunctionDevice(vm->def, &detach->info)) {
         virReportError(VIR_ERR_OPERATION_FAILED,
@@ -3451,6 +3489,9 @@ qemuDomainDetachVirtioDiskDevice(virQEMUDriverPtr driver,
             goto faildel;
     }
 
+    if (encinfo && qemuMonitorDelObject(priv->mon, encinfo->s.aes.alias) < 0)
+        goto faildel;
+
     if (qemuMonitorDelDevice(priv->mon, detach->info.alias) < 0)
         goto faildel;
 
@@ -3478,6 +3519,8 @@ qemuDomainDetachDiskDevice(virQEMUDriverPtr driver,
 {
     int ret = -1;
     qemuDomainObjPrivatePtr priv = vm->privateData;
+    qemuDomainDiskPrivatePtr diskPriv = QEMU_DOMAIN_DISK_PRIVATE(detach);
+    qemuDomainSecretInfoPtr encinfo = diskPriv->encinfo;
 
     if (qemuDomainDiskBlockJobIsActive(detach))
         goto cleanup;
@@ -3485,12 +3528,12 @@ qemuDomainDetachDiskDevice(virQEMUDriverPtr driver,
     qemuDomainMarkDeviceForRemoval(vm, &detach->info);
 
     qemuDomainObjEnterMonitor(driver, vm);
-    if (qemuMonitorDelDevice(priv->mon, detach->info.alias) < 0) {
-        if (qemuDomainObjExitMonitor(driver, vm) < 0)
-            goto cleanup;
-        virDomainAuditDisk(vm, detach->src, NULL, "detach", false);
-        goto cleanup;
-    }
+    if (encinfo && qemuMonitorDelObject(priv->mon, encinfo->s.aes.alias) < 0)
+        goto faildel;
+
+    if (qemuMonitorDelDevice(priv->mon, detach->info.alias) < 0)
+        goto faildel;
+
     if (qemuDomainObjExitMonitor(driver, vm) < 0)
         goto cleanup;
 
@@ -3500,6 +3543,12 @@ qemuDomainDetachDiskDevice(virQEMUDriverPtr driver,
  cleanup:
     qemuDomainResetDeviceRemoval(vm);
     return ret;
+
+ faildel:
+    if (qemuDomainObjExitMonitor(driver, vm) < 0)
+        goto cleanup;
+    virDomainAuditDisk(vm, detach->src, NULL, "detach", false);
+    goto cleanup;
 }
 
 static int
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-luks-disk-cipher.args b/tests/qemuxml2argvdata/qemuxml2argv-luks-disk-cipher.args
new file mode 100644
index 0000000..6eebc87
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-luks-disk-cipher.args
@@ -0,0 +1,36 @@
+LC_ALL=C \
+PATH=/bin \
+HOME=/home/test \
+USER=test \
+LOGNAME=test \
+QEMU_AUDIO_DRV=none \
+/usr/bin/qemu \
+-name encryptdisk \
+-S \
+-object secret,id=masterKey0,format=raw,\
+file=/tmp/lib/domain--1-encryptdisk/master-key.aes \
+-M pc-i440fx-2.1 \
+-m 1024 \
+-smp 1 \
+-uuid 496898a6-e6ff-f7c8-5dc2-3cf410945ee9 \
+-nographic \
+-nodefaults \
+-monitor unix:/tmp/lib/domain--1-encryptdisk/monitor.sock,server,nowait \
+-no-acpi \
+-boot c \
+-usb \
+-object secret,id=virtio-disk0-secret0,\
+data=9eao5F8qtkGt+seB1HYivWIxbtwUu6MQtg1zpj/oDtUsPr1q8wBYM91uEHCn6j/1,\
+keyid=masterKey0,iv=AAECAwQFBgcICQoLDA0ODw==,format=base64 \
+-drive file=/storage/guest_disks/encryptdisk,key-secret=virtio-disk0-secret0,\
+format=luks,if=none,id=drive-virtio-disk0 \
+-device virtio-blk-pci,bus=pci.0,addr=0x4,drive=drive-virtio-disk0,\
+id=virtio-disk0 \
+-object secret,id=virtio-disk1-secret0,\
+data=9eao5F8qtkGt+seB1HYivWIxbtwUu6MQtg1zpj/oDtUsPr1q8wBYM91uEHCn6j/1,\
+keyid=masterKey0,iv=AAECAwQFBgcICQoLDA0ODw==,format=base64 \
+-drive file=/storage/guest_disks/encryptdisk2,key-secret=virtio-disk1-secret0,\
+format=luks,if=none,id=drive-virtio-disk1 \
+-device virtio-blk-pci,bus=pci.0,addr=0x5,drive=drive-virtio-disk1,\
+id=virtio-disk1 \
+-device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x3
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-luks-disks.args b/tests/qemuxml2argvdata/qemuxml2argv-luks-disks.args
new file mode 100644
index 0000000..6eebc87
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-luks-disks.args
@@ -0,0 +1,36 @@
+LC_ALL=C \
+PATH=/bin \
+HOME=/home/test \
+USER=test \
+LOGNAME=test \
+QEMU_AUDIO_DRV=none \
+/usr/bin/qemu \
+-name encryptdisk \
+-S \
+-object secret,id=masterKey0,format=raw,\
+file=/tmp/lib/domain--1-encryptdisk/master-key.aes \
+-M pc-i440fx-2.1 \
+-m 1024 \
+-smp 1 \
+-uuid 496898a6-e6ff-f7c8-5dc2-3cf410945ee9 \
+-nographic \
+-nodefaults \
+-monitor unix:/tmp/lib/domain--1-encryptdisk/monitor.sock,server,nowait \
+-no-acpi \
+-boot c \
+-usb \
+-object secret,id=virtio-disk0-secret0,\
+data=9eao5F8qtkGt+seB1HYivWIxbtwUu6MQtg1zpj/oDtUsPr1q8wBYM91uEHCn6j/1,\
+keyid=masterKey0,iv=AAECAwQFBgcICQoLDA0ODw==,format=base64 \
+-drive file=/storage/guest_disks/encryptdisk,key-secret=virtio-disk0-secret0,\
+format=luks,if=none,id=drive-virtio-disk0 \
+-device virtio-blk-pci,bus=pci.0,addr=0x4,drive=drive-virtio-disk0,\
+id=virtio-disk0 \
+-object secret,id=virtio-disk1-secret0,\
+data=9eao5F8qtkGt+seB1HYivWIxbtwUu6MQtg1zpj/oDtUsPr1q8wBYM91uEHCn6j/1,\
+keyid=masterKey0,iv=AAECAwQFBgcICQoLDA0ODw==,format=base64 \
+-drive file=/storage/guest_disks/encryptdisk2,key-secret=virtio-disk1-secret0,\
+format=luks,if=none,id=drive-virtio-disk1 \
+-device virtio-blk-pci,bus=pci.0,addr=0x5,drive=drive-virtio-disk1,\
+id=virtio-disk1 \
+-device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x3
diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c
index ca52ab0..aba346d 100644
--- a/tests/qemuxml2argvtest.c
+++ b/tests/qemuxml2argvtest.c
@@ -62,10 +62,17 @@ fakeSecretLookupByUsage(virConnectPtr conn,
     return virGetSecret(conn, uuid, usageType, usageID);
 }
 
+static virSecretPtr
+fakeSecretLookupByUUID(virConnectPtr conn,
+                       const unsigned char *uuid)
+{
+    return virGetSecret(conn, uuid, 0, "");
+}
+
 static virSecretDriver fakeSecretDriver = {
     .connectNumOfSecrets = NULL,
     .connectListSecrets = NULL,
-    .secretLookupByUUID = NULL,
+    .secretLookupByUUID = fakeSecretLookupByUUID,
     .secretLookupByUsage = fakeSecretLookupByUsage,
     .secretDefineXML = NULL,
     .secretGetXMLDesc = NULL,
@@ -1342,6 +1349,8 @@ mymain(void)
 
     DO_TEST("encrypted-disk", NONE);
     DO_TEST("encrypted-disk-usage", NONE);
+    DO_TEST("luks-disks", QEMU_CAPS_OBJECT_SECRET);
+    DO_TEST("luks-disk-cipher", QEMU_CAPS_OBJECT_SECRET);
 
     DO_TEST("memtune", NONE);
     DO_TEST("memtune-unlimited", NONE);
-- 
2.5.5




More information about the libvir-list mailing list