RE: [PATCH v1 1/1] virtio-block: switch to blk_get_max_hw_transfer

2023-01-30 Thread Or Ozeri

> -Original Message-
> From: Kevin Wolf 
> Sent: Friday, 13 January 2023 13:45
> To: Ilya Dryomov 
> Cc: Or Ozeri ; qemu-de...@nongnu.org;
> dupad...@redhat.com; to.my.troc...@gmail.com; qemu-
> bl...@nongnu.org; Danny Harnik ; Stefan Hajnoczi
> ; Paolo Bonzini 
> Subject: [EXTERNAL] Re: [PATCH v1 1/1] virtio-block: switch to
> blk_get_max_hw_transfer
> > 
> I'm not sure I understand. This is not a passthrough device (unlike scsi-
> generic), so why should we consider the hardware limits rather than the
> kernel/other backend limits for read/write requests?

I don't understand much about it as well :)
But anyway, this bug was tested on 6.1.0, and Ilya suggested that I will test 
it on newer versions.
After doing that, I found out that the bug is not reproduceable in 6.1.1.
The commit that fixed things in 6.1.1 is this:
block: introduce max_hw_iov for use in scsi-generic
https://lists.gnu.org/archive/html/qemu-block/2021-09/msg00807.html

I guess we can just discard this thread.

Thanks,
Or


[PATCH v5 3/3] block/rbd: Add support for layered encryption

2023-01-15 Thread Or Ozeri
Starting from ceph Reef, RBD has built-in support for layered encryption,
where each ancestor image (in a cloned image setting) can be possibly
encrypted using a unique passphrase.

A new function, rbd_encryption_load2, was added to librbd API.
This new function supports an array of passphrases (via "spec" structs).

This commit extends the qemu rbd driver API to use this new librbd API,
in order to support this new layered encryption feature.

Signed-off-by: Or Ozeri 
---
 block/rbd.c  | 154 ++-
 qapi/block-core.json |  11 +++-
 2 files changed, 163 insertions(+), 2 deletions(-)

diff --git a/block/rbd.c b/block/rbd.c
index b929378871..c8418a8057 100644
--- a/block/rbd.c
+++ b/block/rbd.c
@@ -71,6 +71,16 @@ static const char rbd_luks2_header_verification[
 'L', 'U', 'K', 'S', 0xBA, 0xBE, 0, 2
 };
 
+static const char rbd_layered_luks_header_verification[
+RBD_ENCRYPTION_LUKS_HEADER_VERIFICATION_LEN] = {
+'R', 'B', 'D', 'L', 0xBA, 0xBE, 0, 1
+};
+
+static const char rbd_layered_luks2_header_verification[
+RBD_ENCRYPTION_LUKS_HEADER_VERIFICATION_LEN] = {
+'R', 'B', 'D', 'L', 0xBA, 0xBE, 0, 2
+};
+
 typedef enum {
 RBD_AIO_READ,
 RBD_AIO_WRITE,
@@ -537,6 +547,129 @@ static int qemu_rbd_encryption_load(rbd_image_t image,
 
 return 0;
 }
+
+#ifdef LIBRBD_SUPPORTS_ENCRYPTION_LOAD2
+static int qemu_rbd_encryption_load2(rbd_image_t image,
+ RbdEncryptionOptions *encrypt,
+ Error **errp)
+{
+int r = 0;
+int encrypt_count = 1;
+int i;
+RbdEncryptionOptions *curr_encrypt;
+rbd_encryption_spec_t *specs;
+rbd_encryption_luks1_format_options_t *luks_opts;
+rbd_encryption_luks2_format_options_t *luks2_opts;
+rbd_encryption_luks_format_options_t *luks_any_opts;
+
+/* count encryption options */
+for (curr_encrypt = encrypt; curr_encrypt->parent;
+ curr_encrypt = curr_encrypt->parent) {
+++encrypt_count;
+}
+
+specs = g_new0(rbd_encryption_spec_t, encrypt_count);
+
+curr_encrypt = encrypt;
+for (i = 0; i < encrypt_count; ++i) {
+switch (curr_encrypt->format) {
+case RBD_IMAGE_ENCRYPTION_FORMAT_LUKS: {
+specs[i].format = RBD_ENCRYPTION_FORMAT_LUKS1;
+
+luks_opts = g_new0(rbd_encryption_luks1_format_options_t, 1);
+specs[i].opts = luks_opts;
+specs[i].opts_size = sizeof(*luks_opts);
+
+r = qemu_rbd_convert_luks_options(
+qapi_RbdEncryptionOptionsLUKS_base(
+&curr_encrypt->u.luks),
+(char **)&luks_opts->passphrase,
+&luks_opts->passphrase_size,
+errp);
+break;
+}
+case RBD_IMAGE_ENCRYPTION_FORMAT_LUKS2: {
+specs[i].format = RBD_ENCRYPTION_FORMAT_LUKS2;
+
+luks2_opts = g_new0(rbd_encryption_luks2_format_options_t, 1);
+specs[i].opts = luks2_opts;
+specs[i].opts_size = sizeof(*luks2_opts);
+
+r = qemu_rbd_convert_luks_options(
+qapi_RbdEncryptionOptionsLUKS2_base(
+&curr_encrypt->u.luks2),
+(char **)&luks2_opts->passphrase,
+&luks2_opts->passphrase_size,
+errp);
+break;
+}
+case RBD_IMAGE_ENCRYPTION_FORMAT_LUKS_ANY: {
+specs[i].format = RBD_ENCRYPTION_FORMAT_LUKS;
+
+luks_any_opts = g_new0(rbd_encryption_luks_format_options_t, 
1);
+specs[i].opts = luks_any_opts;
+specs[i].opts_size = sizeof(*luks_any_opts);
+
+r = qemu_rbd_convert_luks_options(
+qapi_RbdEncryptionOptionsLUKSAny_base(
+&curr_encrypt->u.luks_any),
+(char **)&luks_any_opts->passphrase,
+&luks_any_opts->passphrase_size,
+errp);
+break;
+}
+
+default: {
+r = -ENOTSUP;
+error_setg_errno(
+errp, -r, "unknown image encryption format: %u",
+curr_encrypt->format);
+}
+}
+
+if (r < 0) {
+goto exit;
+}
+
+curr_encrypt = curr_encrypt->parent;
+}
+
+r = rbd_encryption_load2(image, specs, encrypt_count);
+if (r < 0) {
+error_setg_errno(errp, -r, "layered encryption load fail");
+goto exit;
+}
+
+exi

[PATCH v5 0/3] block/rbd: Add support for layered encryption

2023-01-15 Thread Or Ozeri
v5: nit fixes
v4: split to multiple commits
add support for more than just luks-any in layered encryption
nit fixes
v3: further nit fixes suggested by @idryomov
v2: nit fixes suggested by @idryomov

Or Ozeri (3):
  block/rbd: Remove redundant stack variable passphrase_len
  block/rbd: Add luks-any encryption opening option
  block/rbd: Add support for layered encryption

 block/rbd.c  | 189 ---
 qapi/block-core.json |  31 ++-
 2 files changed, 206 insertions(+), 14 deletions(-)

-- 
2.25.1




[PATCH v5 2/3] block/rbd: Add luks-any encryption opening option

2023-01-15 Thread Or Ozeri
Ceph RBD encryption API required specifying the encryption format
for loading encryption. The supported formats were LUKS (v1) and LUKS2.

Starting from Reef release, RBD also supports loading with "luks-any" format,
which works for both versions of LUKS.

This commit extends the qemu rbd driver API to enable qemu users to use
this luks-any wildcard format.

Signed-off-by: Or Ozeri 
---
 block/rbd.c  | 19 +++
 qapi/block-core.json | 20 ++--
 2 files changed, 37 insertions(+), 2 deletions(-)

diff --git a/block/rbd.c b/block/rbd.c
index cfec0f2862..b929378871 100644
--- a/block/rbd.c
+++ b/block/rbd.c
@@ -468,6 +468,9 @@ static int qemu_rbd_encryption_load(rbd_image_t image,
 g_autofree char *passphrase = NULL;
 rbd_encryption_luks1_format_options_t luks_opts;
 rbd_encryption_luks2_format_options_t luks2_opts;
+#ifdef LIBRBD_SUPPORTS_ENCRYPTION_LOAD2
+rbd_encryption_luks_format_options_t luks_any_opts;
+#endif
 rbd_encryption_format_t format;
 rbd_encryption_options_t opts;
 size_t opts_size;
@@ -501,6 +504,22 @@ static int qemu_rbd_encryption_load(rbd_image_t image,
 luks2_opts.passphrase = passphrase;
 break;
 }
+#ifdef LIBRBD_SUPPORTS_ENCRYPTION_LOAD2
+case RBD_IMAGE_ENCRYPTION_FORMAT_LUKS_ANY: {
+memset(&luks_any_opts, 0, sizeof(luks_any_opts));
+format = RBD_ENCRYPTION_FORMAT_LUKS;
+opts = &luks_any_opts;
+opts_size = sizeof(luks_any_opts);
+r = qemu_rbd_convert_luks_options(
+
qapi_RbdEncryptionOptionsLUKSAny_base(&encrypt->u.luks_any),
+&passphrase, &luks_any_opts.passphrase_size, errp);
+if (r < 0) {
+return r;
+}
+luks_any_opts.passphrase = passphrase;
+break;
+}
+#endif
 default: {
 r = -ENOTSUP;
 error_setg_errno(
diff --git a/qapi/block-core.json b/qapi/block-core.json
index 95ac4fa634..e59fb5d453 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -3827,10 +3827,16 @@
 ##
 # @RbdImageEncryptionFormat:
 #
+# luks
+#
+# luks2
+#
+# luks-any: Used for opening either luks or luks2. (Since 8.0)
+#
 # Since: 6.1
 ##
 { 'enum': 'RbdImageEncryptionFormat',
-  'data': [ 'luks', 'luks2' ] }
+  'data': [ 'luks', 'luks2', 'luks-any' ] }
 
 ##
 # @RbdEncryptionOptionsLUKSBase:
@@ -3872,6 +3878,15 @@
   'base': 'RbdEncryptionOptionsLUKSBase',
   'data': { } }
 
+##
+# @RbdEncryptionOptionsLUKSAny:
+#
+# Since: 8.0
+##
+{ 'struct': 'RbdEncryptionOptionsLUKSAny',
+  'base': 'RbdEncryptionOptionsLUKSBase',
+  'data': { } }
+
 ##
 # @RbdEncryptionCreateOptionsLUKS:
 #
@@ -3899,7 +3914,8 @@
   'base': { 'format': 'RbdImageEncryptionFormat' },
   'discriminator': 'format',
   'data': { 'luks': 'RbdEncryptionOptionsLUKS',
-'luks2': 'RbdEncryptionOptionsLUKS2' } }
+'luks2': 'RbdEncryptionOptionsLUKS2',
+'luks-any': 'RbdEncryptionOptionsLUKSAny'} }
 
 ##
 # @RbdEncryptionCreateOptions:
-- 
2.25.1




[PATCH v5 1/3] block/rbd: Remove redundant stack variable passphrase_len

2023-01-15 Thread Or Ozeri
Signed-off-by: Or Ozeri 
---
 block/rbd.c | 16 ++--
 1 file changed, 6 insertions(+), 10 deletions(-)

