diff mbox series

[v5,3/4] crypto.c: cleanup created file when block_crypto_co_create_opts_luks fails

Message ID 20190807142114.17569-4-danielhb413@gmail.com
State New
Headers show
Series delete created files when block_crypto_co_create_opts_luks fails | expand

Commit Message

Daniel Henrique Barboza Aug. 7, 2019, 2:21 p.m. UTC
When using a non-UTF8 secret to create a volume using qemu-img, the
following error happens:

$ qemu-img create -f luks --object secret,id=vol_1_encrypt0,file=vol_resize_pool.vol_1.secret.qzVQrI -o key-secret=vol_1_encrypt0 /var/tmp/pool_target/vol_1 10240K

Formatting '/var/tmp/pool_target/vol_1', fmt=luks size=10485760 key-secret=vol_1_encrypt0
qemu-img: /var/tmp/pool_target/vol_1: Data from secret vol_1_encrypt0 is not valid UTF-8

However, the created file '/var/tmp/pool_target/vol_1' is left behind in the
file system after the failure. This behavior can be observed when creating
the volume using Libvirt, via 'virsh vol-create', and then getting "volume
target path already exist" errors when trying to re-create the volume.

The volume file is created inside block_crypto_co_create_opts_luks(), in
block/crypto.c. If the bdrv_create_file() call is successful but any
succeeding step fails*, the existing 'fail' label does not take into
account the created file, leaving it behind.

This patch changes block_crypto_co_create_opts_luks() to delete
'filename' in case of failure. A failure in this point means that
the volume is now truncated/corrupted, so even if 'filename' was an
existing volume before calling qemu-img, it is now unusable. Deleting
the file it is not much worse than leaving it in the filesystem in
this scenario, and we don't have to deal with checking the file
pre-existence in the code.

* in our case, block_crypto_co_create_generic calls qcrypto_block_create,
which calls qcrypto_block_luks_create, and this function fails when
calling qcrypto_secret_lookup_as_utf8.

Reported-by: Srikanth Aithal <bssrikanth@in.ibm.com>
Suggested-by: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com>
---
 block/crypto.c | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)

Comments

