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