diff mbox

[v7,19/20] qcow2: report encryption specific image information

Message ID 20170525163851.8047-20-berrange@redhat.com
State New
Headers show

Commit Message

Daniel P. Berrangé May 25, 2017, 4:38 p.m. UTC
Currently 'qemu-img info' reports a simple "encrypted: yes"
field. This is not very useful now that qcow2 can support
multiple encryption formats. Users want to know which format
is in use and some data related to it.

Wire up usage of the qcrypto_block_get_info() method so that
'qemu-img info' can report about the encryption format
and parameters in use

  $ qemu-img create \
      --object secret,id=sec0,data=123456 \
      -o encrypt.format=luks,encrypt.key-secret=sec0 \
      -f qcow2 demo.qcow2 1G
  Formatting 'demo.qcow2', fmt=qcow2 size=1073741824 \
  encryption=off encrypt.format=luks encrypt.key-secret=sec0 \
  cluster_size=65536 lazy_refcounts=off refcount_bits=16

  $ qemu-img info demo.qcow2
  image: demo.qcow2
  file format: qcow2
  virtual size: 1.0G (1073741824 bytes)
  disk size: 480K
  encrypted: yes
  cluster_size: 65536
  Format specific information:
      compat: 1.1
      lazy refcounts: false
      refcount bits: 16
      encrypt:
          ivgen alg: plain64
          hash alg: sha256
          cipher alg: aes-256
          uuid: 3fa930c4-58c8-4ef7-b3c5-314bb5af21f3
          format: luks
          cipher mode: xts
          slots:
              [0]:
                  active: true
                  iters: 1839058
                  key offset: 4096
                  stripes: 4000
              [1]:
                  active: false
                  key offset: 262144
              [2]:
                  active: false
                  key offset: 520192
              [3]:
                  active: false
                  key offset: 778240
              [4]:
                  active: false
                  key offset: 1036288
              [5]:
                  active: false
                  key offset: 1294336
              [6]:
                  active: false
                  key offset: 1552384
              [7]:
                  active: false
                  key offset: 1810432
          payload offset: 2068480
          master key iters: 438487
      corrupt: false

With the legacy "AES" encryption we just report the format
name

  $ qemu-img create \
      --object secret,id=sec0,data=123456 \
      -o encrypt.format=aes,encrypt.key-secret=sec0 \
      -f qcow2 demo.qcow2 1G
  Formatting 'demo.qcow2', fmt=qcow2 size=1073741824 \
  encryption=off encrypt.format=aes encrypt.key-secret=sec0 \
  cluster_size=65536 lazy_refcounts=off refcount_bits=16

  $ ./qemu-img info demo.qcow2
  image: demo.qcow2
  file format: qcow2
  virtual size: 1.0G (1073741824 bytes)
  disk size: 196K
  encrypted: yes
  cluster_size: 65536
  Format specific information:
      compat: 1.1
      lazy refcounts: false
      refcount bits: 16
      encrypt:
          format: aes
      corrupt: false

Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
---
 block/qcow2.c        | 35 ++++++++++++++++++++++++++++++++++-
 qapi/block-core.json | 24 +++++++++++++++++++++++-
 2 files changed, 57 insertions(+), 2 deletions(-)

Comments

Eric Blake May 25, 2017, 7:52 p.m. UTC | #1
On 05/25/2017 11:38 AM, Daniel P. Berrange wrote:
> Currently 'qemu-img info' reports a simple "encrypted: yes"
> field. This is not very useful now that qcow2 can support
> multiple encryption formats. Users want to know which format
> is in use and some data related to it.
> 
> Wire up usage of the qcrypto_block_get_info() method so that
> 'qemu-img info' can report about the encryption format
> and parameters in use
> 

> Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
> ---
>  block/qcow2.c        | 35 ++++++++++++++++++++++++++++++++++-
>  qapi/block-core.json | 24 +++++++++++++++++++++++-
>  2 files changed, 57 insertions(+), 2 deletions(-)
> 
> diff --git a/block/qcow2.c b/block/qcow2.c
> index 38f9eb5..cb321a2 100644
> --- a/block/qcow2.c
> +++ b/block/qcow2.c
> @@ -3196,8 +3196,17 @@ static int qcow2_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
>  static ImageInfoSpecific *qcow2_get_specific_info(BlockDriverState *bs)
>  {
>      BDRVQcow2State *s = bs->opaque;
> -    ImageInfoSpecific *spec_info = g_new(ImageInfoSpecific, 1);
> +    ImageInfoSpecific *spec_info;
> +    QCryptoBlockInfo *encrypt_info = NULL;
>  
> +    if (s->crypto != NULL) {
> +        encrypt_info = qcrypto_block_get_info(s->crypto, NULL);

Worth using &error_abort instead of silently ignoring the error?  Is an
error even possible in our output visitor [adding Markus for reference]?

> +        if (!encrypt_info) {
> +            return NULL;
> +        }

If you use &error_abort, this is a dead check.

> +    }
> +
> +    spec_info = g_new(ImageInfoSpecific, 1);
>      *spec_info = (ImageInfoSpecific){
>          .type  = IMAGE_INFO_SPECIFIC_KIND_QCOW2,
>          .u.qcow2.data = g_new(ImageInfoSpecificQCow2, 1),
> @@ -3224,6 +3233,30 @@ static ImageInfoSpecific *qcow2_get_specific_info(BlockDriverState *bs)
>          assert(false);
>      }
>  
> +    if (encrypt_info) {
> +        ImageInfoSpecificQCow2Encryption *qencrypt =
> +            g_new(ImageInfoSpecificQCow2Encryption, 1);
> +        switch (encrypt_info->format) {
> +        case Q_CRYPTO_BLOCK_FORMAT_QCOW:
> +            qencrypt->format = BLOCKDEV_QCOW2_ENCRYPTION_FORMAT_AES;
> +            qencrypt->u.aes = encrypt_info->u.qcow;
> +            break;
> +        case Q_CRYPTO_BLOCK_FORMAT_LUKS:
> +            qencrypt->format = BLOCKDEV_QCOW2_ENCRYPTION_FORMAT_LUKS;
> +            qencrypt->u.luks = encrypt_info->u.luks;
> +            break;
> +        default:
> +            assert(false);
> +        }
> +        /* Since we did shallow copy above, erase any pointers
> +         * in the original info */
> +        memset(&encrypt_info->u, 0, sizeof(encrypt_info->u));
> +        qapi_free_QCryptoBlockInfo(encrypt_info);

Does QAPI_CLONE_MEMBERS (commit 4626a19c) make this code any easier to
write?  Then again, malloc'ing duplicates to then free the unchanged
original is a bit slower than stealing references from the original then
making sure the original can be freed without problem.

>  # @ImageInfoSpecificQCow2:
>  #
>  # @compat: compatibility level
> @@ -51,7 +72,8 @@
>        'compat': 'str',
>        '*lazy-refcounts': 'bool',
>        '*corrupt': 'bool',
> -      'refcount-bits': 'int'
> +      'refcount-bits': 'int',
> +      '*encrypt': 'ImageInfoSpecificQCow2Encryption'

Missing documentation of the @encrypt field.

Close!
Daniel P. Berrangé May 26, 2017, 2:02 p.m. UTC | #2
On Thu, May 25, 2017 at 02:52:30PM -0500, Eric Blake wrote:
> On 05/25/2017 11:38 AM, Daniel P. Berrange wrote:
> > Currently 'qemu-img info' reports a simple "encrypted: yes"
> > field. This is not very useful now that qcow2 can support
> > multiple encryption formats. Users want to know which format
> > is in use and some data related to it.
> > 
> > Wire up usage of the qcrypto_block_get_info() method so that
> > 'qemu-img info' can report about the encryption format
> > and parameters in use
> > 
> 
> > Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
> > ---
> >  block/qcow2.c        | 35 ++++++++++++++++++++++++++++++++++-
> >  qapi/block-core.json | 24 +++++++++++++++++++++++-
> >  2 files changed, 57 insertions(+), 2 deletions(-)
> > 
> > diff --git a/block/qcow2.c b/block/qcow2.c
> > index 38f9eb5..cb321a2 100644
> > --- a/block/qcow2.c
> > +++ b/block/qcow2.c
> > @@ -3196,8 +3196,17 @@ static int qcow2_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
> >  static ImageInfoSpecific *qcow2_get_specific_info(BlockDriverState *bs)
> >  {
> >      BDRVQcow2State *s = bs->opaque;
> > -    ImageInfoSpecific *spec_info = g_new(ImageInfoSpecific, 1);
> > +    ImageInfoSpecific *spec_info;
> > +    QCryptoBlockInfo *encrypt_info = NULL;
> >  
> > +    if (s->crypto != NULL) {
> > +        encrypt_info = qcrypto_block_get_info(s->crypto, NULL);
> 
> Worth using &error_abort instead of silently ignoring the error?  Is an
> error even possible in our output visitor [adding Markus for reference]?

In fact the qcrypto_block_get_info() will never return an error
right now as implemented. So I guess we could even just remove
the Error **errp parameter from that call

> 
> > +        if (!encrypt_info) {
> > +            return NULL;
> > +        }
> 
> If you use &error_abort, this is a dead check.
> 
> > +    }
> > +
> > +    spec_info = g_new(ImageInfoSpecific, 1);

> > +    if (encrypt_info) {
> > +        ImageInfoSpecificQCow2Encryption *qencrypt =
> > +            g_new(ImageInfoSpecificQCow2Encryption, 1);
> > +        switch (encrypt_info->format) {
> > +        case Q_CRYPTO_BLOCK_FORMAT_QCOW:
> > +            qencrypt->format = BLOCKDEV_QCOW2_ENCRYPTION_FORMAT_AES;
> > +            qencrypt->u.aes = encrypt_info->u.qcow;
> > +            break;
> > +        case Q_CRYPTO_BLOCK_FORMAT_LUKS:
> > +            qencrypt->format = BLOCKDEV_QCOW2_ENCRYPTION_FORMAT_LUKS;
> > +            qencrypt->u.luks = encrypt_info->u.luks;
> > +            break;
> > +        default:
> > +            assert(false);
> > +        }
> > +        /* Since we did shallow copy above, erase any pointers
> > +         * in the original info */
> > +        memset(&encrypt_info->u, 0, sizeof(encrypt_info->u));
> > +        qapi_free_QCryptoBlockInfo(encrypt_info);
> 
> Does QAPI_CLONE_MEMBERS (commit 4626a19c) make this code any easier to
> write?  Then again, malloc'ing duplicates to then free the unchanged
> original is a bit slower than stealing references from the original then
> making sure the original can be freed without problem.

I don't think CLONE would make a signijficant difference to the size
of the code, since we have to remap the enum constants regardless.

Regards,
Daniel
Markus Armbruster May 29, 2017, 9:53 a.m. UTC | #3
"Daniel P. Berrange" <berrange@redhat.com> writes:

> On Thu, May 25, 2017 at 02:52:30PM -0500, Eric Blake wrote:
>> On 05/25/2017 11:38 AM, Daniel P. Berrange wrote:
>> > Currently 'qemu-img info' reports a simple "encrypted: yes"
>> > field. This is not very useful now that qcow2 can support
>> > multiple encryption formats. Users want to know which format
>> > is in use and some data related to it.
>> > 
>> > Wire up usage of the qcrypto_block_get_info() method so that
>> > 'qemu-img info' can report about the encryption format
>> > and parameters in use
>> > 
>> 
>> > Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
>> > ---
>> >  block/qcow2.c        | 35 ++++++++++++++++++++++++++++++++++-
>> >  qapi/block-core.json | 24 +++++++++++++++++++++++-
>> >  2 files changed, 57 insertions(+), 2 deletions(-)
>> > 
>> > diff --git a/block/qcow2.c b/block/qcow2.c
>> > index 38f9eb5..cb321a2 100644
>> > --- a/block/qcow2.c
>> > +++ b/block/qcow2.c
>> > @@ -3196,8 +3196,17 @@ static int qcow2_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
>> >  static ImageInfoSpecific *qcow2_get_specific_info(BlockDriverState *bs)
>> >  {
>> >      BDRVQcow2State *s = bs->opaque;
>> > -    ImageInfoSpecific *spec_info = g_new(ImageInfoSpecific, 1);
>> > +    ImageInfoSpecific *spec_info;
>> > +    QCryptoBlockInfo *encrypt_info = NULL;
>> >  
>> > +    if (s->crypto != NULL) {
>> > +        encrypt_info = qcrypto_block_get_info(s->crypto, NULL);
>> 
>> Worth using &error_abort instead of silently ignoring the error?  Is an
>> error even possible in our output visitor [adding Markus for reference]?
>
> In fact the qcrypto_block_get_info() will never return an error
> right now as implemented. So I guess we could even just remove
> the Error **errp parameter from that call

Do you still need advice on QAPI from me here?

[...]
Daniel P. Berrangé May 30, 2017, 9:16 a.m. UTC | #4
On Mon, May 29, 2017 at 11:53:01AM +0200, Markus Armbruster wrote:
> "Daniel P. Berrange" <berrange@redhat.com> writes:
> 
> > On Thu, May 25, 2017 at 02:52:30PM -0500, Eric Blake wrote:
> >> On 05/25/2017 11:38 AM, Daniel P. Berrange wrote:
> >> > Currently 'qemu-img info' reports a simple "encrypted: yes"
> >> > field. This is not very useful now that qcow2 can support
> >> > multiple encryption formats. Users want to know which format
> >> > is in use and some data related to it.
> >> > 
> >> > Wire up usage of the qcrypto_block_get_info() method so that
> >> > 'qemu-img info' can report about the encryption format
> >> > and parameters in use
> >> > 
> >> 
> >> > Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
> >> > ---
> >> >  block/qcow2.c        | 35 ++++++++++++++++++++++++++++++++++-
> >> >  qapi/block-core.json | 24 +++++++++++++++++++++++-
> >> >  2 files changed, 57 insertions(+), 2 deletions(-)
> >> > 
> >> > diff --git a/block/qcow2.c b/block/qcow2.c
> >> > index 38f9eb5..cb321a2 100644
> >> > --- a/block/qcow2.c
> >> > +++ b/block/qcow2.c
> >> > @@ -3196,8 +3196,17 @@ static int qcow2_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
> >> >  static ImageInfoSpecific *qcow2_get_specific_info(BlockDriverState *bs)
> >> >  {
> >> >      BDRVQcow2State *s = bs->opaque;
> >> > -    ImageInfoSpecific *spec_info = g_new(ImageInfoSpecific, 1);
> >> > +    ImageInfoSpecific *spec_info;
> >> > +    QCryptoBlockInfo *encrypt_info = NULL;
> >> >  
> >> > +    if (s->crypto != NULL) {
> >> > +        encrypt_info = qcrypto_block_get_info(s->crypto, NULL);
> >> 
> >> Worth using &error_abort instead of silently ignoring the error?  Is an
> >> error even possible in our output visitor [adding Markus for reference]?
> >
> > In fact the qcrypto_block_get_info() will never return an error
> > right now as implemented. So I guess we could even just remove
> > the Error **errp parameter from that call
> 
> Do you still need advice on QAPI from me here?

No need, thanks.

Regards,
Daniel
diff mbox

Patch

diff --git a/block/qcow2.c b/block/qcow2.c
index 38f9eb5..cb321a2 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -3196,8 +3196,17 @@  static int qcow2_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
 static ImageInfoSpecific *qcow2_get_specific_info(BlockDriverState *bs)
 {
     BDRVQcow2State *s = bs->opaque;
-    ImageInfoSpecific *spec_info = g_new(ImageInfoSpecific, 1);
+    ImageInfoSpecific *spec_info;
+    QCryptoBlockInfo *encrypt_info = NULL;
 
+    if (s->crypto != NULL) {
+        encrypt_info = qcrypto_block_get_info(s->crypto, NULL);
+        if (!encrypt_info) {
+            return NULL;
+        }
+    }
+
+    spec_info = g_new(ImageInfoSpecific, 1);
     *spec_info = (ImageInfoSpecific){
         .type  = IMAGE_INFO_SPECIFIC_KIND_QCOW2,
         .u.qcow2.data = g_new(ImageInfoSpecificQCow2, 1),
@@ -3224,6 +3233,30 @@  static ImageInfoSpecific *qcow2_get_specific_info(BlockDriverState *bs)
         assert(false);
     }
 
+    if (encrypt_info) {
+        ImageInfoSpecificQCow2Encryption *qencrypt =
+            g_new(ImageInfoSpecificQCow2Encryption, 1);
+        switch (encrypt_info->format) {
+        case Q_CRYPTO_BLOCK_FORMAT_QCOW:
+            qencrypt->format = BLOCKDEV_QCOW2_ENCRYPTION_FORMAT_AES;
+            qencrypt->u.aes = encrypt_info->u.qcow;
+            break;
+        case Q_CRYPTO_BLOCK_FORMAT_LUKS:
+            qencrypt->format = BLOCKDEV_QCOW2_ENCRYPTION_FORMAT_LUKS;
+            qencrypt->u.luks = encrypt_info->u.luks;
+            break;
+        default:
+            assert(false);
+        }
+        /* Since we did shallow copy above, erase any pointers
+         * in the original info */
+        memset(&encrypt_info->u, 0, sizeof(encrypt_info->u));
+        qapi_free_QCryptoBlockInfo(encrypt_info);
+
+        spec_info->u.qcow2.data->has_encrypt = true;
+        spec_info->u.qcow2.data->encrypt = qencrypt;
+    }
+
     return spec_info;
 }
 
diff --git a/qapi/block-core.json b/qapi/block-core.json
index a4e47a1..23b8f3f 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -33,6 +33,27 @@ 
             'vm-clock-sec': 'int', 'vm-clock-nsec': 'int' } }
 
 ##
+# @ImageInfoSpecificQCow2EncryptionBase:
+#
+# @format: The encryption format
+#
+# Since: 2.10
+##
+{ 'struct': 'ImageInfoSpecificQCow2EncryptionBase',
+  'data': { 'format': 'BlockdevQcow2EncryptionFormat'}}
+
+##
+# @ImageInfoSpecificQCow2Encryption:
+#
+# Since: 2.10
+##
+{ 'union': 'ImageInfoSpecificQCow2Encryption',
+  'base': 'ImageInfoSpecificQCow2EncryptionBase',
+  'discriminator': 'format',
+  'data': { 'aes': 'QCryptoBlockInfoQCow',
+            'luks': 'QCryptoBlockInfoLUKS' } }
+
+##
 # @ImageInfoSpecificQCow2:
 #
 # @compat: compatibility level
@@ -51,7 +72,8 @@ 
       'compat': 'str',
       '*lazy-refcounts': 'bool',
       '*corrupt': 'bool',
-      'refcount-bits': 'int'
+      'refcount-bits': 'int',
+      '*encrypt': 'ImageInfoSpecificQCow2Encryption'
   } }
 
 ##