edecca
From a882d10a1eaa02210e048f4a00917c8b30b0c4e6 Mon Sep 17 00:00:00 2001
edecca
Message-Id: <a882d10a1eaa02210e048f4a00917c8b30b0c4e6@dist-git>
edecca
From: John Ferlan <jferlan@redhat.com>
edecca
Date: Fri, 2 Nov 2018 16:57:12 +0100
edecca
Subject: [PATCH] storage: Allow inputvol to be encrypted
edecca
edecca
https://bugzilla.redhat.com/show_bug.cgi?id=1613737
edecca
edecca
When processing the inputvol for encryption, we need to handle
edecca
the case where the inputvol is encrypted. This then allows for
edecca
the encrypted inputvol to be used either for an output encrypted
edecca
volume or an output volume of some XML provided type.
edecca
edecca
Add tests to show the various conversion options when either input
edecca
or output is encrypted. This includes when both are encrypted.
edecca
edecca
Signed-off-by: John Ferlan <jferlan@redhat.com>
edecca
ACKed-by: Michal Privoznik <mprivozn@redhat.com>
edecca
(cherry picked from commit b975afc72504e636ec538ea119bee9a0cd7b63d8)
edecca
edecca
https://bugzilla.redhat.com/show_bug.cgi?id=1645459
edecca
edecca
Signed-off-by: Andrea Bolognani <abologna@redhat.com>
edecca
Reviewed-by: Jiri Denemark <jdenemar@redhat.com>
edecca
---
edecca
 src/storage/storage_util.c                    | 64 ++++++++++++++++---
edecca
 src/storage/storage_util.h                    |  1 +
edecca
 .../luks-convert-encrypt.argv                 | 11 ++++
edecca
 .../luks-convert-encrypt2fileqcow2.argv       |  7 ++
edecca
 .../luks-convert-encrypt2fileraw.argv         |  7 ++
edecca
 tests/storagevolxml2argvtest.c                | 15 ++++-
edecca
 tests/storagevolxml2xmlin/vol-encrypt1.xml    | 21 ++++++
edecca
 tests/storagevolxml2xmlin/vol-encrypt2.xml    | 21 ++++++
edecca
 8 files changed, 138 insertions(+), 9 deletions(-)
edecca
 create mode 100644 tests/storagevolxml2argvdata/luks-convert-encrypt.argv
edecca
 create mode 100644 tests/storagevolxml2argvdata/luks-convert-encrypt2fileqcow2.argv
edecca
 create mode 100644 tests/storagevolxml2argvdata/luks-convert-encrypt2fileraw.argv
edecca
 create mode 100644 tests/storagevolxml2xmlin/vol-encrypt1.xml
edecca
 create mode 100644 tests/storagevolxml2xmlin/vol-encrypt2.xml
edecca
edecca
diff --git a/src/storage/storage_util.c b/src/storage/storage_util.c
edecca
index c5e773ab6d..90a02d19df 100644
edecca
--- a/src/storage/storage_util.c
edecca
+++ b/src/storage/storage_util.c
edecca
@@ -1077,6 +1077,7 @@ virStorageBackendCreateQemuImgCmdFromVol(virStoragePoolObjPtr pool,
edecca
                                          unsigned int flags,
edecca
                                          const char *create_tool,
edecca
                                          const char *secretPath,
edecca
+                                         const char *inputSecretPath,
edecca
                                          virStorageVolEncryptConvertStep convertStep)
