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