John Snow Aug. 29, 2019, 2:10 a.m. UTC | #1
On 8/7/19 10:21 AM, Daniel Henrique Barboza wrote:
> When using a non-UTF8 secret to create a volume using qemu-img, the
> following error happens:
> 
> $ qemu-img create -f luks --object secret,id=vol_1_encrypt0,file=vol_resize_pool.vol_1.secret.qzVQrI -o key-secret=vol_1_encrypt0 /var/tmp/pool_target/vol_1 10240K
> 
> Formatting '/var/tmp/pool_target/vol_1', fmt=luks size=10485760 key-secret=vol_1_encrypt0
> qemu-img: /var/tmp/pool_target/vol_1: Data from secret vol_1_encrypt0 is not valid UTF-8
> 
> However, the created file '/var/tmp/pool_target/vol_1' is left behind in the
> file system after the failure. This behavior can be observed when creating
> the volume using Libvirt, via 'virsh vol-create', and then getting "volume
> target path already exist" errors when trying to re-create the volume.
> 
> The volume file is created inside block_crypto_co_create_opts_luks(), in
> block/crypto.c. If the bdrv_create_file() call is successful but any
> succeeding step fails*, the existing 'fail' label does not take into
> account the created file, leaving it behind.
> 
> This patch changes block_crypto_co_create_opts_luks() to delete
> 'filename' in case of failure. A failure in this point means that
> the volume is now truncated/corrupted, so even if 'filename' was an
> existing volume before calling qemu-img, it is now unusable. Deleting
> the file it is not much worse than leaving it in the filesystem in
> this scenario, and we don't have to deal with checking the file
> pre-existence in the code.
> 
> * in our case, block_crypto_co_create_generic calls qcrypto_block_create,
> which calls qcrypto_block_luks_create, and this function fails when
> calling qcrypto_secret_lookup_as_utf8.
> 
> Reported-by: Srikanth Aithal <bssrikanth@in.ibm.com>
> Suggested-by: Kevin Wolf <kwolf@redhat.com>
> Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com>
> ---
>  block/crypto.c | 20 ++++++++++++++++++++
>  1 file changed, 20 insertions(+)
> 
> diff --git a/block/crypto.c b/block/crypto.c
> index 8237424ae6..8ffca81df6 100644
> --- a/block/crypto.c
> +++ b/block/crypto.c
> @@ -30,6 +30,7 @@
>  #include "qapi/error.h"
>  #include "qemu/module.h"
>  #include "qemu/option.h"
> +#include "qemu/cutils.h"
>  #include "crypto.h"
>  
>  typedef struct BlockCrypto BlockCrypto;
> @@ -575,6 +576,25 @@ fail:
>      bdrv_unref(bs);
>      qapi_free_QCryptoBlockCreateOptions(create_opts);
>      qobject_unref(cryptoopts);
> +
> +    /*
> +     * If an error occurred, delete the file. Even if the file existed
> +     * beforehand, it has been truncated and corrupted in the process.
> +     */
> +    if (ret) {
> +        Error *local_err;
> +        int r_del = bdrv_delete_file(filename, &local_err);
> +        /*
> +         * ENOTSUP will happen if the block driver doesn't support
> +         * 'bdrv_co_delete_file'. ENOENT will happen if the file
> +         * doesn't exist. Both are predictable and shouldn't be
> +         * reported back to the user.
> +         */

Hm, actually, didn't you use ENOENT to mean that we couldn't figure out
which driver to use?

> +        if ((r_del < 0) && (r_del != -ENOTSUP) && (r_del != -ENOENT)) {
> +            error_reportf_err(local_err, "%s: ", bs->filename);
> +        }> +    }
> +
>      return ret;
>  }
>  
>
Daniel Henrique Barboza Sept. 2, 2019, 6:26 p.m. UTC | #2
On 8/28/19 11:10 PM, John Snow wrote:
>
> On 8/7/19 10:21 AM, Daniel Henrique Barboza wrote:
>> When using a non-UTF8 secret to create a volume using qemu-img, the
>> following error happens:
>>
>> $ qemu-img create -f luks --object secret,id=vol_1_encrypt0,file=vol_resize_pool.vol_1.secret.qzVQrI -o key-secret=vol_1_encrypt0 /var/tmp/pool_target/vol_1 10240K
>>
>> Formatting '/var/tmp/pool_target/vol_1', fmt=luks size=10485760 key-secret=vol_1_encrypt0
>> qemu-img: /var/tmp/pool_target/vol_1: Data from secret vol_1_encrypt0 is not valid UTF-8
>>
>> However, the created file '/var/tmp/pool_target/vol_1' is left behind in the
>> file system after the failure. This behavior can be observed when creating
>> the volume using Libvirt, via 'virsh vol-create', and then getting "volume
>> target path already exist" errors when trying to re-create the volume.
>>
>> The volume file is created inside block_crypto_co_create_opts_luks(), in
>> block/crypto.c. If the bdrv_create_file() call is successful but any
>> succeeding step fails*, the existing 'fail' label does not take into
>> account the created file, leaving it behind.
>>
>> This patch changes block_crypto_co_create_opts_luks() to delete
>> 'filename' in case of failure. A failure in this point means that
>> the volume is now truncated/corrupted, so even if 'filename' was an
>> existing volume before calling qemu-img, it is now unusable. Deleting
>> the file it is not much worse than leaving it in the filesystem in
>> this scenario, and we don't have to deal with checking the file
>> pre-existence in the code.
>>
>> * in our case, block_crypto_co_create_generic calls qcrypto_block_create,
>> which calls qcrypto_block_luks_create, and this function fails when
>> calling qcrypto_secret_lookup_as_utf8.
>>
>> Reported-by: Srikanth Aithal <bssrikanth@in.ibm.com>
>> Suggested-by: Kevin Wolf <kwolf@redhat.com>
>> Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com>
>> ---
>>   block/crypto.c | 20 ++++++++++++++++++++
>>   1 file changed, 20 insertions(+)
>>
>> diff --git a/block/crypto.c b/block/crypto.c
>> index 8237424ae6..8ffca81df6 100644
>> --- a/block/crypto.c
>> +++ b/block/crypto.c
>> @@ -30,6 +30,7 @@
>>   #include "qapi/error.h"
>>   #include "qemu/module.h"
>>   #include "qemu/option.h"
>> +#include "qemu/cutils.h"
>>   #include "crypto.h"
>>   
>>   typedef struct BlockCrypto BlockCrypto;
>> @@ -575,6 +576,25 @@ fail:
>>       bdrv_unref(bs);
>>       qapi_free_QCryptoBlockCreateOptions(create_opts);
>>       qobject_unref(cryptoopts);
>> +
>> +    /*
>> +     * If an error occurred, delete the file. Even if the file existed
>> +     * beforehand, it has been truncated and corrupted in the process.
>> +     */
>> +    if (ret) {
>> +        Error *local_err;
>> +        int r_del = bdrv_delete_file(filename, &local_err);
>> +        /*
>> +         * ENOTSUP will happen if the block driver doesn't support
>> +         * 'bdrv_co_delete_file'. ENOENT will happen if the file
>> +         * doesn't exist. Both are predictable and shouldn't be
>> +         * reported back to the user.
>> +         */
> Hm, actually, didn't you use ENOENT to mean that we couldn't figure out
> which driver to use?


True. In this context though I am referring to the co_routine function
that deletes the file:

-------
(file-posix.c)
static int coroutine_fn raw_co_delete_file(BlockDriverState *bs,
                                            Error **errp)
{
     struct stat st;
     int ret;

     if (!(stat(bs->filename, &st) == 0) || !S_ISREG(st.st_mode)) {
         ret = -ENOENT;
         error_setg_errno(errp, -ret, "%s is not a regular file",
                          bs->filename);
         goto done;
     }
(...)
-----


I'll make it clearer in the comment where ENOENT is coming from.

(In fact, this is a good reason to change the !drv error in patch 2 from
ENOENT to ENOMEDIUM ....)







>
>> +        if ((r_del < 0) && (r_del != -ENOTSUP) && (r_del != -ENOENT)) {
>> +            error_reportf_err(local_err, "%s: ", bs->filename);
>> +        }> +    }
>> +
>>       return ret;
>>   }
>>   
>>
diff mbox series

