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