diff --git a/block/rbd.c b/block/rbd.c
index 3aa6aae0e0..cfec0f2862 100644
--- a/block/rbd.c
+++ b/block/rbd.c
@@ -385,7 +385,6 @@ static int qemu_rbd_encryption_format(rbd_image_t image,
 {
 int r = 0;
 g_autofree char *passphrase = NULL;
-size_t passphrase_len;
 rbd_encryption_format_t format;
 rbd_encryption_options_t opts;
 rbd_encryption_luks1_format_options_t luks_opts;
@@ -407,12 +406,12 @@ static int qemu_rbd_encryption_format(rbd_image_t image,
 opts_size = sizeof(luks_opts);
 r = qemu_rbd_convert_luks_create_options(
 qapi_RbdEncryptionCreateOptionsLUKS_base(&encrypt->u.luks),
-&luks_opts.alg, &passphrase, &passphrase_len, errp);
+&luks_opts.alg, &passphrase, &luks_opts.passphrase_size,
+errp);
 if (r < 0) {
 return r;
 }
 luks_opts.passphrase = passphrase;
-luks_opts.passphrase_size = passphrase_len;
 break;
 }
 case RBD_IMAGE_ENCRYPTION_FORMAT_LUKS2: {
@@ -423,12 +422,12 @@ static int qemu_rbd_encryption_format(rbd_image_t image,
 r = qemu_rbd_convert_luks_create_options(
 qapi_RbdEncryptionCreateOptionsLUKS2_base(
 &encrypt->u.luks2),
-&luks2_opts.alg, &passphrase, &passphrase_len, errp);
+&luks2_opts.alg, &passphrase, &luks2_opts.passphrase_size,
+errp);
 if (r < 0) {
 return r;
 }
 luks2_opts.passphrase = passphrase;
-luks2_opts.passphrase_size = passphrase_len;
 break;
 }
 default: {
@@ -467,7 +466,6 @@ static int qemu_rbd_encryption_load(rbd_image_t image,
 {
 int r = 0;
 g_autofree char *passphrase = NULL;
-size_t passphrase_len;
 rbd_encryption_luks1_format_options_t luks_opts;
 rbd_encryption_luks2_format_options_t luks2_opts;
 rbd_encryption_format_t format;
@@ -482,12 +480,11 @@ static int qemu_rbd_encryption_load(rbd_image_t image,
 opts_size = sizeof(luks_opts);
 r = qemu_rbd_convert_luks_options(
 qapi_RbdEncryptionOptionsLUKS_base(&encrypt->u.luks),
-&passphrase, &passphrase_len, errp);
+&passphrase, &luks_opts.passphrase_size, errp);
 if (r < 0) {
 return r;
 }
 luks_opts.passphrase = passphrase;
-luks_opts.passphrase_size = passphrase_len;
 break;
 }
 case RBD_IMAGE_ENCRYPTION_FORMAT_LUKS2: {
@@ -497,12 +494,11 @@ static int qemu_rbd_encryption_load(rbd_image_t image,
 opts_size = sizeof(luks2_opts);
 r = qemu_rbd_convert_luks_options(
 qapi_RbdEncryptionOptionsLUKS2_base(&encrypt->u.luks2),
-&passphrase, &passphrase_len, errp);
+&passphrase, &luks2_opts.passphrase_size, errp);
 if (r < 0) {
 return r;
 }
 luks2_opts.passphrase = passphrase;
-luks2_opts.passphrase_size = passphrase_len;
 break;
 }
 default: {
-- 
2.25.1




RE: [PATCH v4 3/3] block/rbd: Add support for layered encryption

2023-01-12 Thread Or Ozeri
> -Original Message-
> From: Daniel P. Berrangé 
> Sent: Thursday, 12 January 2023 14:50
> To: Or Ozeri 
> Cc: qemu-de...@nongnu.org; qemu-block@nongnu.org; Danny Harnik
> ; idryo...@gmail.com
> Subject: [EXTERNAL] Re: [PATCH v4 3/3] block/rbd: Add support for layered
> encryption
> 
> I don't think we should be reporting this differently.
> 
> The layering is not a different encryption format. It is a configuration
> convenience to avoid repeating the same passphrase for a stack of images
> when opening an image.
> 
> In terms of encryption format it is still either using 'luks1' or 'luks2'.
> 

I don’t think that's right.
The simplest argument is that the magic for RBD layered-luks is not "LUKS".
So, it's a different format, which cannot be opened by dm-crypt for example.
I think this is important for the user to know that, and thus it is useful to 
point it out
in the output of qemu-img info.




[PATCH v4 1/3] block/rbd: encryption nit fixes

2022-11-20 Thread Or Ozeri
Add const modifier to passphrases,
and remove redundant stack variable passphrase_len.

Signed-off-by: Or Ozeri 
---
 block/rbd.c | 24 ++--
 1 file changed, 10 insertions(+), 14 deletions(-)

diff --git a/block/rbd.c b/block/rbd.c
index f826410f40..e575105e6d 100644
--- a/block/rbd.c
+++ b/block/rbd.c
@@ -330,7 +330,7 @@ static int qemu_rbd_set_keypairs(rados_t cluster, const 
char *keypairs_json,
 #ifdef LIBRBD_SUPPORTS_ENCRYPTION
 static int qemu_rbd_convert_luks_options(
 RbdEncryptionOptionsLUKSBase *luks_opts,
-char **passphrase,
+const char **passphrase,
 size_t *passphrase_len,
 Error **errp)
 {
@@ -341,7 +341,7 @@ static int qemu_rbd_convert_luks_options(
 static int qemu_rbd_convert_luks_create_options(
 RbdEncryptionCreateOptionsLUKSBase *luks_opts,
 rbd_encryption_algorithm_t *alg,
-char **passphrase,
+const char **passphrase,
 size_t *passphrase_len,
 Error **errp)
 {
@@ -384,8 +384,7 @@ static int qemu_rbd_encryption_format(rbd_image_t image,
   Error **errp)
 {
 int r = 0;
-g_autofree char *passphrase = NULL;
-size_t passphrase_len;
+g_autofree const char *passphrase = NULL;
 rbd_encryption_format_t format;
 rbd_encryption_options_t opts;
 rbd_encryption_luks1_format_options_t luks_opts;
@@ -407,12 +406,12 @@ static int qemu_rbd_encryption_format(rbd_image_t image,
 opts_size = sizeof(luks_opts);
 r = qemu_rbd_convert_luks_create_options(
 qapi_RbdEncryptionCreateOptionsLUKS_base(&encrypt->u.luks),
-&luks_opts.alg, &passphrase, &passphrase_len, errp);
+&luks_opts.alg, &passphrase, &luks_opts.passphrase_size,
+errp);
 if (r < 0) {
 return r;
 }
 luks_opts.passphrase = passphrase;
-luks_opts.passphrase_size = passphrase_len;
 break;
 }
 case RBD_IMAGE_ENCRYPTION_FORMAT_LUKS2: {
@@ -423,12 +422,12 @@ static int qemu_rbd_encryption_format(rbd_image_t image,
 r = qemu_rbd_convert_luks_create_options(
 qapi_RbdEncryptionCreateOptionsLUKS2_base(
 &encrypt->u.luks2),
-&luks2_opts.alg, &passphrase, &passphrase_len, errp);
+&luks2_opts.alg, &passphrase, &luks2_opts.passphrase_size,
+errp);
 if (r < 0) {
 return r;
 }
 luks2_opts.passphrase = passphrase;
-luks2_opts.passphrase_size = passphrase_len;
 break;
 }
 default: {
@@ -466,8 +465,7 @@ static int qemu_rbd_encryption_load(rbd_image_t image,
 Error **errp)
 {
 int r = 0;
-g_autofree char *passphrase = NULL;
-size_t passphrase_len;
+g_autofree const char *passphrase = NULL;
 rbd_encryption_luks1_format_options_t luks_opts;
 rbd_encryption_luks2_format_options_t luks2_opts;
 rbd_encryption_format_t format;
@@ -482,12 +480,11 @@ static int qemu_rbd_encryption_load(rbd_image_t image,
 opts_size = sizeof(luks_opts);
 r = qemu_rbd_convert_luks_options(
 qapi_RbdEncryptionOptionsLUKS_base(&encrypt->u.luks),
-&passphrase, &passphrase_len, errp);
+&passphrase, &luks_opts.passphrase_size, errp);
 if (r < 0) {
 return r;
 }
 luks_opts.passphrase = passphrase;
-luks_opts.passphrase_size = passphrase_len;
 break;
 }
 case RBD_IMAGE_ENCRYPTION_FORMAT_LUKS2: {
@@ -497,12 +494,11 @@ static int qemu_rbd_encryption_load(rbd_image_t image,
 opts_size = sizeof(luks2_opts);
 r = qemu_rbd_convert_luks_options(
 qapi_RbdEncryptionOptionsLUKS2_base(&encrypt->u.luks2),
-&passphrase, &passphrase_len, errp);
+&passphrase, &luks2_opts.passphrase_size, errp);
 if (r < 0) {
 return r;
 }
 luks2_opts.passphrase = passphrase;
-luks2_opts.passphrase_size = passphrase_len;
 break;
 }
 default: {
-- 
2.25.1




[PATCH v4 3/3] block/rbd: Add support for layered encryption

2022-11-20 Thread Or Ozeri
Starting from ceph Reef, RBD has built-in support for layered encryption,
where each ancestor image (in a cloned image setting) can be possibly
encrypted using a unique passphrase.

A new function, rbd_encryption_load2, was added to librbd API.
This new function supports an array of passphrases (via "spec" structs).

This commit extends the qemu rbd driver API to use this new librbd API,
in order to support this new layered encryption feature.

Signed-off-by: Or Ozeri 
---
 block/rbd.c  | 161 ++-
 qapi/block-core.json |  17 -
 2 files changed, 175 insertions(+), 3 deletions(-)

diff --git a/block/rbd.c b/block/rbd.c
index 7feae45e82..157922e23a 100644
--- a/block/rbd.c
+++ b/block/rbd.c
@@ -71,6 +71,16 @@ static const char rbd_luks2_header_verification[
 'L', 'U', 'K', 'S', 0xBA, 0xBE, 0, 2
 };
 
+static const char rbd_layered_luks_header_verification[
+RBD_ENCRYPTION_LUKS_HEADER_VERIFICATION_LEN] = {
+'R', 'B', 'D', 'L', 0xBA, 0xBE, 0, 1
+};
+
+static const char rbd_layered_luks2_header_verification[
+RBD_ENCRYPTION_LUKS_HEADER_VERIFICATION_LEN] = {
+'R', 'B', 'D', 'L', 0xBA, 0xBE, 0, 2
+};
+
 typedef enum {
 RBD_AIO_READ,
 RBD_AIO_WRITE,
@@ -537,6 +547,136 @@ static int qemu_rbd_encryption_load(rbd_image_t image,
 
 return 0;
 }
+
+#ifdef LIBRBD_SUPPORTS_ENCRYPTION_LOAD2
+static int qemu_rbd_encryption_load2(rbd_image_t image,
+ RbdEncryptionOptions *encrypt,
+ Error **errp)
+{
+int r = 0;
+int encrypt_count = 1;
+int i;
+RbdEncryptionOptions *curr_encrypt;
+rbd_encryption_spec_t *specs;
+rbd_encryption_luks1_format_options_t* luks_opts;
+rbd_encryption_luks2_format_options_t* luks2_opts;
+rbd_encryption_luks_format_options_t* luks_any_opts;
+
+/* count encryption options */
+for (curr_encrypt = encrypt; curr_encrypt->has_parent;
+ curr_encrypt = curr_encrypt->parent) {
+++encrypt_count;
+}
+
+specs = g_new0(rbd_encryption_spec_t, encrypt_count);
+
+curr_encrypt = encrypt;
+for (i = 0; i < encrypt_count; ++i) {
+switch (curr_encrypt->format) {
+case RBD_IMAGE_ENCRYPTION_FORMAT_LUKS: {
+specs[i].format = RBD_ENCRYPTION_FORMAT_LUKS1;
+specs[i].opts_size =
+sizeof(rbd_encryption_luks1_format_options_t);
+
+luks_opts = g_new0(rbd_encryption_luks1_format_options_t, 1);
+specs[i].opts = luks_opts;
+
+r = qemu_rbd_convert_luks_options(
+qapi_RbdEncryptionOptionsLUKS_base(
+&curr_encrypt->u.luks),
+&luks_opts->passphrase,
+&luks_opts->passphrase_size,
+errp);
+break;
+}
+
+case RBD_IMAGE_ENCRYPTION_FORMAT_LUKS2: {
+specs[i].format = RBD_ENCRYPTION_FORMAT_LUKS2;
+specs[i].opts_size =
+sizeof(rbd_encryption_luks2_format_options_t);
+
+luks2_opts = g_new0(rbd_encryption_luks2_format_options_t, 1);
+specs[i].opts = luks2_opts;
+
+r = qemu_rbd_convert_luks_options(
+qapi_RbdEncryptionOptionsLUKS2_base(
+&curr_encrypt->u.luks2),
+&luks2_opts->passphrase,
+&luks2_opts->passphrase_size,
+errp);
+break;
+}
+
+case RBD_IMAGE_ENCRYPTION_FORMAT_LUKS_ANY: {
+specs[i].format = RBD_ENCRYPTION_FORMAT_LUKS;
+specs[i].opts_size =
+sizeof(rbd_encryption_luks_format_options_t);
+
+luks_any_opts = g_new0(rbd_encryption_luks_format_options_t, 
1);
+specs[i].opts = luks_any_opts;
+
+r = qemu_rbd_convert_luks_options(
+qapi_RbdEncryptionOptionsLUKSAny_base(
+&curr_encrypt->u.luks_any),
+&luks_any_opts->passphrase,
+&luks_any_opts->passphrase_size,
+errp);
+break;
+}
+
+default: {
+r = -ENOTSUP;
+error_setg_errno(
+errp, -r, "unknown image encryption format: %u",
+curr_encrypt->format);
+}
+}
+
+if (r < 0) {
+goto exit;
+}
+
+curr_encrypt = curr_encrypt->parent;
+}
+
+r = rbd_encryption_load2(image, specs, encrypt

[PATCH v4 0/3] block/rbd: Add support for layered encryption

2022-11-20 Thread Or Ozeri
v4: split to multiple commits
add support for more than just luks-any in layered encryption
nit fixes
v3: further nit fixes suggested by @idryomov
v2: nit fixes suggested by @idryomov


Or Ozeri (3):
  block/rbd: encryption nit fixes
  block/rbd: Add luks-any encryption opening option
  block/rbd: Add support for layered encryption

 block/rbd.c  | 204 +++
 qapi/block-core.json |  35 +++-
 2 files changed, 221 insertions(+), 18 deletions(-)

-- 
2.25.1




[PATCH v4 2/3] block/rbd: Add luks-any encryption opening option

2022-11-20 Thread Or Ozeri
Ceph RBD encryption API required specifying the encryption format
for loading encryption. The supported formats were LUKS (v1) and LUKS2.

Starting from Reef release, RBD also supports loading with "luks-any" format,
which works for both versions of LUKS.

This commit extends the qemu rbd driver API to enable qemu users to use
this luks-any wildcard format.

Signed-off-by: Or Ozeri 
---
 block/rbd.c  | 19 +++
 qapi/block-core.json | 20 ++--
 2 files changed, 37 insertions(+), 2 deletions(-)

diff --git a/block/rbd.c b/block/rbd.c
index e575105e6d..7feae45e82 100644
--- a/block/rbd.c
+++ b/block/rbd.c
@@ -468,6 +468,9 @@ static int qemu_rbd_encryption_load(rbd_image_t image,
 g_autofree const char *passphrase = NULL;
 rbd_encryption_luks1_format_options_t luks_opts;
 rbd_encryption_luks2_format_options_t luks2_opts;
+#ifdef LIBRBD_SUPPORTS_ENCRYPTION_LOAD2
+rbd_encryption_luks_format_options_t luks_any_opts;
+#endif
 rbd_encryption_format_t format;
 rbd_encryption_options_t opts;
 size_t opts_size;
@@ -501,6 +504,22 @@ static int qemu_rbd_encryption_load(rbd_image_t image,
 luks2_opts.passphrase = passphrase;
 break;
 }
+#ifdef LIBRBD_SUPPORTS_ENCRYPTION_LOAD2
+case RBD_IMAGE_ENCRYPTION_FORMAT_LUKS_ANY: {
+memset(&luks_any_opts, 0, sizeof(luks_any_opts));
+format = RBD_ENCRYPTION_FORMAT_LUKS;
+opts = &luks_any_opts;
+opts_size = sizeof(luks_any_opts);
+r = qemu_rbd_convert_luks_options(
+
qapi_RbdEncryptionOptionsLUKSAny_base(&encrypt->u.luks_any),
+&passphrase, &luks_any_opts.passphrase_size, errp);
+if (r < 0) {
+return r;
+}
+luks_any_opts.passphrase = passphrase;
+break;
+}
+#endif
 default: {
 r = -ENOTSUP;
 error_setg_errno(
diff --git a/qapi/block-core.json b/qapi/block-core.json
index 882b266532..d064847d85 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -3753,10 +3753,16 @@
 ##
 # @RbdImageEncryptionFormat:
 #
+# luks
+#
+# luks2
+#
+# luks-any: Used for opening either luks or luks2. (Since 8.0)
+#
 # Since: 6.1
 ##
 { 'enum': 'RbdImageEncryptionFormat',
-  'data': [ 'luks', 'luks2' ] }
+  'data': [ 'luks', 'luks2', 'luks-any' ] }
 
 ##
 # @RbdEncryptionOptionsLUKSBase:
@@ -3798,6 +3804,15 @@
   'base': 'RbdEncryptionOptionsLUKSBase',
   'data': { } }
 
+##
+# @RbdEncryptionOptionsLUKSAny:
+#
+# Since: 8.0
+##
+{ 'struct': 'RbdEncryptionOptionsLUKSAny',
+  'base': 'RbdEncryptionOptionsLUKSBase',
+  'data': { } }
+
 ##
 # @RbdEncryptionCreateOptionsLUKS:
 #
@@ -3825,7 +3840,8 @@
   'base': { 'format': 'RbdImageEncryptionFormat' },
   'discriminator': 'format',
   'data': { 'luks': 'RbdEncryptionOptionsLUKS',
-'luks2': 'RbdEncryptionOptionsLUKS2' } }
+'luks2': 'RbdEncryptionOptionsLUKS2',
+'luks-any': 'RbdEncryptionOptionsLUKSAny'} }
 
 ##
 # @RbdEncryptionCreateOptions:
-- 
2.25.1




RE: [PATCH v3] block/rbd: Add support for layered encryption

2022-11-17 Thread Or Ozeri


> -Original Message-
> From: Daniel P. Berrangé 
> Sent: 16 November 2022 13:15
> To: Or Ozeri ; qemu-de...@nongnu.org; qemu-
> bl...@nongnu.org; Danny Harnik ;
> idryo...@gmail.com
> Subject: [EXTERNAL] Re: [PATCH v3] block/rbd: Add support for layered
> encryption
> 
> On Wed, Nov 16, 2022 at 10:23:52AM +, Daniel P. Berrangé wrote:
> 
> So with that precedent I guess it is ok to add 'luks-any'.
> 

So is it OK to leave the "luks-any" changes to this commit?
If not, is it ok to split this to 2 commits, in the same "patch-series"?

BTW is there a possibility this will actually make it to 7.2?
For me personally, the highest priority for me is just getting it merged (not 
necessarily to the 7.2 release),
so that I can submit a follow-up patch to libvirt.


RE: [PATCH v3] block/rbd: Add support for layered encryption

2022-11-16 Thread Or Ozeri
> -Original Message-
> From: Daniel P. Berrangé 
> Sent: 15 November 2022 19:47
> To: Or Ozeri 
> Cc: qemu-de...@nongnu.org; qemu-block@nongnu.org; Danny Harnik
> ; idryo...@gmail.com
> Subject: [EXTERNAL] Re: [PATCH v3] block/rbd: Add support for layered
> encryption
> 
> AFAICT, supporting layered encryption shouldn't require anything other than
> the 'parent' addition.
> 

Since the layered encryption API is new in librbd, we don't have to support 
"luks" and "luks2" at all.
In librbd we are actually deprecating the use of "luks" and "luks2", and 
instead ask users to use "luks-any".
If we don't add "luks-any" here, we will need to implement explicit cases for 
"luks" and "luks2" in the qemu_rbd_encryption_load2. This looks like a kind of 
wasteful coding that won't be actually used by users of the rbd driver in qemu.
Anyhow, we need the "luks-any" option for our use-case, so if you insist, I 
will first submit a patch to add "luks-any", before this patch.


RE: [PATCH v1] block/rbd: Add support for layered encryption

2022-11-15 Thread Or Ozeri
I tried casting to non-const and it seems to work. Changed in v3 now.
I did not know that a const modifier could simply be cast out :)

> -Original Message-
> From: Ilya Dryomov 
> Sent: 15 November 2022 14:00
> To: Or Ozeri 
> Cc: qemu-de...@nongnu.org; qemu-block@nongnu.org; Danny Harnik
> 
> Subject: [EXTERNAL] Re: [PATCH v1] block/rbd: Add support for layered
> encryption
> 
> On Sun, Nov 13, 2022 at 11:16 AM Or Ozeri  wrote:
> >
> >
> >
> > > -Original Message-
> > > From: Ilya Dryomov 
> > > Sent: 11 November 2022 15:01
> > > To: Or Ozeri 
> > > Cc: qemu-de...@nongnu.org; qemu-block@nongnu.org; Danny Harnik
> > > 
> > > Subject: [EXTERNAL] Re: [PATCH v1] block/rbd: Add support for
> > > layered encryption
> > >
> > > I don't understand the need for this char* array.  Is there a
> > > problem with putting the blob directly into
> > > luks_all_opts->passphrase just like the size is put into luks_all_opts-
> >passphrase_size?
> > >
> >
> > luks_all_opts->passphrase has a const modifier.
> 
> Hi Or,
> 
> That's really not a reason to make a dynamic memory allocation.  You can just
> cast that const away but I suspect that the underlying issue is that a const 
> is
> missing somewhere else.  At the end of the day, QEMU allocates a buffer for
> the passphrase when it's fetched via the secret API -- that pointer should
> assign to const char* just fine.
> 
> Thanks,
> 
> Ilya


[PATCH v3] block/rbd: Add support for layered encryption

2022-11-15 Thread Or Ozeri
Starting from ceph Reef, RBD has built-in support for layered encryption,
where each ancestor image (in a cloned image setting) can be possibly
encrypted using a unique passphrase.

A new function, rbd_encryption_load2, was added to librbd API.
This new function supports an array of passphrases (via "spec" structs).

This commit extends the qemu rbd driver API to use this new librbd API,
in order to support this new layered encryption feature.

Signed-off-by: Or Ozeri 
---
v3: further nit fixes suggested by @idryomov
v2: nit fixes suggested by @idryomov
---
 block/rbd.c  | 119 ++-
 qapi/block-core.json |  35 +++--
 2 files changed, 150 insertions(+), 4 deletions(-)

diff --git a/block/rbd.c b/block/rbd.c
index f826410f40..ce017c29b5 100644
--- a/block/rbd.c
+++ b/block/rbd.c
@@ -71,6 +71,16 @@ static const char rbd_luks2_header_verification[
 'L', 'U', 'K', 'S', 0xBA, 0xBE, 0, 2
 };
 
+static const char rbd_layered_luks_header_verification[
+RBD_ENCRYPTION_LUKS_HEADER_VERIFICATION_LEN] = {
+'R', 'B', 'D', 'L', 0xBA, 0xBE, 0, 1
+};
+
+static const char rbd_layered_luks2_header_verification[
+RBD_ENCRYPTION_LUKS_HEADER_VERIFICATION_LEN] = {
+'R', 'B', 'D', 'L', 0xBA, 0xBE, 0, 2
+};
+
 typedef enum {
 RBD_AIO_READ,
 RBD_AIO_WRITE,
@@ -470,6 +480,9 @@ static int qemu_rbd_encryption_load(rbd_image_t image,
 size_t passphrase_len;
 rbd_encryption_luks1_format_options_t luks_opts;
 rbd_encryption_luks2_format_options_t luks2_opts;
+#ifdef LIBRBD_SUPPORTS_ENCRYPTION_LOAD2
+rbd_encryption_luks_format_options_t luks_any_opts;
+#endif
 rbd_encryption_format_t format;
 rbd_encryption_options_t opts;
 size_t opts_size;
@@ -505,6 +518,23 @@ static int qemu_rbd_encryption_load(rbd_image_t image,
 luks2_opts.passphrase_size = passphrase_len;
 break;
 }
+#ifdef LIBRBD_SUPPORTS_ENCRYPTION_LOAD2
+case RBD_IMAGE_ENCRYPTION_FORMAT_LUKS_ANY: {
+memset(&luks_any_opts, 0, sizeof(luks_any_opts));
+format = RBD_ENCRYPTION_FORMAT_LUKS;
+opts = &luks_any_opts;
+opts_size = sizeof(luks_any_opts);
+r = qemu_rbd_convert_luks_options(
+
qapi_RbdEncryptionOptionsLUKSAny_base(&encrypt->u.luks_any),
+&passphrase, &passphrase_len, errp);
+if (r < 0) {
+return r;
+}
+luks_any_opts.passphrase = passphrase;
+luks_any_opts.passphrase_size = passphrase_len;
+break;
+}
+#endif
 default: {
 r = -ENOTSUP;
 error_setg_errno(
@@ -522,6 +552,74 @@ static int qemu_rbd_encryption_load(rbd_image_t image,
 
 return 0;
 }
+
+#ifdef LIBRBD_SUPPORTS_ENCRYPTION_LOAD2
+static int qemu_rbd_encryption_load2(rbd_image_t image,
+ RbdEncryptionOptions *encrypt,
+ Error **errp)
+{
+int r = 0;
+int encrypt_count = 1;
+int i;
+RbdEncryptionOptions *curr_encrypt;
+rbd_encryption_spec_t *specs;
+rbd_encryption_luks_format_options_t* luks_any_opts;
+
+/* count encryption options */
+for (curr_encrypt = encrypt; curr_encrypt->has_parent;
+ curr_encrypt = curr_encrypt->parent) {
+++encrypt_count;
+}
+
+specs = g_new0(rbd_encryption_spec_t, encrypt_count);
+
+curr_encrypt = encrypt;
+for (i = 0; i < encrypt_count; ++i) {
+if (curr_encrypt->format != RBD_IMAGE_ENCRYPTION_FORMAT_LUKS_ANY) {
+r = -ENOTSUP;
+error_setg_errno(
+errp, -r, "unknown image encryption format: %u",
+curr_encrypt->format);
+goto exit;
+}
+
+specs[i].format = RBD_ENCRYPTION_FORMAT_LUKS;
+specs[i].opts_size = sizeof(rbd_encryption_luks_format_options_t);
+
+luks_any_opts = g_new0(rbd_encryption_luks_format_options_t, 1);
+specs[i].opts = luks_any_opts;
+
+r = qemu_rbd_convert_luks_options(
+qapi_RbdEncryptionOptionsLUKSAny_base(
+&curr_encrypt->u.luks_any),
+(char**)&luks_any_opts->passphrase,
+&luks_any_opts->passphrase_size,
+errp);
+if (r < 0) {
+goto exit;
+}
+
+curr_encrypt = curr_encrypt->parent;
+}
+
+r = rbd_encryption_load2(image, specs, encrypt_count);
+if (r < 0) {
+error_setg_errno(errp, -r, "layered encryption load fail");
+goto exit;
+}
+
+exit:
+for (i = 0; i < encrypt_count; ++i) {
+luks_any_opts = specs[i].opts;
+if (luks_any_opts) {
+g_free((c

[PATCH v2] block/rbd: Add support for layered encryption

2022-11-13 Thread Or Ozeri
Starting from ceph Reef, RBD has built-in support for layered encryption,
where each ancestor image (in a cloned image setting) can be possibly
encrypted using a unique passphrase.

A new function, rbd_encryption_load2, was added to librbd API.
This new function supports an array of passphrases (via "spec" structs).

This commit extends the qemu rbd driver API to use this new librbd API,
in order to support this new layered encryption feature.

Signed-off-by: Or Ozeri 
---
v2: nit fixes suggested by @idryomov
---
 block/rbd.c  | 122 ++-
 qapi/block-core.json |  33 ++--
 2 files changed, 151 insertions(+), 4 deletions(-)

diff --git a/block/rbd.c b/block/rbd.c
index f826410f40..bde0326bfd 100644
--- a/block/rbd.c
+++ b/block/rbd.c
@@ -71,6 +71,16 @@ static const char rbd_luks2_header_verification[
 'L', 'U', 'K', 'S', 0xBA, 0xBE, 0, 2
 };
 
+static const char rbd_layered_luks_header_verification[
+RBD_ENCRYPTION_LUKS_HEADER_VERIFICATION_LEN] = {
+'R', 'B', 'D', 'L', 0xBA, 0xBE, 0, 1
+};
+
+static const char rbd_layered_luks2_header_verification[
+RBD_ENCRYPTION_LUKS_HEADER_VERIFICATION_LEN] = {
+'R', 'B', 'D', 'L', 0xBA, 0xBE, 0, 2
+};
+
 typedef enum {
 RBD_AIO_READ,
 RBD_AIO_WRITE,
@@ -470,6 +480,9 @@ static int qemu_rbd_encryption_load(rbd_image_t image,
 size_t passphrase_len;
 rbd_encryption_luks1_format_options_t luks_opts;
 rbd_encryption_luks2_format_options_t luks2_opts;
+#ifdef LIBRBD_SUPPORTS_ENCRYPTION_LOAD2
+rbd_encryption_luks_format_options_t luks_any_opts;
+#endif
 rbd_encryption_format_t format;
 rbd_encryption_options_t opts;
 size_t opts_size;
@@ -505,6 +518,23 @@ static int qemu_rbd_encryption_load(rbd_image_t image,
 luks2_opts.passphrase_size = passphrase_len;
 break;
 }
+#ifdef LIBRBD_SUPPORTS_ENCRYPTION_LOAD2
+case RBD_IMAGE_ENCRYPTION_FORMAT_LUKS_ANY: {
+memset(&luks_any_opts, 0, sizeof(luks_any_opts));
+format = RBD_ENCRYPTION_FORMAT_LUKS;
+opts = &luks_any_opts;
+opts_size = sizeof(luks_any_opts);
+r = qemu_rbd_convert_luks_options(
+
qapi_RbdEncryptionOptionsLUKSAny_base(&encrypt->u.luks_any),
+&passphrase, &passphrase_len, errp);
+if (r < 0) {
+return r;
+}
+luks_any_opts.passphrase = passphrase;
+luks_any_opts.passphrase_size = passphrase_len;
+break;
+}
+#endif
 default: {
 r = -ENOTSUP;
 error_setg_errno(
@@ -522,6 +552,76 @@ static int qemu_rbd_encryption_load(rbd_image_t image,
 
 return 0;
 }
+
+#ifdef LIBRBD_SUPPORTS_ENCRYPTION_LOAD2
+static int qemu_rbd_encryption_load2(rbd_image_t image,
+ RbdEncryptionOptions *encrypt,
+ Error **errp)
+{
+int r = 0;
+int encrypt_count = 1;
+int i;
+RbdEncryptionOptions *curr_encrypt;
+rbd_encryption_spec_t *specs;
+rbd_encryption_luks_format_options_t* luks_any_opts;
+char **passphrases;
+
+/* count encryption options */
+for (curr_encrypt = encrypt; curr_encrypt->has_parent;
+ curr_encrypt = curr_encrypt->parent) {
+++encrypt_count;
+}
+
+specs = g_new0(rbd_encryption_spec_t, encrypt_count);
+passphrases = g_new0(char*, encrypt_count);
+
+curr_encrypt = encrypt;
+for (i = 0; i < encrypt_count; ++i) {
+if (curr_encrypt->format != RBD_IMAGE_ENCRYPTION_FORMAT_LUKS_ANY) {
+r = -ENOTSUP;
+error_setg_errno(
+errp, -r, "unknown image encryption format: %u",
+curr_encrypt->format);
+goto exit;
+}
+
+specs[i].format = RBD_ENCRYPTION_FORMAT_LUKS;
+specs[i].opts_size = sizeof(rbd_encryption_luks_format_options_t);
+
+luks_any_opts = g_new0(rbd_encryption_luks_format_options_t, 1);
+specs[i].opts = luks_any_opts;
+
+r = qemu_rbd_convert_luks_options(
+qapi_RbdEncryptionOptionsLUKSAny_base(
+&curr_encrypt->u.luks_any),
+&passphrases[i], &luks_any_opts->passphrase_size,
+errp);
+if (r < 0) {
+goto exit;
+}
+
+luks_any_opts->passphrase = passphrases[i];
+
+curr_encrypt = curr_encrypt->parent;
+}
+
+r = rbd_encryption_load2(image, specs, encrypt_count);
+if (r < 0) {
+error_setg_errno(errp, -r, "layered encryption load fail");
+goto exit;
+}
+
+exit:
+for (i = 0; i < encrypt_count; ++i) {
+luks_any_opts = (rbd_encryption_

RE: [PATCH v1] block/rbd: Add support for layered encryption

2022-11-13 Thread Or Ozeri


> -Original Message-
> From: Ilya Dryomov 
> Sent: 11 November 2022 15:01
> To: Or Ozeri 
> Cc: qemu-de...@nongnu.org; qemu-block@nongnu.org; Danny Harnik
> 
> Subject: [EXTERNAL] Re: [PATCH v1] block/rbd: Add support for layered
> encryption
> 
> I don't understand the need for this char* array.  Is there a problem with
> putting the blob directly into luks_all_opts->passphrase just like the size is
> put into luks_all_opts->passphrase_size?
> 

luks_all_opts->passphrase has a const modifier.


[PATCH v1] block/rbd: Add support for layered encryption

2022-10-26 Thread Or Ozeri
Starting from ceph Reef, RBD has built-in support for layered encryption,
where each ancestor image (in a cloned image setting) can be possibly
encrypted using a unique passphrase.

A new function, rbd_encryption_load2, was added to librbd API.
This new function supports an array of passphrases (via "spec" structs).

This commit extends the qemu rbd driver API to use this new librbd API,
in order to support this new layered encryption feature.

Signed-off-by: Or Ozeri 
---
 block/rbd.c  | 134 ++-
 qapi/block-core.json |  33 ++-
 2 files changed, 163 insertions(+), 4 deletions(-)

diff --git a/block/rbd.c b/block/rbd.c
index f826410f40..09953687c9 100644
--- a/block/rbd.c
+++ b/block/rbd.c
@@ -71,6 +71,16 @@ static const char rbd_luks2_header_verification[
 'L', 'U', 'K', 'S', 0xBA, 0xBE, 0, 2
 };
 
+static const char rbd_layered_luks_header_verification[
+RBD_ENCRYPTION_LUKS_HEADER_VERIFICATION_LEN] = {
+'R', 'B', 'D', 'L', 0xBA, 0xBE, 0, 1
+};
+
+static const char rbd_layered_luks2_header_verification[
+RBD_ENCRYPTION_LUKS_HEADER_VERIFICATION_LEN] = {
+'R', 'B', 'D', 'L', 0xBA, 0xBE, 0, 2
+};
+
 typedef enum {
 RBD_AIO_READ,
 RBD_AIO_WRITE,
@@ -470,6 +480,9 @@ static int qemu_rbd_encryption_load(rbd_image_t image,
 size_t passphrase_len;
 rbd_encryption_luks1_format_options_t luks_opts;
 rbd_encryption_luks2_format_options_t luks2_opts;
+#ifdef LIBRBD_SUPPORTS_ENCRYPTION_LOAD2
+rbd_encryption_luks_format_options_t luks_all_opts;
+#endif
 rbd_encryption_format_t format;
 rbd_encryption_options_t opts;
 size_t opts_size;
@@ -505,6 +518,23 @@ static int qemu_rbd_encryption_load(rbd_image_t image,
 luks2_opts.passphrase_size = passphrase_len;
 break;
 }
+#ifdef LIBRBD_SUPPORTS_ENCRYPTION_LOAD2
+case RBD_IMAGE_ENCRYPTION_FORMAT_LUKS_ALL: {
+memset(&luks_all_opts, 0, sizeof(luks_all_opts));
+format = RBD_ENCRYPTION_FORMAT_LUKS;
+opts = &luks_all_opts;
+opts_size = sizeof(luks_all_opts);
+r = qemu_rbd_convert_luks_options(
+
qapi_RbdEncryptionOptionsLUKSAll_base(&encrypt->u.luks_all),
+&passphrase, &passphrase_len, errp);
+if (r < 0) {
+return r;
+}
+luks_all_opts.passphrase = passphrase;
+luks_all_opts.passphrase_size = passphrase_len;
+break;
+}
+#endif
 default: {
 r = -ENOTSUP;
 error_setg_errno(
@@ -522,6 +552,87 @@ static int qemu_rbd_encryption_load(rbd_image_t image,
 
 return 0;
 }
+
+#ifdef LIBRBD_SUPPORTS_ENCRYPTION_LOAD2
+static int qemu_rbd_encryption_load2(rbd_image_t image,
+ RbdEncryptionOptions *encrypt,
+ Error **errp)
+{
+int r = 0;
+int encryption_options_count = 1;
+int spec_count = 0;
+int passphrase_count = 0;
+int i;
+RbdEncryptionOptions *curr_encrypt;
+rbd_encryption_spec_t *specs;
+rbd_encryption_spec_t *curr_spec;
+rbd_encryption_luks_format_options_t* luks_all_opts;
+char **passphrases;
+char **curr_passphrase;
+
+/* count encryption options */
+for (curr_encrypt = encrypt; curr_encrypt->has_parent;
+ curr_encrypt = curr_encrypt->parent, ++encryption_options_count) {
+}
+
+specs = g_new0(rbd_encryption_spec_t, encryption_options_count);
+passphrases = g_new0(char*, encryption_options_count);
+
+curr_encrypt = encrypt;
+for (i = 0; i < encryption_options_count; ++i) {
+if (curr_encrypt->format != RBD_IMAGE_ENCRYPTION_FORMAT_LUKS_ALL) {
+r = -ENOTSUP;
+error_setg_errno(
+errp, -r, "unknown image encryption format: %u",
+curr_encrypt->format);
+goto exit;
+}
+
+curr_spec = &specs[i];
+curr_passphrase = &passphrases[i];
+curr_spec->format = RBD_ENCRYPTION_FORMAT_LUKS;
+curr_spec->opts_size = sizeof(rbd_encryption_luks_format_options_t);
+
+luks_all_opts = g_new0(rbd_encryption_luks_format_options_t, 1);
+curr_spec->opts = luks_all_opts;
+++spec_count;
+memset(luks_all_opts, 0, sizeof(rbd_encryption_luks_format_options_t));
+
+r = qemu_rbd_convert_luks_options(
+qapi_RbdEncryptionOptionsLUKSAll_base(
+&curr_encrypt->u.luks_all),
+curr_passphrase, &luks_all_opts->passphrase_size,
+errp);
+if (r < 0) {
+goto exit;
+}
+
+++passphrase_count;
+luks_all_opts->passphrase = *curr_pass

[PATCH v1 1/1] virtio-block: switch to blk_get_max_hw_transfer

2021-12-09 Thread Or Ozeri
The blk_get_max_hw_transfer API was recently added in 6.1.0.
It allows querying an underlying block device its max transfer capability.
This commit changes virtio-blk to use this.

Signed-off-by: Or Ozeri 
---
 hw/block/virtio-blk.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c
index f139cd7cc9..1ba9a06888 100644
--- a/hw/block/virtio-blk.c
+++ b/hw/block/virtio-blk.c
@@ -458,7 +458,7 @@ static void virtio_blk_submit_multireq(BlockBackend *blk, 
MultiReqBuffer *mrb)
 return;
 }
 
-max_transfer = blk_get_max_transfer(mrb->reqs[0]->dev->blk);
+max_transfer = blk_get_max_hw_transfer(mrb->reqs[0]->dev->blk);
 
 qsort(mrb->reqs, mrb->num_reqs, sizeof(*mrb->reqs),
   &multireq_compare);
-- 
2.25.1




[PATCH v1 0/1] virtio-block: switch to blk_get_max_hw_transfer

2021-12-09 Thread Or Ozeri
Since moving to qemu 6.1.0 we've been seeing disk failures inside a qemu guest 
VM.
This happened when using if=virtio on a host /dev/nbdX device.
Binary searching on qemu commit history, I found these errors start on this 
commit:

Commit 18473467
file-posix: try BLKSECTGET on block devices too, do not round to power of 2

The above commit switched posix block device limits (including host /dev/nbdX 
devices)
to query limits from /sys/dev/block/..., instead of using predefined limits.

The scsi-generic driver was changed to use the queried limits,
whereas the virtio-blk driver was only the queried max_iov,
but still using the predefined max_transfer, which is unlimited in qemu.

For NBD devices, max_iov is unlimited by the kernel nbd driver.
As as consequence, the virtio-blk merged requests over the limit of our host 
/dev/nbdX device,
which apparently caused the guest disk errors.

The solution that worked for me was to change the virtio-blk driver to use the 
max_transfer
limit queried from the posix host device (given by blk_get_max_hw_transfer).

Or Ozeri (1):
  virtio-block: switch to blk_get_max_hw_transfer

 hw/block/virtio-blk.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

-- 
2.25.1




RE: [PATCH v1] block/raw-format: implement .bdrv_get_specific_info handler

2021-07-07 Thread Or Ozeri
Would you suggest to do this child traversal on bdrv_query_image_info, and have it returned as part of the ImageInfo struct?In that case, I would add *driver-specific to ImageInfo, in addition to the existing *format-specific?Or should I just do the traversal in img_info (qemu-img.c), avoiding the change to the ImageInfo struct?-"Kevin Wolf" <kw...@redhat.com> wrote: -----To: "Or Ozeri" <o...@il.ibm.com>From: "Kevin Wolf" <kw...@redhat.com>Date: 07/07/2021 10:52AMCc: qemu-de...@nongnu.org, qemu-block@nongnu.org, to.my.troc...@gmail.com, dan...@il.ibm.com, berra...@redhat.com, idryo...@gmail.comSubject: [EXTERNAL] Re: [PATCH v1] block/raw-format: implement .bdrv_get_specific_info handlerAm 07.07.2021 um 07:35 hat Or Ozeri geschrieben:> When using the raw format, allow exposing specific info by the underlying storage.> In particular, this will enable RBD images using the raw format to indicate> a LUKS2 encrypted image in the output of qemu-img info.> > Signed-off-by: Or Ozeri <o...@il.ibm.com>This doesn't feel right because it would introduce an inconsistency(drivers are supposed to return information about their layer, and alldrivers except raw would still do so) and therefore wouldn't even solvethe full problem: For non-raw images, the information isn't any lessuseful, but it still wouldn't be available.I believe the information is already available in QMP, usingquery-named-block-nodes, because then you get a separate BlockDeviceInfo(which contains ImageInfoSpecific) for each node, including the protocolnode.So maybe what we need to do is change qemu-img to iterate the node chain(possibly using bdrv_primary_bs()) and print the ImageInfoSpecific foreach layer if it's present, while indicating which part is for whichlayer.So the output could look like this:...Driver specific information (qcow2):    compat: 0.10    compression type: zlib    refcount bits: 16Driver specific information (rbd):    encryption format: luksKevin




[PATCH v1] block/raw-format: implement .bdrv_get_specific_info handler

2021-07-06 Thread Or Ozeri
When using the raw format, allow exposing specific info by the underlying 
storage.
In particular, this will enable RBD images using the raw format to indicate
a LUKS2 encrypted image in the output of qemu-img info.

Signed-off-by: Or Ozeri 
---
 block/raw-format.c | 7 +++
 1 file changed, 7 insertions(+)

diff --git a/block/raw-format.c b/block/raw-format.c
index 7717578ed6..f6e70e2356 100644
--- a/block/raw-format.c
+++ b/block/raw-format.c
@@ -369,6 +369,12 @@ static int raw_get_info(BlockDriverState *bs, 
BlockDriverInfo *bdi)
 return bdrv_get_info(bs->file->bs, bdi);
 }
 
+static ImageInfoSpecific *raw_get_specific_info(BlockDriverState *bs,
+Error **errp)
+{
+return bdrv_get_specific_info(bs->file->bs, errp);
+}
+
 static void raw_refresh_limits(BlockDriverState *bs, Error **errp)
 {
 if (bs->probed) {
@@ -603,6 +609,7 @@ BlockDriver bdrv_raw = {
 .has_variable_length  = true,
 .bdrv_measure = &raw_measure,
 .bdrv_get_info= &raw_get_info,
+.bdrv_get_specific_info = &raw_get_specific_info,
 .bdrv_refresh_limits  = &raw_refresh_limits,
 .bdrv_probe_blocksizes = &raw_probe_blocksizes,
 .bdrv_probe_geometry  = &raw_probe_geometry,
-- 
2.27.0




[PATCH v2] block/rbd: Add support for rbd image encryption

2021-06-27 Thread Or Ozeri
Starting from ceph Pacific, RBD has built-in support for image-level encryption.
Currently supported formats are LUKS version 1 and 2.

There are 2 new relevant librbd APIs for controlling encryption, both expect an
open image context:

rbd_encryption_format: formats an image (i.e. writes the LUKS header)
rbd_encryption_load: loads encryptor/decryptor to the image IO stack

This commit extends the qemu rbd driver API to support the above.

Signed-off-by: Or Ozeri 
---
v2: handle encryption info only for the case where encryption is not loaded
---
 block/rbd.c  | 361 ++-
 qapi/block-core.json | 110 -
 2 files changed, 465 insertions(+), 6 deletions(-)

diff --git a/block/rbd.c b/block/rbd.c
index f098a89c7b..8edd1be49e 100644
--- a/block/rbd.c
+++ b/block/rbd.c
@@ -73,6 +73,18 @@
 #define LIBRBD_USE_IOVEC 0
 #endif
 
+#define RBD_ENCRYPTION_LUKS_HEADER_VERIFICATION_LEN 8
+
+static const char rbd_luks_header_verification[
+RBD_ENCRYPTION_LUKS_HEADER_VERIFICATION_LEN] = {
+'L', 'U', 'K', 'S', 0xBA, 0xBE, 0, 1
+};
+
+static const char rbd_luks2_header_verification[
+RBD_ENCRYPTION_LUKS_HEADER_VERIFICATION_LEN] = {
+'L', 'U', 'K', 'S', 0xBA, 0xBE, 0, 2
+};
+
 typedef enum {
 RBD_AIO_READ,
 RBD_AIO_WRITE,
@@ -341,6 +353,203 @@ static void qemu_rbd_memset(RADOSCB *rcb, int64_t offs)
 }
 }
 
+#ifdef LIBRBD_SUPPORTS_ENCRYPTION
+static int qemu_rbd_convert_luks_options(
+RbdEncryptionOptionsLUKSBase *luks_opts,
+char **passphrase,
+size_t *passphrase_len,
+Error **errp)
+{
+return qcrypto_secret_lookup(luks_opts->key_secret, (uint8_t **)passphrase,
+ passphrase_len, errp);
+}
+
+static int qemu_rbd_convert_luks_create_options(
+RbdEncryptionCreateOptionsLUKSBase *luks_opts,
+rbd_encryption_algorithm_t *alg,
+char **passphrase,
+size_t *passphrase_len,
+Error **errp)
+{
+int r = 0;
+
+r = qemu_rbd_convert_luks_options(
+qapi_RbdEncryptionCreateOptionsLUKSBase_base(luks_opts),
+passphrase, passphrase_len, errp);
+if (r < 0) {
+return r;
+}
+
+if (luks_opts->has_cipher_alg) {
+switch (luks_opts->cipher_alg) {
+case QCRYPTO_CIPHER_ALG_AES_128: {
+*alg = RBD_ENCRYPTION_ALGORITHM_AES128;
+break;
+}
+case QCRYPTO_CIPHER_ALG_AES_256: {
+*alg = RBD_ENCRYPTION_ALGORITHM_AES256;
+break;
+}
+default: {
+r = -ENOTSUP;
+error_setg_errno(errp, -r, "unknown encryption algorithm: %u",
+ luks_opts->cipher_alg);
+return r;
+}
+}
+} else {
+/* default alg */
+*alg = RBD_ENCRYPTION_ALGORITHM_AES256;
+}
+
+return 0;
+}
+
+static int qemu_rbd_encryption_format(rbd_image_t image,
+  RbdEncryptionCreateOptions *encrypt,
+  Error **errp)
+{
+int r = 0;
+g_autofree char *passphrase = NULL;
+size_t passphrase_len;
+rbd_encryption_format_t format;
+rbd_encryption_options_t opts;
+rbd_encryption_luks1_format_options_t luks_opts;
+rbd_encryption_luks2_format_options_t luks2_opts;
+size_t opts_size;
+uint64_t raw_size, effective_size;
+
+r = rbd_get_size(image, &raw_size);
+if (r < 0) {
+error_setg_errno(errp, -r, "cannot get raw image size");
+return r;
+}
+
+switch (encrypt->format) {
+case RBD_IMAGE_ENCRYPTION_FORMAT_LUKS: {
+memset(&luks_opts, 0, sizeof(luks_opts));
+format = RBD_ENCRYPTION_FORMAT_LUKS1;
+opts = &luks_opts;
+opts_size = sizeof(luks_opts);
+r = qemu_rbd_convert_luks_create_options(
+qapi_RbdEncryptionCreateOptionsLUKS_base(&encrypt->u.luks),
+&luks_opts.alg, &passphrase, &passphrase_len, errp);
+if (r < 0) {
+return r;
+}
+luks_opts.passphrase = passphrase;
+luks_opts.passphrase_size = passphrase_len;
+break;
+}
+case RBD_IMAGE_ENCRYPTION_FORMAT_LUKS2: {
+memset(&luks2_opts, 0, sizeof(luks2_opts));
+format = RBD_ENCRYPTION_FORMAT_LUKS2;
+opts = &luks2_opts;
+opts_size = sizeof(luks2_opts);
+r = qemu_rbd_convert_luks_create_options(
+qapi_RbdEncryptionCreateOptionsLUKS2_base(
+&encrypt->u.luks2),
+&luks2_opts.alg, &passphrase, &passphrase_len, errp);
+  

RE: [PATCH] block/rbd: Add support for rbd image encryption

2021-06-27 Thread Or Ozeri
Should I still leave the encryption format part of the state, and just not report it? or should I also remove it from the state?-"Ilya Dryomov" <idryo...@gmail.com> wrote: -----To: "Or Ozeri" <o...@il.ibm.com>From: "Ilya Dryomov" <idryo...@gmail.com>Date: 06/27/2021 02:00PMCc: qemu-de...@nongnu.org, qemu-block@nongnu.org, kw...@redhat.com, "Mykola Golub" <to.my.troc...@gmail.com>, "Danny Harnik" <dan...@il.ibm.com>, "Daniel P. Berrangé" <berra...@redhat.com>Subject: [EXTERNAL] Re: [PATCH] block/rbd: Add support for rbd image encryptionOn Sun, Jun 27, 2021 at 10:44 AM Or Ozeri <o...@il.ibm.com> wrote:>> Ilya,>> I fixed according to your suggestions, except for the passphrase zeroing.> Looks like it's not a one-liner, but rather a long list of ifdefs to try and cover all possible platforms/compilers (this is what I've seen they do in k5-int.h).> I didn't want to copy this into rbd.c.> I guess that the right solution would be adding a qemu utility function (not sure where exactly), but anyways perhaps this, like the changes I previously made to raw_format.c, should be made in different patch.Hi Or,Yes, given that there doesn't seem to be an existing straightforwardAPI for it, I don't think it is a blocker.  Just something to keep inmind.You also implemented one change that I didn't suggest -- storingthe encryption status in BDRVRBDState.  BTW it is a good practiceto include the version in the subject (e.g. [PATCH v3] ...) anda per-version changelog in the description.The way the encryption format is reported in this patch actually begsmore questions because now I think we need to differentiate between anencrypted image for which the encryption profile has been loaded andone for which it hasn't been loaded and probably also report the rawsize...The previous approach of reporting the encryption format only for "raw"images was a good starting point IMO.  I'd keep the bit that switchesfrom rbd_get_size() to s->image_size and drop everything else for now.>> Thanks,> Or>> -"Or Ozeri" <o...@il.ibm.com> wrote: -> To: qemu-de...@nongnu.org> From: "Or Ozeri" <o...@il.ibm.com>> Date: 06/27/2021 11:31AM> Cc: qemu-block@nongnu.org, o...@il.ibm.com, kw...@redhat.com, to.my.troc...@gmail.com, dan...@il.ibm.com, berra...@redhat.com, idryo...@gmail.com> Subject: [PATCH] block/rbd: Add support for rbd image encryption>> Starting from ceph Pacific, RBD has built-in support for image-level encryption.> Currently supported formats are LUKS version 1 and 2.>> There are 2 new relevant librbd APIs for controlling encryption, both expect an> open image context:>> rbd_encryption_format: formats an image (i.e. writes the LUKS header)> rbd_encryption_load: loads encryptor/decryptor to the image IO stack>> This commit extends the qemu rbd driver API to support the above.>> Signed-off-by: Or Ozeri <o...@il.ibm.com>> --->  block/rbd.c          | 380 ++->  qapi/block-core.json | 110 ->  2 files changed, 484 insertions(+), 6 deletions(-)>> diff --git a/block/rbd.c b/block/rbd.c> index f098a89c7b..dadecaf3da 100644> --- a/block/rbd.c> +++ b/block/rbd.c> @@ -73,6 +73,18 @@>  #define LIBRBD_USE_IOVEC 0>  #endif>> +#define RBD_ENCRYPTION_LUKS_HEADER_VERIFICATION_LEN 8> +> +static const char rbd_luks_header_verification[> +        RBD_ENCRYPTION_LUKS_HEADER_VERIFICATION_LEN] = {> +    'L', 'U', 'K', 'S', 0xBA, 0xBE, 0, 1> +};> +> +static const char rbd_luks2_header_verification[> +        RBD_ENCRYPTION_LUKS_HEADER_VERIFICATION_LEN] = {> +    'L', 'U', 'K', 'S', 0xBA, 0xBE, 0, 2> +};> +>  typedef enum {>      RBD_AIO_READ,>      RBD_AIO_WRITE,> @@ -106,6 +118,7 @@ typedef struct BDRVRBDState {>      char *snap;>      char *namespace;>      uint64_t image_size;> +    ImageInfoSpecificRbd image_info;>  } BDRVRBDState;>>  static int qemu_rbd_connect(rados_t *cluster, rados_ioctx_t *io_ctx,> @@ -341,6 +354,207 @@ static void qemu_rbd_memset(RADOSCB *rcb, int64_t offs)>      }>  }>> +#ifdef LIBRBD_SUPPORTS_ENCRYPTION> +static int qemu_rbd_convert_luks_options(> +        RbdEncryptionOptionsLUKSBase *luks_opts,> +        char **passphrase,> +        size_t *passphrase_len,> +        Error **errp)> +{> +    return qcrypto_secret_lookup(luks_opts->key_secret, (uint8_t **)passphrase,> +                                 passphrase_len, errp);> +}> +> +static int qemu_rbd_convert_luks_create_options(> +        RbdEncryptionCreateOptionsLUKSBase *luks

Re: [PATCH] block/rbd: Add support for rbd image encryption

2021-06-27 Thread Or Ozeri
Ilya,I fixed according to your suggestions, except for the passphrase zeroing.Looks like it's not a one-liner, but rather a long list of ifdefs to try and cover all possible platforms/compilers (this is what I've seen they do in k5-int.h).I didn't want to copy this into rbd.c.I guess that the right solution would be adding a qemu utility function (not sure where exactly), but anyways perhaps this, like the changes I previously made to raw_format.c, should be made in different patch.Thanks,Or-"Or Ozeri" <o...@il.ibm.com> wrote: -To: qemu-de...@nongnu.orgFrom: "Or Ozeri" <o...@il.ibm.com>Date: 06/27/2021 11:31AMCc: qemu-block@nongnu.org, o...@il.ibm.com, kw...@redhat.com, to.my.troc...@gmail.com, dan...@il.ibm.com, berra...@redhat.com, idryo...@gmail.comSubject: [PATCH] block/rbd: Add support for rbd image encryptionStarting from ceph Pacific, RBD has built-in support for image-level encryption.Currently supported formats are LUKS version 1 and 2.There are 2 new relevant librbd APIs for controlling encryption, both expect anopen image context:rbd_encryption_format: formats an image (i.e. writes the LUKS header)rbd_encryption_load: loads encryptor/decryptor to the image IO stackThis commit extends the qemu rbd driver API to support the above.Signed-off-by: Or Ozeri <o...@il.ibm.com>--- block/rbd.c          | 380 ++- qapi/block-core.json | 110 - 2 files changed, 484 insertions(+), 6 deletions(-)diff --git a/block/rbd.c b/block/rbd.cindex f098a89c7b..dadecaf3da 100644--- a/block/rbd.c+++ b/block/rbd.c@@ -73,6 +73,18 @@ #define LIBRBD_USE_IOVEC 0 #endif +#define RBD_ENCRYPTION_LUKS_HEADER_VERIFICATION_LEN 8++static const char rbd_luks_header_verification[+        RBD_ENCRYPTION_LUKS_HEADER_VERIFICATION_LEN] = {+    'L', 'U', 'K', 'S', 0xBA, 0xBE, 0, 1+};++static const char rbd_luks2_header_verification[+        RBD_ENCRYPTION_LUKS_HEADER_VERIFICATION_LEN] = {+    'L', 'U', 'K', 'S', 0xBA, 0xBE, 0, 2+};+ typedef enum {     RBD_AIO_READ,     RBD_AIO_WRITE,@@ -106,6 +118,7 @@ typedef struct BDRVRBDState {     char *snap;     char *namespace;     uint64_t image_size;+    ImageInfoSpecificRbd image_info; } BDRVRBDState;  static int qemu_rbd_connect(rados_t *cluster, rados_ioctx_t *io_ctx,@@ -341,6 +354,207 @@ static void qemu_rbd_memset(RADOSCB *rcb, int64_t offs)     } } +#ifdef LIBRBD_SUPPORTS_ENCRYPTION+static int qemu_rbd_convert_luks_options(+        RbdEncryptionOptionsLUKSBase *luks_opts,+        char **passphrase,+        size_t *passphrase_len,+        Error **errp)+{+    return qcrypto_secret_lookup(luks_opts->key_secret, (uint8_t **)passphrase,+                                 passphrase_len, errp);+}++static int qemu_rbd_convert_luks_create_options(+        RbdEncryptionCreateOptionsLUKSBase *luks_opts,+        rbd_encryption_algorithm_t *alg,+        char **passphrase,+        size_t *passphrase_len,+        Error **errp)+{+    int r = 0;++    r = qemu_rbd_convert_luks_options(+            qapi_RbdEncryptionCreateOptionsLUKSBase_base(luks_opts),+            passphrase, passphrase_len, errp);+    if (r < 0) {+        return r;+    }++    if (luks_opts->has_cipher_alg) {+        switch (luks_opts->cipher_alg) {+            case QCRYPTO_CIPHER_ALG_AES_128: {+                *alg = RBD_ENCRYPTION_ALGORITHM_AES128;+                break;+            }+            case QCRYPTO_CIPHER_ALG_AES_256: {+                *alg = RBD_ENCRYPTION_ALGORITHM_AES256;+                break;+            }+            default: {+                r = -ENOTSUP;+                error_setg_errno(errp, -r, "unknown encryption algorithm: %u",+                                 luks_opts->cipher_alg);+                return r;+            }+        }+    } else {+        /* default alg */+        *alg = RBD_ENCRYPTION_ALGORITHM_AES256;+    }++    return 0;+}++static int qemu_rbd_encryption_format(rbd_image_t image,+                                      RbdEncryptionCreateOptions *encrypt,+                                      Error **errp)+{+    int r = 0;+    g_autofree char *passphrase = NULL;+    size_t passphrase_len;+    rbd_encryption_format_t format;+    rbd_encryption_options_t opts;+    rbd_encryption_luks1_format_options_t luks_opts;+    rbd_encryption_luks2_format_options_t luks2_opts;+    size_t opts_size;+    uint64_t raw_size, effective_size;++    r = rbd_get_size(image, &raw_size);+    if (r < 0) {+        error_setg_errno(errp, -r, "cannot get raw image size");+        return r;+    }++    switch (encrypt->format) {+        case RBD_IMAGE_ENCRYPTION_FORMAT_LUKS: {+            memset(&luks_opts, 0, sizeof(luks_opts));+            format = RBD_ENCRYPTION_FORMAT_LUKS1;+            opts = &luks_opts;+            opts_size = sizeof(luks_opts);+            r = qemu_rbd_convert_luks_

[PATCH] block/rbd: Add support for rbd image encryption

2021-06-27 Thread Or Ozeri
Starting from ceph Pacific, RBD has built-in support for image-level encryption.
Currently supported formats are LUKS version 1 and 2.

There are 2 new relevant librbd APIs for controlling encryption, both expect an
open image context:

rbd_encryption_format: formats an image (i.e. writes the LUKS header)
rbd_encryption_load: loads encryptor/decryptor to the image IO stack

This commit extends the qemu rbd driver API to support the above.

Signed-off-by: Or Ozeri 
---
 block/rbd.c  | 380 ++-
 qapi/block-core.json | 110 -
 2 files changed, 484 insertions(+), 6 deletions(-)

diff --git a/block/rbd.c b/block/rbd.c
index f098a89c7b..dadecaf3da 100644
--- a/block/rbd.c
+++ b/block/rbd.c
@@ -73,6 +73,18 @@
 #define LIBRBD_USE_IOVEC 0
 #endif
 
+#define RBD_ENCRYPTION_LUKS_HEADER_VERIFICATION_LEN 8
+
+static const char rbd_luks_header_verification[
+RBD_ENCRYPTION_LUKS_HEADER_VERIFICATION_LEN] = {
+'L', 'U', 'K', 'S', 0xBA, 0xBE, 0, 1
+};
+
+static const char rbd_luks2_header_verification[
+RBD_ENCRYPTION_LUKS_HEADER_VERIFICATION_LEN] = {
+'L', 'U', 'K', 'S', 0xBA, 0xBE, 0, 2
+};
+
 typedef enum {
 RBD_AIO_READ,
 RBD_AIO_WRITE,
@@ -106,6 +118,7 @@ typedef struct BDRVRBDState {
 char *snap;
 char *namespace;
 uint64_t image_size;
+ImageInfoSpecificRbd image_info;
 } BDRVRBDState;
 
 static int qemu_rbd_connect(rados_t *cluster, rados_ioctx_t *io_ctx,
@@ -341,6 +354,207 @@ static void qemu_rbd_memset(RADOSCB *rcb, int64_t offs)
 }
 }
 
+#ifdef LIBRBD_SUPPORTS_ENCRYPTION
+static int qemu_rbd_convert_luks_options(
+RbdEncryptionOptionsLUKSBase *luks_opts,
+char **passphrase,
+size_t *passphrase_len,
+Error **errp)
+{
+return qcrypto_secret_lookup(luks_opts->key_secret, (uint8_t **)passphrase,
+ passphrase_len, errp);
+}
+
+static int qemu_rbd_convert_luks_create_options(
+RbdEncryptionCreateOptionsLUKSBase *luks_opts,
+rbd_encryption_algorithm_t *alg,
+char **passphrase,
+size_t *passphrase_len,
+Error **errp)
+{
+int r = 0;
+
+r = qemu_rbd_convert_luks_options(
+qapi_RbdEncryptionCreateOptionsLUKSBase_base(luks_opts),
+passphrase, passphrase_len, errp);
+if (r < 0) {
+return r;
+}
+
+if (luks_opts->has_cipher_alg) {
+switch (luks_opts->cipher_alg) {
+case QCRYPTO_CIPHER_ALG_AES_128: {
+*alg = RBD_ENCRYPTION_ALGORITHM_AES128;
+break;
+}
+case QCRYPTO_CIPHER_ALG_AES_256: {
+*alg = RBD_ENCRYPTION_ALGORITHM_AES256;
+break;
+}
+default: {
+r = -ENOTSUP;
+error_setg_errno(errp, -r, "unknown encryption algorithm: %u",
+ luks_opts->cipher_alg);
+return r;
+}
+}
+} else {
+/* default alg */
+*alg = RBD_ENCRYPTION_ALGORITHM_AES256;
+}
+
+return 0;
+}
+
+static int qemu_rbd_encryption_format(rbd_image_t image,
+  RbdEncryptionCreateOptions *encrypt,
+  Error **errp)
+{
+int r = 0;
+g_autofree char *passphrase = NULL;
+size_t passphrase_len;
+rbd_encryption_format_t format;
+rbd_encryption_options_t opts;
+rbd_encryption_luks1_format_options_t luks_opts;
+rbd_encryption_luks2_format_options_t luks2_opts;
+size_t opts_size;
+uint64_t raw_size, effective_size;
+
+r = rbd_get_size(image, &raw_size);
+if (r < 0) {
+error_setg_errno(errp, -r, "cannot get raw image size");
+return r;
+}
+
+switch (encrypt->format) {
+case RBD_IMAGE_ENCRYPTION_FORMAT_LUKS: {
+memset(&luks_opts, 0, sizeof(luks_opts));
+format = RBD_ENCRYPTION_FORMAT_LUKS1;
+opts = &luks_opts;
+opts_size = sizeof(luks_opts);
+r = qemu_rbd_convert_luks_create_options(
+qapi_RbdEncryptionCreateOptionsLUKS_base(&encrypt->u.luks),
+&luks_opts.alg, &passphrase, &passphrase_len, errp);
+if (r < 0) {
+return r;
+}
+luks_opts.passphrase = passphrase;
+luks_opts.passphrase_size = passphrase_len;
+break;
+}
+case RBD_IMAGE_ENCRYPTION_FORMAT_LUKS2: {
+memset(&luks2_opts, 0, sizeof(luks2_opts));
+format = RBD_ENCRYPTION_FORMAT_LUKS2;
+opts = &luks2_opts;
+opts_size = sizeof(luks2_opts);
+r = qemu_rbd_convert_luks_create_options(
+qapi_RbdEncryptionCreateOptionsLUKS2_base(
+   

[PATCH] block/rbd: Add support for rbd image encryption

2021-06-21 Thread Or Ozeri
Starting from ceph Pacific, RBD has built-in support for image-level encryption.
Currently supported formats are LUKS version 1 and 2.

There are 2 new relevant librbd APIs for controlling encryption, both expect an
open image context:

rbd_encryption_format: formats an image (i.e. writes the LUKS header)
rbd_encryption_load: loads encryptor/decryptor to the image IO stack

This commit extends the qemu rbd driver API to support the above.

Signed-off-by: Or Ozeri 
---
 block/rbd.c  | 367 ++-
 qapi/block-core.json | 110 -
 2 files changed, 471 insertions(+), 6 deletions(-)

diff --git a/block/rbd.c b/block/rbd.c
index f098a89c7b..7e282a8e94 100644
--- a/block/rbd.c
+++ b/block/rbd.c
@@ -73,6 +73,18 @@
 #define LIBRBD_USE_IOVEC 0
 #endif
 
+#define RBD_ENCRYPTION_LUKS_HEADER_VERIFICATION_LEN 8
+
+static const char rbd_luks_header_verification[
+RBD_ENCRYPTION_LUKS_HEADER_VERIFICATION_LEN] = {
+'L', 'U', 'K', 'S', 0xBA, 0xBE, 0, 1
+};
+
+static const char rbd_luks2_header_verification[
+RBD_ENCRYPTION_LUKS_HEADER_VERIFICATION_LEN] = {
+'L', 'U', 'K', 'S', 0xBA, 0xBE, 0, 2
+};
+
 typedef enum {
 RBD_AIO_READ,
 RBD_AIO_WRITE,
@@ -341,6 +353,202 @@ static void qemu_rbd_memset(RADOSCB *rcb, int64_t offs)
 }
 }
 
+#ifdef LIBRBD_SUPPORTS_ENCRYPTION
+static int qemu_rbd_convert_luks_options(
+RbdEncryptionOptionsLUKSBase *luks_opts,
+char **passphrase,
+size_t *passphrase_len,
+Error **errp)
+{
+return qcrypto_secret_lookup(
+luks_opts->key_secret, (uint8_t **)passphrase, passphrase_len, 
errp);
+}
+
+static int qemu_rbd_convert_luks_create_options(
+RbdEncryptionCreateOptionsLUKSBase *luks_opts,
+rbd_encryption_algorithm_t *alg,
+char **passphrase,
+size_t *passphrase_len,
+Error **errp)
+{
+int r = 0;
+
+r = qemu_rbd_convert_luks_options(
+qapi_RbdEncryptionCreateOptionsLUKSBase_base(luks_opts),
+passphrase, passphrase_len, errp);
+if (r < 0) {
+return r;
+}
+
+if (luks_opts->has_cipher_alg) {
+switch (luks_opts->cipher_alg) {
+case QCRYPTO_CIPHER_ALG_AES_128: {
+*alg = RBD_ENCRYPTION_ALGORITHM_AES128;
+break;
+}
+case QCRYPTO_CIPHER_ALG_AES_256: {
+*alg = RBD_ENCRYPTION_ALGORITHM_AES256;
+break;
+}
+default: {
+r = -ENOTSUP;
+error_setg_errno(errp, -r, "unknown encryption algorithm: %u",
+ luks_opts->cipher_alg);
+return r;
+}
+}
+} else {
+/* default alg */
+*alg = RBD_ENCRYPTION_ALGORITHM_AES256;
+}
+
+return 0;
+}
+
+static int qemu_rbd_encryption_format(rbd_image_t image,
+  RbdEncryptionCreateOptions *encrypt,
+  Error **errp)
+{
+int r = 0;
+g_autofree char *passphrase = NULL;
+size_t passphrase_len;
+rbd_encryption_format_t format;
+rbd_encryption_options_t opts;
+rbd_encryption_luks1_format_options_t luks_opts;
+rbd_encryption_luks2_format_options_t luks2_opts;
+size_t opts_size;
+uint64_t raw_size, effective_size;
+
+r = rbd_get_size(image, &raw_size);
+if (r < 0) {
+error_setg_errno(errp, -r, "cannot get raw image size");
+return r;
+}
+
+switch (encrypt->format) {
+case RBD_IMAGE_ENCRYPTION_FORMAT_LUKS: {
+memset(&luks_opts, 0, sizeof(luks_opts));
+format = RBD_ENCRYPTION_FORMAT_LUKS1;
+opts = &luks_opts;
+opts_size = sizeof(luks_opts);
+r = qemu_rbd_convert_luks_create_options(
+qapi_RbdEncryptionCreateOptionsLUKS_base(&encrypt->u.luks),
+&luks_opts.alg, &passphrase, &passphrase_len, errp);
+if (r < 0) {
+return r;
+}
+luks_opts.passphrase = passphrase;
+luks_opts.passphrase_size = passphrase_len;
+break;
+}
+case RBD_IMAGE_ENCRYPTION_FORMAT_LUKS2: {
+memset(&luks2_opts, 0, sizeof(luks2_opts));
+format = RBD_ENCRYPTION_FORMAT_LUKS2;
+opts = &luks2_opts;
+opts_size = sizeof(luks2_opts);
+r = qemu_rbd_convert_luks_create_options(
+qapi_RbdEncryptionCreateOptionsLUKS2_base(
+&encrypt->u.luks2),
+&luks2_opts.alg, &passphrase, &passphrase_len, errp);
+if (r < 0) {
+return r;
+}
+luks2_opts.passphrase = passphrase;
+  

[PATCH] block/rbd: Add support for rbd image encryption

2021-06-21 Thread Or Ozeri
Starting from ceph Pacific, RBD has built-in support for image-level encryption.
Currently supported formats are LUKS version 1 and 2.

There are 2 new relevant librbd APIs for controlling encryption, both expect an
open image context:

rbd_encryption_format: formats an image (i.e. writes the LUKS header)
rbd_encryption_load: loads encryptor/decryptor to the image IO stack

This commit extends the qemu rbd driver API to support the above.

Signed-off-by: Or Ozeri 
---
 block/rbd.c  | 367 ++-
 qapi/block-core.json | 110 -
 2 files changed, 471 insertions(+), 6 deletions(-)

diff --git a/block/rbd.c b/block/rbd.c
index f098a89c7b..be1419a9bd 100644
--- a/block/rbd.c
+++ b/block/rbd.c
@@ -73,6 +73,18 @@
 #define LIBRBD_USE_IOVEC 0
 #endif
 
+#define RBD_ENCRYPTION_LUKS_HEADER_VERIFICATION_LEN 8
+
+static const char rbd_luks_header_verification[
+RBD_ENCRYPTION_LUKS_HEADER_VERIFICATION_LEN] = {
+'L', 'U', 'K', 'S', 0xBA, 0xBE, 0, 1
+};
+
+static const char rbd_luks2_header_verification[
+RBD_ENCRYPTION_LUKS_HEADER_VERIFICATION_LEN] = {
+'L', 'U', 'K', 'S', 0xBA, 0xBE, 0, 2
+};
+
 typedef enum {
 RBD_AIO_READ,
 RBD_AIO_WRITE,
@@ -341,6 +353,202 @@ static void qemu_rbd_memset(RADOSCB *rcb, int64_t offs)
 }
 }
 
+#ifdef LIBRBD_SUPPORTS_ENCRYPTION
+static int qemu_rbd_convert_luks_options(
+RbdEncryptionOptionsLUKSBase *luks_opts,
+char **passphrase,
+size_t *passphrase_len,
+Error **errp)
+{
+return qcrypto_secret_lookup(
+luks_opts->key_secret, (uint8_t**)passphrase, passphrase_len, 
errp);
+}
+
+static int qemu_rbd_convert_luks_create_options(
+RbdEncryptionCreateOptionsLUKSBase *luks_opts,
+rbd_encryption_algorithm_t *alg,
+char **passphrase,
+size_t *passphrase_len,
+Error **errp)
+{
+int r = 0;
+
+r = qemu_rbd_convert_luks_options(
+qapi_RbdEncryptionCreateOptionsLUKSBase_base(luks_opts),
+passphrase, passphrase_len, errp);
+if (r < 0) {
+return r;
+}
+
+if (luks_opts->has_cipher_alg) {
+switch (luks_opts->cipher_alg) {
+case QCRYPTO_CIPHER_ALG_AES_128: {
+*alg = RBD_ENCRYPTION_ALGORITHM_AES128;
+break;
+}
+case QCRYPTO_CIPHER_ALG_AES_256: {
+*alg = RBD_ENCRYPTION_ALGORITHM_AES256;
+break;
+}
+default: {
+r = -ENOTSUP;
+error_setg_errno(errp, -r, "unknown encryption algorithm: %u",
+ luks_opts->cipher_alg);
+return r;
+}
+}
+} else {
+/* default alg */
+*alg = RBD_ENCRYPTION_ALGORITHM_AES256;
+}
+
+return 0;
+}
+
+static int qemu_rbd_encryption_format(rbd_image_t image,
+  RbdEncryptionCreateOptions *encrypt,
+  Error **errp)
+{
+int r = 0;
+g_autofree char *passphrase = NULL;
+size_t passphrase_len;
+rbd_encryption_format_t format;
+rbd_encryption_options_t opts;
+rbd_encryption_luks1_format_options_t luks_opts;
+rbd_encryption_luks2_format_options_t luks2_opts;
+size_t opts_size;
+uint64_t raw_size, effective_size;
+
+r = rbd_get_size(image, &raw_size);
+if (r < 0) {
+error_setg_errno(errp, -r, "cannot get raw image size");
+return r;
+}
+
+switch (encrypt->format) {
+case RBD_IMAGE_ENCRYPTION_FORMAT_LUKS: {
+memset(&luks_opts, 0, sizeof(luks_opts));
+format = RBD_ENCRYPTION_FORMAT_LUKS1;
+opts = &luks_opts;
+opts_size = sizeof(luks_opts);
+r = qemu_rbd_convert_luks_create_options(
+qapi_RbdEncryptionCreateOptionsLUKS_base(&encrypt->u.luks),
+&luks_opts.alg, &passphrase, &passphrase_len, errp);
+if (r < 0) {
+return r;
+}
+luks_opts.passphrase = passphrase;
+luks_opts.passphrase_size = passphrase_len;
+break;
+}
+case RBD_IMAGE_ENCRYPTION_FORMAT_LUKS2: {
+memset(&luks2_opts, 0, sizeof(luks2_opts));
+format = RBD_ENCRYPTION_FORMAT_LUKS2;
+opts = &luks2_opts;
+opts_size = sizeof(luks2_opts);
+r = qemu_rbd_convert_luks_create_options(
+qapi_RbdEncryptionCreateOptionsLUKS2_base(
+&encrypt->u.luks2),
+&luks2_opts.alg, &passphrase, &passphrase_len, errp);
+if (r < 0) {
+return r;
+}
+luks2_opts.passphrase = passphrase;
+  

RE: [PATCH] block/rbd: Add support for rbd image encryption

2021-06-20 Thread Or Ozeri
Thanks for your review!Regarding the last point:I currently don't have any plans for adding new luks2-only options, but they do exist. See in cryptsetup, for example the sector size which is configurable in luks2 only.In the librbd API we followed the same spirit and split luks1 and luks2 option structs.Same goes for passphrase (or "key-secret", as it called in qemu). In cryptsetup this is sort-of optional (there are other ways to authenticate othar than a passphrase, like a keyfile or a token).-Ilya Dryomov <idryo...@gmail.com> wrote: -To: Or Ozeri <o...@il.ibm.com>From: Ilya Dryomov <idryo...@gmail.com>Date: 06/19/2021 10:44PMCc: qemu-de...@nongnu.org, qemu-block@nongnu.org, kw...@redhat.com, Mykola Golub <to.my.troc...@gmail.com>, Danny Harnik <dan...@il.ibm.com>, berra...@redhat.comSubject: [EXTERNAL] Re: [PATCH] block/rbd: Add support for rbd image encryptionOn Thu, Jun 17, 2021 at 6:05 PM Or Ozeri <o...@il.ibm.com> wrote:>> Starting from ceph Pacific, RBD has built-in support for image-level encryption.> Currently supported formats are LUKS version 1 and 2.>> There are 2 new relevant librbd APIs for controlling encryption, both expect an> open image context:>> rbd_encryption_format: formats an image (i.e. writes the LUKS header)> rbd_encryption_load: loads encryptor/decryptor to the image IO stack>> This commit extends the qemu rbd driver API to support the above.>> Signed-off-by: Or Ozeri <o...@il.ibm.com>> --->  block/raw-format.c   |   7 +>  block/rbd.c          | 371 ++->  qapi/block-core.json | 110 ->  3 files changed, 482 insertions(+), 6 deletions(-)>> diff --git a/block/raw-format.c b/block/raw-format.c> index 7717578ed6..f6e70e2356 100644> --- a/block/raw-format.c> +++ b/block/raw-format.c> @@ -369,6 +369,12 @@ static int raw_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)>      return bdrv_get_info(bs->file->bs, bdi);>  }>> +static ImageInfoSpecific *raw_get_specific_info(BlockDriverState *bs,> +                                                Error **errp)> +{> +    return bdrv_get_specific_info(bs->file->bs, errp);> +}> +>  static void raw_refresh_limits(BlockDriverState *bs, Error **errp)>  {>      if (bs->probed) {> @@ -603,6 +609,7 @@ BlockDriver bdrv_raw = {>      .has_variable_length  = true,>      .bdrv_measure         = &raw_measure,>      .bdrv_get_info        = &raw_get_info,> +    .bdrv_get_specific_info = &raw_get_specific_info,Hi Or,This feels a bit contentious to me.AFAIU ImageInfoSpecific is for format-specfic information.  "raw"is a format and passing the request down the stack this way resultsin a somewhat confusing output such as    $ qemu-img info rbd:foo/bar    image: json:{"driver": "raw", "file": {"pool": "foo", "image":"bar", "driver": "rbd", "namespace": ""}}    file format: raw    ...    Format specific information:       I think this should be broken out into its own patch and get separateacks.>      .bdrv_refresh_limits  = &raw_refresh_limits,>      .bdrv_probe_blocksizes = &raw_probe_blocksizes,>      .bdrv_probe_geometry  = &raw_probe_geometry,> diff --git a/block/rbd.c b/block/rbd.c> index f098a89c7b..183b17cd84 100644> --- a/block/rbd.c> +++ b/block/rbd.c> @@ -73,6 +73,18 @@>  #define LIBRBD_USE_IOVEC 0>  #endif>> +#define RBD_ENCRYPTION_LUKS_HEADER_VERIFICATION_LEN 8> +> +static const char rbd_luks_header_verification[> +        RBD_ENCRYPTION_LUKS_HEADER_VERIFICATION_LEN] = {> +    'L', 'U', 'K', 'S', 0xBA, 0xBE, 0, 1> +};> +> +static const char rbd_luks2_header_verification[> +        RBD_ENCRYPTION_LUKS_HEADER_VERIFICATION_LEN] = {> +    'L', 'U', 'K', 'S', 0xBA, 0xBE, 0, 2> +};> +>  typedef enum {>      RBD_AIO_READ,>      RBD_AIO_WRITE,> @@ -341,6 +353,206 @@ static void qemu_rbd_memset(RADOSCB *rcb, int64_t offs)>      }>  }>> +#ifdef LIBRBD_SUPPORTS_ENCRYPTION> +static int qemu_rbd_convert_luks_options(> +        RbdEncryptionOptionsLUKSBase *luks_opts,> +        char **passphrase,> +        Error **errp)> +{> +    int r = 0;> +> +    if (!luks_opts->has_key_secret) {> +        r = -EINVAL;> +        error_setg_errno(errp, -r, "missing encrypt.key-secret");> +        return r;> +    }Why is key-secret optional?> +> +    *passphrase = qcrypto_secret_lookup_as_utf8(luks_opts->key_secret, errp);> +    if (!*passphrase) {> +        return -EIO;> +    }> +> +    return 0;> +}> +> +static int qem

[PATCH] block/rbd: Add support for rbd image encryption

2021-06-17 Thread Or Ozeri
Starting from ceph Pacific, RBD has built-in support for image-level encryption.
Currently supported formats are LUKS version 1 and 2.

There are 2 new relevant librbd APIs for controlling encryption, both expect an
open image context:

rbd_encryption_format: formats an image (i.e. writes the LUKS header)
rbd_encryption_load: loads encryptor/decryptor to the image IO stack

This commit extends the qemu rbd driver API to support the above.

Signed-off-by: Or Ozeri 
---
 block/raw-format.c   |   7 +
 block/rbd.c  | 371 ++-
 qapi/block-core.json | 110 -
 3 files changed, 482 insertions(+), 6 deletions(-)

diff --git a/block/raw-format.c b/block/raw-format.c
index 7717578ed6..f6e70e2356 100644
--- a/block/raw-format.c
+++ b/block/raw-format.c
@@ -369,6 +369,12 @@ static int raw_get_info(BlockDriverState *bs, 
BlockDriverInfo *bdi)
 return bdrv_get_info(bs->file->bs, bdi);
 }
 
+static ImageInfoSpecific *raw_get_specific_info(BlockDriverState *bs,
+Error **errp)
+{
+return bdrv_get_specific_info(bs->file->bs, errp);
+}
+
 static void raw_refresh_limits(BlockDriverState *bs, Error **errp)
 {
 if (bs->probed) {
@@ -603,6 +609,7 @@ BlockDriver bdrv_raw = {
 .has_variable_length  = true,
 .bdrv_measure = &raw_measure,
 .bdrv_get_info= &raw_get_info,
+.bdrv_get_specific_info = &raw_get_specific_info,
 .bdrv_refresh_limits  = &raw_refresh_limits,
 .bdrv_probe_blocksizes = &raw_probe_blocksizes,
 .bdrv_probe_geometry  = &raw_probe_geometry,
diff --git a/block/rbd.c b/block/rbd.c
index f098a89c7b..183b17cd84 100644
--- a/block/rbd.c
+++ b/block/rbd.c
@@ -73,6 +73,18 @@
 #define LIBRBD_USE_IOVEC 0
 #endif
 
+#define RBD_ENCRYPTION_LUKS_HEADER_VERIFICATION_LEN 8
+
+static const char rbd_luks_header_verification[
+RBD_ENCRYPTION_LUKS_HEADER_VERIFICATION_LEN] = {
+'L', 'U', 'K', 'S', 0xBA, 0xBE, 0, 1
+};
+
+static const char rbd_luks2_header_verification[
+RBD_ENCRYPTION_LUKS_HEADER_VERIFICATION_LEN] = {
+'L', 'U', 'K', 'S', 0xBA, 0xBE, 0, 2
+};
+
 typedef enum {
 RBD_AIO_READ,
 RBD_AIO_WRITE,
@@ -341,6 +353,206 @@ static void qemu_rbd_memset(RADOSCB *rcb, int64_t offs)
 }
 }
 
+#ifdef LIBRBD_SUPPORTS_ENCRYPTION
+static int qemu_rbd_convert_luks_options(
+RbdEncryptionOptionsLUKSBase *luks_opts,
+char **passphrase,
+Error **errp)
+{
+int r = 0;
+
+if (!luks_opts->has_key_secret) {
+r = -EINVAL;
+error_setg_errno(errp, -r, "missing encrypt.key-secret");
+return r;
+}
+
+*passphrase = qcrypto_secret_lookup_as_utf8(luks_opts->key_secret, errp);
+if (!*passphrase) {
+return -EIO;
+}
+
+return 0;
+}
+
+static int qemu_rbd_convert_luks_create_options(
+RbdEncryptionCreateOptionsLUKSBase *luks_opts,
+rbd_encryption_algorithm_t *alg,
+char **passphrase,
+Error **errp)
+{
+int r = 0;
+
+r = qemu_rbd_convert_luks_options(
+qapi_RbdEncryptionCreateOptionsLUKSBase_base(luks_opts),
+passphrase, errp);
+if (r < 0) {
+return r;
+}
+
+if (luks_opts->has_cipher_alg) {
+switch (luks_opts->cipher_alg) {
+case QCRYPTO_CIPHER_ALG_AES_128: {
+*alg = RBD_ENCRYPTION_ALGORITHM_AES128;
+break;
+}
+case QCRYPTO_CIPHER_ALG_AES_256: {
+*alg = RBD_ENCRYPTION_ALGORITHM_AES256;
+break;
+}
+default: {
+r = -ENOTSUP;
+error_setg_errno(errp, -r, "unknown encryption algorithm: %u",
+ luks_opts->cipher_alg);
+return r;
+}
+}
+} else {
+/* default alg */
+*alg = RBD_ENCRYPTION_ALGORITHM_AES256;
+}
+
+return 0;
+}
+
+static int qemu_rbd_encryption_format(rbd_image_t image,
+  RbdEncryptionCreateOptions *encrypt,
+  Error **errp)
+{
+int r = 0;
+g_autofree char *passphrase = NULL;
+g_autofree rbd_encryption_options_t opts = NULL;
+rbd_encryption_format_t format;
+rbd_image_info_t info;
+size_t opts_size;
+uint64_t raw_size;
+
+r = rbd_stat(image, &info, sizeof(info));
+if (r < 0) {
+error_setg_errno(errp, -r, "cannot get raw image size");
+return r;
+}
+raw_size = info.size;
+
+switch (encrypt->format) {
+case RBD_IMAGE_ENCRYPTION_FORMAT_LUKS: {
+rbd_encryption_luks1_format_options_t *luks_opts =
+g_new0(rbd_encryption_luks1_format_options_t, 1);
+format = RBD_ENCR

RE: [PATCH] block/rbd: Add support for rbd image encryption

2021-05-05 Thread Or Ozeri
Thanks Daniel!I prepared a modified patch addressing all of your suggestions (including resizing after formatting to increase the image size).The only thing I'm not sure about is your last point regarding reporting image is encrypted.When I followed the flow of "qemu-img info" on an "rbd:pool/image" I saw that this information is extracted from the root BlockDriverState.In our case, the root BlockDriverState comes from:BlockDriver bdrv_raw = {    .format_name          = "raw",...The RBD driver is a child of this root raw driver.Given this situation, it is not clear to me how can I set:bs->drv->format_name="luks2", bs->encrypted=trueOn the root BlockDriverState.Any advice?-"Daniel P. Berrangé" <berra...@redhat.com> wrote: -To: Or Ozeri <o...@il.ibm.com>From: "Daniel P. Berrangé" <berra...@redhat.com>Date: 05/04/2021 05:47PMCc: qemu-de...@nongnu.org, kw...@redhat.com, to.my.troc...@gmail.com, qemu-block@nongnu.org, dan...@il.ibm.comSubject: [EXTERNAL] Re: [PATCH] block/rbd: Add support for rbd image encryptionOn Sun, May 02, 2021 at 10:36:17AM +0300, Or Ozeri wrote:> Starting from ceph Pacific, RBD has built-in support for image-level encryption.> Currently supported formats are LUKS version 1 and 2.> > There are 2 new relevant librbd APIs for controlling encryption, both expect an> open image context:> > rbd_encryption_format: formats an image (i.e. writes the LUKS header)> rbd_encryption_load: loads encryptor/decryptor to the image IO stack> > This commit extends the qemu rbd driver API to support the above.> > Signed-off-by: Or Ozeri <o...@il.ibm.com>> --->  block/rbd.c          | 230 ++->  qapi/block-core.json |  61 >  2 files changed, 287 insertions(+), 4 deletions(-)> > diff --git a/block/rbd.c b/block/rbd.c> index f098a89c7b..1239e97889 100644> --- a/block/rbd.c> +++ b/block/rbd.c> @@ -108,6 +108,13 @@ typedef struct BDRVRBDState {>      uint64_t image_size;>  } BDRVRBDState;>  > +#ifdef LIBRBD_SUPPORTS_ENCRYPTION> +typedef int (*RbdEncryptionFunc)(rbd_image_t image,> +                                 rbd_encryption_format_t format,> +                                 rbd_encryption_options_t opts,> +                                 size_t opts_size);> +#endif> +>  static int qemu_rbd_connect(rados_t *cluster, rados_ioctx_t *io_ctx,>                              BlockdevOptionsRbd *opts, bool cache,>                              const char *keypairs, const char *secretid,> @@ -341,6 +348,115 @@ static void qemu_rbd_memset(RADOSCB *rcb, int64_t offs)>      }>  }>  > +#ifdef LIBRBD_SUPPORTS_ENCRYPTION> +static int qemu_rbd_convert_luks_options(> +        RbdEncryptionOptionsLUKSBase *luks_opts,> +        rbd_encryption_algorithm_t *alg,> +        char** passphrase,> +        Error **errp)> +{> +    int r = 0;> +> +    if (!luks_opts->has_passphrase_secret) {> +        r = -EINVAL;> +        error_setg_errno(errp, -r, "missing encrypt.passphrase-secret");> +        return r;> +    }> +> +    *passphrase = qcrypto_secret_lookup_as_utf8(luks_opts->passphrase_secret,> +                                                errp);> +    if (!*passphrase) {> +        return -EIO;> +    }> +> +    if (luks_opts->has_cipher_alg) {> +        switch (luks_opts->cipher_alg) {> +            case RBD_ENCRYPTION_ALGORITHM_AES_128: {> +                *alg = RBD_ENCRYPTION_ALGORITHM_AES128;> +                break;> +            }> +            case RBD_ENCRYPTION_ALGORITHM_AES_256: {> +                *alg = RBD_ENCRYPTION_ALGORITHM_AES256;> +                break;> +            }> +            default: {> +                r = -ENOTSUP;> +                error_setg_errno(errp, -r, "unknown encryption algorithm: %u",> +                                 luks_opts->cipher_alg);> +                return r;> +            }> +        }> +    } else {> +        /* default alg */> +        *alg = RBD_ENCRYPTION_ALGORITHM_AES256;> +    }> +> +    return 0;> +}> +> +static int qemu_rbd_apply_encryption_function(rbd_image_t image,> +                                              RbdEncryptionSpec* spec,> +                                              RbdEncryptionFunc func,> +                                              Error **errp)> +{> +    int r = 0;> +    g_autofree char *passphrase = NULL;> +    g_autofree rbd_encryption_options_t opts = NULL;> +    rbd_encryption_format_t format;> +    size_t opts_size;> +> +    switch (spec->format) {> +        case RBD_IMAGE_ENCRYPTION_FORMAT_LUKS1: {> +            rbd_encryption_luks1_format_op

[PATCH] block/rbd: Add support for rbd image encryption

2021-05-05 Thread Or Ozeri
Starting from ceph Pacific, RBD has built-in support for image-level encryption.
Currently supported formats are LUKS version 1 and 2.

There are 2 new relevant librbd APIs for controlling encryption, both expect an
open image context:

rbd_encryption_format: formats an image (i.e. writes the LUKS header)
rbd_encryption_load: loads encryptor/decryptor to the image IO stack

This commit extends the qemu rbd driver API to support the above.

Signed-off-by: Or Ozeri 
---
 block/raw-format.c   |   7 +
 block/rbd.c  | 371 ++-
 qapi/block-core.json | 110 -
 3 files changed, 482 insertions(+), 6 deletions(-)

diff --git a/block/raw-format.c b/block/raw-format.c
index 7717578ed6..f6e70e2356 100644
--- a/block/raw-format.c
+++ b/block/raw-format.c
@@ -369,6 +369,12 @@ static int raw_get_info(BlockDriverState *bs, 
BlockDriverInfo *bdi)
 return bdrv_get_info(bs->file->bs, bdi);
 }
 
+static ImageInfoSpecific *raw_get_specific_info(BlockDriverState *bs,
+Error **errp)
+{
+return bdrv_get_specific_info(bs->file->bs, errp);
+}
+
 static void raw_refresh_limits(BlockDriverState *bs, Error **errp)
 {
 if (bs->probed) {
@@ -603,6 +609,7 @@ BlockDriver bdrv_raw = {
 .has_variable_length  = true,
 .bdrv_measure = &raw_measure,
 .bdrv_get_info= &raw_get_info,
+.bdrv_get_specific_info = &raw_get_specific_info,
 .bdrv_refresh_limits  = &raw_refresh_limits,
 .bdrv_probe_blocksizes = &raw_probe_blocksizes,
 .bdrv_probe_geometry  = &raw_probe_geometry,
diff --git a/block/rbd.c b/block/rbd.c
index f098a89c7b..183b17cd84 100644
--- a/block/rbd.c
+++ b/block/rbd.c
@@ -73,6 +73,18 @@
 #define LIBRBD_USE_IOVEC 0
 #endif
 
+#define RBD_ENCRYPTION_LUKS_HEADER_VERIFICATION_LEN 8
+
+static const char rbd_luks_header_verification[
+RBD_ENCRYPTION_LUKS_HEADER_VERIFICATION_LEN] = {
+'L', 'U', 'K', 'S', 0xBA, 0xBE, 0, 1
+};
+
+static const char rbd_luks2_header_verification[
+RBD_ENCRYPTION_LUKS_HEADER_VERIFICATION_LEN] = {
+'L', 'U', 'K', 'S', 0xBA, 0xBE, 0, 2
+};
+
 typedef enum {
 RBD_AIO_READ,
 RBD_AIO_WRITE,
@@ -341,6 +353,206 @@ static void qemu_rbd_memset(RADOSCB *rcb, int64_t offs)
 }
 }
 
+#ifdef LIBRBD_SUPPORTS_ENCRYPTION
+static int qemu_rbd_convert_luks_options(
+RbdEncryptionOptionsLUKSBase *luks_opts,
+char **passphrase,
+Error **errp)
+{
+int r = 0;
+
+if (!luks_opts->has_key_secret) {
+r = -EINVAL;
+error_setg_errno(errp, -r, "missing encrypt.key-secret");
+return r;
+}
+
+*passphrase = qcrypto_secret_lookup_as_utf8(luks_opts->key_secret, errp);
+if (!*passphrase) {
+return -EIO;
+}
+
+return 0;
+}
+
+static int qemu_rbd_convert_luks_create_options(
+RbdEncryptionCreateOptionsLUKSBase *luks_opts,
+rbd_encryption_algorithm_t *alg,
+char **passphrase,
+Error **errp)
+{
+int r = 0;
+
+r = qemu_rbd_convert_luks_options(
+qapi_RbdEncryptionCreateOptionsLUKSBase_base(luks_opts),
+passphrase, errp);
+if (r < 0) {
+return r;
+}
+
+if (luks_opts->has_cipher_alg) {
+switch (luks_opts->cipher_alg) {
+case QCRYPTO_CIPHER_ALG_AES_128: {
+*alg = RBD_ENCRYPTION_ALGORITHM_AES128;
+break;
+}
+case QCRYPTO_CIPHER_ALG_AES_256: {
+*alg = RBD_ENCRYPTION_ALGORITHM_AES256;
+break;
+}
+default: {
+r = -ENOTSUP;
+error_setg_errno(errp, -r, "unknown encryption algorithm: %u",
+ luks_opts->cipher_alg);
+return r;
+}
+}
+} else {
+/* default alg */
+*alg = RBD_ENCRYPTION_ALGORITHM_AES256;
+}
+
+return 0;
+}
+
+static int qemu_rbd_encryption_format(rbd_image_t image,
+  RbdEncryptionCreateOptions *encrypt,
+  Error **errp)
+{
+int r = 0;
+g_autofree char *passphrase = NULL;
+g_autofree rbd_encryption_options_t opts = NULL;
+rbd_encryption_format_t format;
+rbd_image_info_t info;
+size_t opts_size;
+uint64_t raw_size;
+
+r = rbd_stat(image, &info, sizeof(info));
+if (r < 0) {
+error_setg_errno(errp, -r, "cannot get raw image size");
+return r;
+}
+raw_size = info.size;
+
+switch (encrypt->format) {
+case RBD_IMAGE_ENCRYPTION_FORMAT_LUKS: {
+rbd_encryption_luks1_format_options_t *luks_opts =
+g_new0(rbd_encryption_luks1_format_options_t, 1);
+format = RBD_ENCR

[PATCH] block/rbd: Add support for rbd image encryption

2021-05-02 Thread Or Ozeri
Starting from ceph Pacific, RBD has built-in support for image-level encryption.
Currently supported formats are LUKS version 1 and 2.

There are 2 new relevant librbd APIs for controlling encryption, both expect an
open image context:

rbd_encryption_format: formats an image (i.e. writes the LUKS header)
rbd_encryption_load: loads encryptor/decryptor to the image IO stack

This commit extends the qemu rbd driver API to support the above.

Signed-off-by: Or Ozeri 
---
 block/rbd.c  | 230 ++-
 qapi/block-core.json |  61 
 2 files changed, 287 insertions(+), 4 deletions(-)

diff --git a/block/rbd.c b/block/rbd.c
index f098a89c7b..1239e97889 100644
--- a/block/rbd.c
+++ b/block/rbd.c
@@ -108,6 +108,13 @@ typedef struct BDRVRBDState {
 uint64_t image_size;
 } BDRVRBDState;
 
+#ifdef LIBRBD_SUPPORTS_ENCRYPTION
+typedef int (*RbdEncryptionFunc)(rbd_image_t image,
+ rbd_encryption_format_t format,
+ rbd_encryption_options_t opts,
+ size_t opts_size);
+#endif
+
 static int qemu_rbd_connect(rados_t *cluster, rados_ioctx_t *io_ctx,
 BlockdevOptionsRbd *opts, bool cache,
 const char *keypairs, const char *secretid,
@@ -341,6 +348,115 @@ static void qemu_rbd_memset(RADOSCB *rcb, int64_t offs)
 }
 }
 
+#ifdef LIBRBD_SUPPORTS_ENCRYPTION
+static int qemu_rbd_convert_luks_options(
+RbdEncryptionOptionsLUKSBase *luks_opts,
+rbd_encryption_algorithm_t *alg,
+char** passphrase,
+Error **errp)
+{
+int r = 0;
+
+if (!luks_opts->has_passphrase_secret) {
+r = -EINVAL;
+error_setg_errno(errp, -r, "missing encrypt.passphrase-secret");
+return r;
+}
+
+*passphrase = qcrypto_secret_lookup_as_utf8(luks_opts->passphrase_secret,
+errp);
+if (!*passphrase) {
+return -EIO;
+}
+
+if (luks_opts->has_cipher_alg) {
+switch (luks_opts->cipher_alg) {
+case RBD_ENCRYPTION_ALGORITHM_AES_128: {
+*alg = RBD_ENCRYPTION_ALGORITHM_AES128;
+break;
+}
+case RBD_ENCRYPTION_ALGORITHM_AES_256: {
+*alg = RBD_ENCRYPTION_ALGORITHM_AES256;
+break;
+}
+default: {
+r = -ENOTSUP;
+error_setg_errno(errp, -r, "unknown encryption algorithm: %u",
+ luks_opts->cipher_alg);
+return r;
+}
+}
+} else {
+/* default alg */
+*alg = RBD_ENCRYPTION_ALGORITHM_AES256;
+}
+
+return 0;
+}
+
+static int qemu_rbd_apply_encryption_function(rbd_image_t image,
+  RbdEncryptionSpec* spec,
+  RbdEncryptionFunc func,
+  Error **errp)
+{
+int r = 0;
+g_autofree char *passphrase = NULL;
+g_autofree rbd_encryption_options_t opts = NULL;
+rbd_encryption_format_t format;
+size_t opts_size;
+
+switch (spec->format) {
+case RBD_IMAGE_ENCRYPTION_FORMAT_LUKS1: {
+rbd_encryption_luks1_format_options_t *luks1_opts =
+g_new0(rbd_encryption_luks1_format_options_t, 1);
+format = RBD_ENCRYPTION_FORMAT_LUKS1;
+opts = luks1_opts;
+opts_size = sizeof(rbd_encryption_luks1_format_options_t);
+r = qemu_rbd_convert_luks_options(
+qapi_RbdEncryptionOptionsLUKS1_base(&spec->u.luks1),
+&luks1_opts->alg, &passphrase, errp);
+if (passphrase) {
+luks1_opts->passphrase = passphrase;
+luks1_opts->passphrase_size = strlen(passphrase);
+}
+break;
+}
+case RBD_IMAGE_ENCRYPTION_FORMAT_LUKS2: {
+rbd_encryption_luks2_format_options_t *luks2_opts =
+g_new0(rbd_encryption_luks2_format_options_t, 1);
+format = RBD_ENCRYPTION_FORMAT_LUKS2;
+opts = luks2_opts;
+opts_size = sizeof(rbd_encryption_luks2_format_options_t);
+r = qemu_rbd_convert_luks_options(
+qapi_RbdEncryptionOptionsLUKS2_base(&spec->u.luks2),
+&luks2_opts->alg, &passphrase, errp);
+if (passphrase) {
+luks2_opts->passphrase = passphrase;
+luks2_opts->passphrase_size = strlen(passphrase);
+}
+break;
+}
+default: {
+r = -ENOTSUP;
+error_setg_errno(
+errp, -r, "unknown image encryption format: %u",
+spec->format);
+}
+}
+
+