edecca
 {
edecca
     virCommandPtr cmd = NULL;
edecca
@@ -1094,6 +1095,8 @@ virStorageBackendCreateQemuImgCmdFromVol(virStoragePoolObjPtr pool,
edecca
         .secretAlias = NULL,
edecca
     };
edecca
     virStorageEncryptionPtr enc = vol->target.encryption;
edecca
+    char *inputSecretAlias = NULL;
edecca
+    virStorageEncryptionPtr inputenc = inputvol ? inputvol->target.encryption : NULL;
edecca
     virStorageEncryptionInfoDefPtr encinfo = NULL;
edecca
 
edecca
     virCheckFlags(VIR_STORAGE_VOL_CREATE_PREALLOC_METADATA, NULL);
edecca
@@ -1107,6 +1110,12 @@ virStorageBackendCreateQemuImgCmdFromVol(virStoragePoolObjPtr pool,
edecca
         goto error;
edecca
     }
edecca
 
edecca
+    if (inputenc && inputenc->format != VIR_STORAGE_ENCRYPTION_FORMAT_LUKS) {
edecca
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
edecca
+                       _("encryption format of inputvol must be LUKS"));
edecca
+        goto error;
edecca
+    }
edecca
+
edecca
     if (virStorageBackendCreateQemuImgSetInfo(pool, vol, inputvol,
edecca
                                               convertStep, &info) < 0)
edecca
         goto error;
edecca
@@ -1146,6 +1155,20 @@ virStorageBackendCreateQemuImgCmdFromVol(virStoragePoolObjPtr pool,
edecca
         encinfo = &enc->encinfo;
edecca
     }
edecca
 
edecca
+    if (inputenc && convertStep == VIR_STORAGE_VOL_ENCRYPT_CONVERT) {
edecca
+        if (!inputSecretPath) {
edecca
+            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
edecca
+                           _("path to inputvol secret data file is required"));
edecca
+            goto error;
edecca
+        }
edecca
+        if (virAsprintf(&inputSecretAlias, "%s_encrypt0",
edecca
+                        inputvol->name) < 0)
edecca
+            goto error;
edecca
+        if (storageBackendCreateQemuImgSecretObject(cmd, inputSecretPath,
edecca
+                                                    inputSecretAlias) < 0)
edecca
+            goto error;
edecca
+    }
edecca
+
edecca
     if (convertStep != VIR_STORAGE_VOL_ENCRYPT_CONVERT) {
edecca
         if (storageBackendCreateQemuImgSetOptions(cmd, encinfo, info) < 0)
edecca
             goto error;
edecca
@@ -1156,20 +1179,33 @@ virStorageBackendCreateQemuImgCmdFromVol(virStoragePoolObjPtr pool,
edecca
             virCommandAddArgFormat(cmd, "%lluK", info.size_arg);
edecca
     } else {
edecca
         /* source */
edecca
-        virCommandAddArgFormat(cmd, "driver=%s,file.filename=%s",
edecca
-                               info.inputType ? info.inputType : "raw",
edecca
-                               info.inputPath);
edecca
+        if (inputenc)
edecca
+            virCommandAddArgFormat(cmd,
edecca
+                                   "driver=luks,file.filename=%s,key-secret=%s",
edecca
+                                   info.inputPath, inputSecretAlias);
edecca
+        else
edecca
+            virCommandAddArgFormat(cmd, "driver=%s,file.filename=%s",
edecca
+                                   info.inputType ? info.inputType : "raw",
edecca
+                                   info.inputPath);
edecca
 
edecca
         /* dest */
edecca
-        virCommandAddArgFormat(cmd, "driver=%s,file.filename=%s,key-secret=%s",
edecca
-                               info.type, info.path, info.secretAlias);
edecca
+        if (enc)
edecca
+            virCommandAddArgFormat(cmd,
edecca
+                                   "driver=%s,file.filename=%s,key-secret=%s",
edecca
+                                   info.type, info.path, info.secretAlias);
edecca
+        else
edecca
+            virCommandAddArgFormat(cmd, "driver=%s,file.filename=%s",
edecca
+                                   info.type, info.path);
edecca
+
edecca
     }
edecca
     VIR_FREE(info.secretAlias);
edecca
+    VIR_FREE(inputSecretAlias);
edecca
 
edecca
     return cmd;
edecca
 
edecca
  error:
edecca
     VIR_FREE(info.secretAlias);
edecca
+    VIR_FREE(inputSecretAlias);
edecca
     virCommandFree(cmd);
edecca
     return NULL;
edecca
 }
edecca
@@ -1255,6 +1291,7 @@ storageBackendDoCreateQemuImg(virStoragePoolObjPtr pool,
edecca
                               unsigned int flags,
edecca
                               const char *create_tool,
edecca
                               const char *secretPath,
edecca
+                              const char *inputSecretPath,
edecca
                               virStorageVolEncryptConvertStep convertStep)