Patch

diff --git a/block/crypto.c b/block/crypto.c
index 8237424ae6..8ffca81df6 100644
--- a/block/crypto.c
+++ b/block/crypto.c
@@ -30,6 +30,7 @@ 
 #include "qapi/error.h"
 #include "qemu/module.h"
 #include "qemu/option.h"
+#include "qemu/cutils.h"
 #include "crypto.h"
 
 typedef struct BlockCrypto BlockCrypto;
@@ -575,6 +576,25 @@  fail:
     bdrv_unref(bs);
     qapi_free_QCryptoBlockCreateOptions(create_opts);
     qobject_unref(cryptoopts);
+
+    /*
+     * If an error occurred, delete the file. Even if the file existed
+     * beforehand, it has been truncated and corrupted in the process.
+     */
+    if (ret) {
+        Error *local_err;
+        int r_del = bdrv_delete_file(filename, &local_err);
+        /*
+         * ENOTSUP will happen if the block driver doesn't support
+         * 'bdrv_co_delete_file'. ENOENT will happen if the file
+         * doesn't exist. Both are predictable and shouldn't be
+         * reported back to the user.
+         */
+        if ((r_del < 0) && (r_del != -ENOTSUP) && (r_del != -ENOENT)) {
+            error_reportf_err(local_err, "%s: ", bs->filename);
+        }
+    }
+
     return ret;
 }