aboutsummaryrefslogtreecommitdiff
path: root/block/rbd.c
diff options
context:
space:
mode:
Diffstat (limited to 'block/rbd.c')
-rw-r--r--block/rbd.c153
1 files changed, 152 insertions, 1 deletions
diff --git a/block/rbd.c b/block/rbd.c
index 744f84c..9786714 100644
--- a/block/rbd.c
+++ b/block/rbd.c
@@ -72,6 +72,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,
@@ -538,6 +548,128 @@ 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->parent; curr_encrypt;
+ 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;
+ }
+
+exit:
+ for (i = 0; i < encrypt_count; ++i) {
+ if (!specs[i].opts) {
+ break;
+ }
+
+ switch (specs[i].format) {
+ case RBD_ENCRYPTION_FORMAT_LUKS1: {
+ luks_opts = specs[i].opts;
+ g_free((void *)luks_opts->passphrase);
+ break;
+ }
+ case RBD_ENCRYPTION_FORMAT_LUKS2: {
+ luks2_opts = specs[i].opts;
+ g_free((void *)luks2_opts->passphrase);
+ break;
+ }
+ case RBD_ENCRYPTION_FORMAT_LUKS: {
+ luks_any_opts = specs[i].opts;
+ g_free((void *)luks_any_opts->passphrase);
+ break;
+ }
+ }
+
+ g_free(specs[i].opts);
+ }
+ g_free(specs);
+ return r;
+}
+#endif
#endif
/* FIXME Deprecate and remove keypairs or make it available in QMP. */
@@ -1004,7 +1136,16 @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
if (opts->encrypt) {
#ifdef LIBRBD_SUPPORTS_ENCRYPTION
- r = qemu_rbd_encryption_load(s->image, opts->encrypt, errp);
+ if (opts->encrypt->parent) {
+#ifdef LIBRBD_SUPPORTS_ENCRYPTION_LOAD2
+ r = qemu_rbd_encryption_load2(s->image, opts->encrypt, errp);
+#else
+ r = -ENOTSUP;
+ error_setg(errp, "RBD library does not support layered encryption");
+#endif
+ } else {
+ r = qemu_rbd_encryption_load(s->image, opts->encrypt, errp);
+ }
if (r < 0) {
goto failed_post_open;
}
@@ -1296,6 +1437,16 @@ static ImageInfoSpecific *qemu_rbd_get_specific_info(BlockDriverState *bs,
spec_info->u.rbd.data->encryption_format =
RBD_IMAGE_ENCRYPTION_FORMAT_LUKS2;
spec_info->u.rbd.data->has_encryption_format = true;
+ } else if (memcmp(buf, rbd_layered_luks_header_verification,
+ RBD_ENCRYPTION_LUKS_HEADER_VERIFICATION_LEN) == 0) {
+ spec_info->u.rbd.data->encryption_format =
+ RBD_IMAGE_ENCRYPTION_FORMAT_LUKS;
+ spec_info->u.rbd.data->has_encryption_format = true;
+ } else if (memcmp(buf, rbd_layered_luks2_header_verification,
+ RBD_ENCRYPTION_LUKS_HEADER_VERIFICATION_LEN) == 0) {
+ spec_info->u.rbd.data->encryption_format =
+ RBD_IMAGE_ENCRYPTION_FORMAT_LUKS2;
+ spec_info->u.rbd.data->has_encryption_format = true;
} else {
spec_info->u.rbd.data->has_encryption_format = false;
}