edecca
 {
edecca
     int ret;
edecca
@@ -1262,7 +1299,8 @@ storageBackendDoCreateQemuImg(virStoragePoolObjPtr pool,
edecca
 
edecca
     cmd = virStorageBackendCreateQemuImgCmdFromVol(pool, vol, inputvol,
edecca
                                                    flags, create_tool,
edecca
-                                                   secretPath, convertStep);
edecca
+                                                   secretPath, inputSecretPath,
edecca
+                                                   convertStep);
edecca
     if (!cmd)
edecca
         return -1;
edecca
 
edecca
@@ -1283,6 +1321,7 @@ storageBackendCreateQemuImg(virStoragePoolObjPtr pool,
edecca
     int ret = -1;
edecca
     char *create_tool;
edecca
     char *secretPath = NULL;
edecca
+    char *inputSecretPath = NULL;
edecca
     virStorageVolEncryptConvertStep convertStep = VIR_STORAGE_VOL_ENCRYPT_NONE;
edecca
 
edecca
     virCheckFlags(VIR_STORAGE_VOL_CREATE_PREALLOC_METADATA, -1);
edecca
@@ -1299,16 +1338,21 @@ storageBackendCreateQemuImg(virStoragePoolObjPtr pool,
edecca
         !(secretPath = storageBackendCreateQemuImgSecretPath(pool, vol)))
edecca
         goto cleanup;
edecca
 
edecca
+    if (inputvol && inputvol->target.encryption &&
edecca
+        !(inputSecretPath = storageBackendCreateQemuImgSecretPath(pool,
edecca
+                                                                  inputvol)))
edecca
+        goto cleanup;
edecca
+
edecca
     /* Using an input file for encryption requires a multi-step process
edecca
      * to create an image of the same size as the inputvol and then to
edecca
      * convert the inputvol afterwards. */
edecca
-    if (secretPath && inputvol)
edecca
+    if ((secretPath || inputSecretPath) && inputvol)
edecca
         convertStep = VIR_STORAGE_VOL_ENCRYPT_CREATE;
edecca
 
edecca
     do {
edecca
         ret = storageBackendDoCreateQemuImg(pool, vol, inputvol, flags,
edecca
                                             create_tool, secretPath,
edecca
-                                            convertStep);
edecca
+                                            inputSecretPath, convertStep);
edecca
 
edecca
         /* Failure to convert, attempt to delete what we created */
edecca
         if (ret < 0 && convertStep == VIR_STORAGE_VOL_ENCRYPT_CONVERT)
edecca
@@ -1330,6 +1374,10 @@ storageBackendCreateQemuImg(virStoragePoolObjPtr pool,
edecca
         unlink(secretPath);
edecca
         VIR_FREE(secretPath);
edecca
     }
edecca
+    if (inputSecretPath) {
edecca
+        unlink(inputSecretPath);
edecca
+        VIR_FREE(inputSecretPath);
edecca
+    }
edecca
     VIR_FREE(create_tool);
edecca
     return ret;
edecca
 }
edecca
diff --git a/src/storage/storage_util.h b/src/storage/storage_util.h
edecca
index 6fc8e8972c..58b991c772 100644
edecca
--- a/src/storage/storage_util.h
edecca
+++ b/src/storage/storage_util.h
edecca
@@ -167,6 +167,7 @@ virStorageBackendCreateQemuImgCmdFromVol(virStoragePoolObjPtr pool,
edecca
                                          unsigned int flags,
edecca
                                          const char *create_tool,
edecca
                                          const char *secretPath,
edecca
+                                         const char *inputSecretPath,
edecca
                                          virStorageVolEncryptConvertStep convertStep);
edecca
 
edecca
 int virStorageBackendSCSIFindLUs(virStoragePoolObjPtr pool,
edecca
diff --git a/tests/storagevolxml2argvdata/luks-convert-encrypt.argv b/tests/storagevolxml2argvdata/luks-convert-encrypt.argv
edecca
new file mode 100644
edecca
index 0000000000..b2ad16b7cb
edecca
--- /dev/null
edecca
+++ b/tests/storagevolxml2argvdata/luks-convert-encrypt.argv
edecca
@@ -0,0 +1,11 @@
edecca
+qemu-img create -f luks \
edecca
+--object secret,id=encrypt2.img_encrypt0,file=/path/to/secretFile \
edecca
+-o key-secret=encrypt2.img_encrypt0 \
edecca
+/var/lib/libvirt/images/encrypt2.img 5242880K
edecca
+qemu-img convert --image-opts -n --target-image-opts \
edecca
+--object secret,id=encrypt2.img_encrypt0,file=/path/to/secretFile \
edecca
+--object secret,id=encrypt1.img_encrypt0,file=/path/to/inputSecretFile \
edecca
+driver=luks,file.filename=/var/lib/libvirt/images/encrypt1.img,\
edecca
+key-secret=encrypt1.img_encrypt0 \
edecca
+driver=luks,file.filename=/var/lib/libvirt/images/encrypt2.img,\
edecca
+key-secret=encrypt2.img_encrypt0
edecca
diff --git a/tests/storagevolxml2argvdata/luks-convert-encrypt2fileqcow2.argv b/tests/storagevolxml2argvdata/luks-convert-encrypt2fileqcow2.argv
edecca
new file mode 100644
edecca
index 0000000000..82cb364b61
edecca
--- /dev/null
edecca
+++ b/tests/storagevolxml2argvdata/luks-convert-encrypt2fileqcow2.argv
edecca
@@ -0,0 +1,7 @@
edecca
+qemu-img create -f qcow2 \
edecca
+-o compat=0.10 /var/lib/libvirt/images/sparse-qcow2.img 1073741824K
edecca
+qemu-img convert --image-opts -n --target-image-opts \
edecca
+--object secret,id=encrypt2.img_encrypt0,file=/path/to/inputSecretFile \
edecca
+driver=luks,file.filename=/var/lib/libvirt/images/encrypt2.img,\
edecca
+key-secret=encrypt2.img_encrypt0 \
edecca
+driver=qcow2,file.filename=/var/lib/libvirt/images/sparse-qcow2.img
edecca
diff --git a/tests/storagevolxml2argvdata/luks-convert-encrypt2fileraw.argv b/tests/storagevolxml2argvdata/luks-convert-encrypt2fileraw.argv
edecca
new file mode 100644
edecca
index 0000000000..2661c345a8
edecca
--- /dev/null
edecca
+++ b/tests/storagevolxml2argvdata/luks-convert-encrypt2fileraw.argv
edecca
@@ -0,0 +1,7 @@
edecca
+qemu-img create -f raw \
edecca
+/var/lib/libvirt/images/sparse.img 1073741824K
edecca
+qemu-img convert --image-opts -n --target-image-opts \
edecca
+--object secret,id=encrypt2.img_encrypt0,file=/path/to/inputSecretFile \
edecca
+driver=luks,file.filename=/var/lib/libvirt/images/encrypt2.img,\
edecca
+key-secret=encrypt2.img_encrypt0 \
edecca
+driver=raw,file.filename=/var/lib/libvirt/images/sparse.img
edecca
diff --git a/tests/storagevolxml2argvtest.c b/tests/storagevolxml2argvtest.c
edecca
index 6a9a080dd1..105705f348 100644
edecca
--- a/tests/storagevolxml2argvtest.c
edecca
+++ b/tests/storagevolxml2argvtest.c
edecca
@@ -85,7 +85,7 @@ testCompareXMLToArgvFiles(bool shouldFail,
edecca
      * convert the inputvol afterwards. Since we only care about the
edecca
      * command line we have to copy code from storageBackendCreateQemuImg
edecca
      * and adjust it for the test needs. */
edecca
-    if (inputvol && vol->target.encryption)
edecca
+    if (inputvol && (vol->target.encryption || inputvol->target.encryption))
edecca
         convertStep = VIR_STORAGE_VOL_ENCRYPT_CREATE;
edecca
 
edecca
     do {
edecca
@@ -93,6 +93,7 @@ testCompareXMLToArgvFiles(bool shouldFail,
edecca
                                                        inputvol, flags,
edecca
                                                        create_tool,
edecca
                                                        "/path/to/secretFile",
edecca
+                                                       "/path/to/inputSecretFile",
edecca
                                                        convertStep);
edecca
         if (!cmd) {
edecca
             if (shouldFail) {
edecca
@@ -288,6 +289,18 @@ mymain(void)
edecca
             "pool-dir", "vol-file-qcow2",
edecca
             "luks-convert-qcow2", 0);
edecca
 
edecca
+    DO_TEST("pool-dir", "vol-encrypt2",
edecca
+            "pool-dir", "vol-encrypt1",
edecca
+            "luks-convert-encrypt", 0);
edecca
+
edecca
+    DO_TEST("pool-dir", "vol-file",
edecca
+            "pool-dir", "vol-encrypt2",
edecca
+            "luks-convert-encrypt2fileraw", 0);
edecca
+
edecca
+    DO_TEST("pool-dir", "vol-file-qcow2",
edecca
+            "pool-dir", "vol-encrypt2",
edecca
+            "luks-convert-encrypt2fileqcow2", 0);
edecca
+
edecca
     return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
edecca
 }
edecca
 
edecca
diff --git a/tests/storagevolxml2xmlin/vol-encrypt1.xml b/tests/storagevolxml2xmlin/vol-encrypt1.xml
edecca
new file mode 100644
edecca
index 0000000000..681734dc7b
edecca
--- /dev/null
edecca
+++ b/tests/storagevolxml2xmlin/vol-encrypt1.xml
edecca
@@ -0,0 +1,21 @@
edecca
+<volume>
edecca
+  <name>encrypt1.img</name>
edecca
+  <key>/var/lib/libvirt/images/encrypt1.img</key>
edecca
+  <source>
edecca
+  </source>
edecca
+  <capacity unit="G">5</capacity>
edecca
+  <allocation>294912</allocation>
edecca
+  <target>
edecca
+    <path>/var/lib/libvirt/images/encrypt1.img</path>
edecca
+    <format type='raw'/>
edecca
+    <permissions>
edecca
+      <mode>0644</mode>
edecca
+      <owner>0</owner>
edecca
+      <group>0</group>
edecca
+      <label>unconfined_u:object_r:virt_image_t:s0</label>
edecca
+    </permissions>
edecca
+    <encryption format='luks'>
edecca
+      <secret type='passphrase' uuid='e78d4b51-a2af-485f-b0f5-afca709a80f4'/>
edecca
+    </encryption>
edecca
+  </target>
edecca
+</volume>
edecca
diff --git a/tests/storagevolxml2xmlin/vol-encrypt2.xml b/tests/storagevolxml2xmlin/vol-encrypt2.xml
edecca
new file mode 100644
edecca
index 0000000000..0507d3b9e6
edecca
--- /dev/null
edecca
+++ b/tests/storagevolxml2xmlin/vol-encrypt2.xml
edecca
@@ -0,0 +1,21 @@
edecca
+<volume>
edecca
+  <name>encrypt2.img</name>
edecca
+  <key>/var/lib/libvirt/images/encrypt2.img</key>
edecca
+  <source>
edecca
+  </source>
edecca
+  <capacity unit="G">5</capacity>
edecca
+  <allocation>294912</allocation>
edecca
+  <target>
edecca
+    <path>/var/lib/libvirt/images/encrypt2.img</path>
edecca
+    <format type='raw'/>
edecca
+    <permissions>
edecca
+      <mode>0644</mode>
edecca
+      <owner>0</owner>
edecca
+      <group>0</group>
edecca
+      <label>unconfined_u:object_r:virt_image_t:s0</label>
edecca
+    </permissions>
edecca
+    <encryption format='luks'>
edecca
+      <secret type='passphrase' uuid='e78d4b51-a2af-485f-b0f5-afca709af480'/>
edecca
+    </encryption>
edecca
+  </target>
edecca
+</volume>
edecca
-- 
edecca
2.19.1
edecca