From patchwork Sun Nov 13 10:17:27 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Or Ozeri X-Patchwork-Id: 1703217 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=ibm.com header.i=@ibm.com header.a=rsa-sha256 header.s=pp1 header.b=iOjDW2/9; dkim-atps=neutral Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-ECDSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4N97h03NGqz23mj for ; Sun, 13 Nov 2022 21:18:40 +1100 (AEDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1ouA3k-00083g-AC; Sun, 13 Nov 2022 05:17:52 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1ouA3h-0007zj-Vz; Sun, 13 Nov 2022 05:17:50 -0500 Received: from mx0b-001b2d01.pphosted.com ([148.163.158.5]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1ouA3f-0006M3-4k; Sun, 13 Nov 2022 05:17:48 -0500 Received: from pps.filterd (m0098417.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.17.1.19/8.17.1.5) with ESMTP id 2ADAEoU0015064; Sun, 13 Nov 2022 10:17:45 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ibm.com; h=from : to : cc : subject : date : message-id : mime-version : content-transfer-encoding; s=pp1; bh=GDYJpMWHj0MhQxk9e1ngrGk0gK552jw76TbPdA0aqp8=; b=iOjDW2/9a9Fr6uM022SkRvEl3rxBY/gCbAYMhqYxAcFDm/frSbesyIeGCOUzPzZaC32/ AecvMCzAH5W64qQtyAOWf/QDM9e2t/LA1lduXADDqh4+qoHvRNO6NdGvh7BYWXbc56FK +LKJpT5Q5n3z0SodhRUBt7xlYTOU4XYwLx0J/kC6tScMmJ+Cq0Jn1GZrQfqpjzYKCz0n 3clLlji/Ha85xVHMKmeAa7mHoiJwHiugYaVndMIB7gUDedSk8ku5Sf/b6lzabLeILVR4 l3SjJAQW2t2vytBnt7lPxJWcnysXAaAoKdgyGe+QSzMrSQIHRigQ39bG9ATDOSPlZFnE UQ== Received: from pps.reinject (localhost [127.0.0.1]) by mx0a-001b2d01.pphosted.com (PPS) with ESMTPS id 3ktxnkg1qb-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Sun, 13 Nov 2022 10:17:44 +0000 Received: from m0098417.ppops.net (m0098417.ppops.net [127.0.0.1]) by pps.reinject (8.17.1.5/8.17.1.5) with ESMTP id 2ADAGHLQ022236; Sun, 13 Nov 2022 10:17:44 GMT Received: from ppma05wdc.us.ibm.com (1b.90.2fa9.ip4.static.sl-reverse.com [169.47.144.27]) by mx0a-001b2d01.pphosted.com (PPS) with ESMTPS id 3ktxnkg1q6-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Sun, 13 Nov 2022 10:17:44 +0000 Received: from pps.filterd (ppma05wdc.us.ibm.com [127.0.0.1]) by ppma05wdc.us.ibm.com (8.16.1.2/8.16.1.2) with SMTP id 2ADA6hoR009207; Sun, 13 Nov 2022 10:17:43 GMT Received: from b01cxnp22033.gho.pok.ibm.com (b01cxnp22033.gho.pok.ibm.com [9.57.198.23]) by ppma05wdc.us.ibm.com with ESMTP id 3kt349ffp1-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Sun, 13 Nov 2022 10:17:43 +0000 Received: from smtpav01.wdc07v.mail.ibm.com ([9.208.128.113]) by b01cxnp22033.gho.pok.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 2ADAHfQQ4981368 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Sun, 13 Nov 2022 10:17:42 GMT Received: from smtpav01.wdc07v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 7C29C5804B; Sun, 13 Nov 2022 10:17:41 +0000 (GMT) Received: from smtpav01.wdc07v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 9501E58055; Sun, 13 Nov 2022 10:17:40 +0000 (GMT) Received: from oro.sl.cloud9.ibm.com (unknown [9.59.192.176]) by smtpav01.wdc07v.mail.ibm.com (Postfix) with ESMTP; Sun, 13 Nov 2022 10:17:40 +0000 (GMT) From: Or Ozeri To: qemu-devel@nongnu.org Cc: qemu-block@nongnu.org, oro@il.ibm.com, dannyh@il.ibm.com, idryomov@gmail.com Subject: [PATCH v2] block/rbd: Add support for layered encryption Date: Sun, 13 Nov 2022 04:17:27 -0600 Message-Id: <20221113101727.2801739-1-oro@il.ibm.com> X-Mailer: git-send-email 2.25.1 MIME-Version: 1.0 X-TM-AS-GCONF: 00 X-Proofpoint-GUID: wgwv3ilruEXh0Ivz7QFVeFQ5fGlKCsLz X-Proofpoint-ORIG-GUID: gYqIySdL4n_hRl6OlD7fjZxUkqyOyGsd X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.219,Aquarius:18.0.895,Hydra:6.0.545,FMLib:17.11.122.1 definitions=2022-11-13_07,2022-11-11_01,2022-06-22_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 priorityscore=1501 malwarescore=0 mlxlogscore=825 suspectscore=0 phishscore=0 spamscore=0 clxscore=1011 lowpriorityscore=0 bulkscore=0 mlxscore=0 impostorscore=0 adultscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2210170000 definitions=main-2211130066 Received-SPF: pass client-ip=148.163.158.5; envelope-from=oro@il.ibm.com; helo=mx0b-001b2d01.pphosted.com X-Spam_score_int: -19 X-Spam_score: -2.0 X-Spam_bar: -- X-Spam_report: (-2.0 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_MSPIKE_H2=-0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org 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_luks_format_options_t*)(specs[i].opts); + g_free(luks_any_opts); + g_free(passphrases[i]); + } + g_free(passphrases); + g_free(specs); + return r; +} +#endif #endif /* FIXME Deprecate and remove keypairs or make it available in QMP. */ @@ -993,7 +1093,17 @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags, if (opts->has_encrypt) { #ifdef LIBRBD_SUPPORTS_ENCRYPTION - r = qemu_rbd_encryption_load(s->image, opts->encrypt, errp); + if (opts->encrypt->has_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" + " specifying parent encryption"); +#endif + } else { + r = qemu_rbd_encryption_load(s->image, opts->encrypt, errp); + } if (r < 0) { goto failed_post_open; } @@ -1284,6 +1394,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_LAYERED; + 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_LAYERED; + spec_info->u.rbd.data->has_encryption_format = true; } else { spec_info->u.rbd.data->has_encryption_format = false; } diff --git a/qapi/block-core.json b/qapi/block-core.json index 882b266532..c8f0ad56b8 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -3753,10 +3753,20 @@ ## # @RbdImageEncryptionFormat: # +# luks +# +# luks2 +# +# luks-any: Used for opening either luks or luks2. (Since 7.2) +# +# luks-layered: Layered encryption. Only used for info. (Since 7.2) +# +# luks2-layered: Layered encryption. Only used for info. (Since 7.2) +# # Since: 6.1 ## { 'enum': 'RbdImageEncryptionFormat', - 'data': [ 'luks', 'luks2' ] } + 'data': [ 'luks', 'luks2', 'luks-any', 'luks-layered', 'luks2-layered' ] } ## # @RbdEncryptionOptionsLUKSBase: @@ -3798,6 +3808,15 @@ 'base': 'RbdEncryptionOptionsLUKSBase', 'data': { } } +## +# @RbdEncryptionOptionsLUKSAny: +# +# Since: 7.2 +## +{ 'struct': 'RbdEncryptionOptionsLUKSAny', + 'base': 'RbdEncryptionOptionsLUKSBase', + 'data': { } } + ## # @RbdEncryptionCreateOptionsLUKS: # @@ -3819,13 +3838,21 @@ ## # @RbdEncryptionOptions: # +# @format: Encryption format. +# +# @parent: Parent image encryption options (for cloned images). +# Can be left unspecified if all ancestor images are encrypted +# the same way as the child image or not encrypted. (Since 7.2) +# # Since: 6.1 ## { 'union': 'RbdEncryptionOptions', - 'base': { 'format': 'RbdImageEncryptionFormat' }, + 'base': { 'format': 'RbdImageEncryptionFormat', + '*parent': 'RbdEncryptionOptions' }, 'discriminator': 'format', 'data': { 'luks': 'RbdEncryptionOptionsLUKS', - 'luks2': 'RbdEncryptionOptionsLUKS2' } } + 'luks2': 'RbdEncryptionOptionsLUKS2', + 'luks-any': 'RbdEncryptionOptionsLUKSAny'} } ## # @RbdEncryptionCreateOptions: