From nobody Sat May 11 20:50:55 2024 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=il.ibm.com ARC-Seal: i=1; a=rsa-sha256; t=1668515824; cv=none; d=zohomail.com; s=zohoarc; b=gHqA+FNqAjvNoVNmKKeFp27eFD5Dufl3zYfW/H8jN+UtZZpH4+BxhI0BuvBtzhH+dwOkRW2ZR1y0Ib5Dk6ZFR0aPCcfYVFfxG2F2N/+16QueS5FGMHWFJ3+kjk0jWV9vPnaMNJxFnTG94gD+U7Iqc/x7vnovCdZyOVN4Kf0R7ho= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1668515824; h=Content-Transfer-Encoding:Cc:Date:From:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Sender:Subject:To; bh=8kQB9n4zTyQT9PkndWpkg4Ddnesz5bI1vScDXViOKcg=; b=DkwhkpirE37mQOOfU28Ptr0K4VQPuFwT5AO+ytr1BNVO+Aga2yCRW6quzDfBtVTXl75ZhuPVNuJrI+VuvjKJlhLgAmxAAC1VC/iTsPniF/jjKSs6nyEsVb4PqR2FVBDTPNPfyDuNMHKVuwTzuhivRIQbkOcDmHhUmZz5O0GHTJ0= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1668515824964237.30688699582265; Tue, 15 Nov 2022 04:37:04 -0800 (PST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1ouv0c-0006tH-F6; Tue, 15 Nov 2022 07:25:46 -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 1ouv0Z-0006rB-PM; Tue, 15 Nov 2022 07:25:44 -0500 Received: from mx0a-001b2d01.pphosted.com ([148.163.156.1]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1ouv0X-00073t-KQ; Tue, 15 Nov 2022 07:25:43 -0500 Received: from pps.filterd (m0098396.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.17.1.19/8.17.1.19) with ESMTP id 2AFCBv4U020671; Tue, 15 Nov 2022 12:25:37 GMT Received: from pps.reinject (localhost [127.0.0.1]) by mx0a-001b2d01.pphosted.com (PPS) with ESMTPS id 3kvajd09ay-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 15 Nov 2022 12:25:37 +0000 Received: from m0098396.ppops.net (m0098396.ppops.net [127.0.0.1]) by pps.reinject (8.17.1.5/8.17.1.5) with ESMTP id 2AFCDcEe025555; Tue, 15 Nov 2022 12:25:36 GMT Received: from ppma02wdc.us.ibm.com (aa.5b.37a9.ip4.static.sl-reverse.com [169.55.91.170]) by mx0a-001b2d01.pphosted.com (PPS) with ESMTPS id 3kvajd09ap-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 15 Nov 2022 12:25:36 +0000 Received: from pps.filterd (ppma02wdc.us.ibm.com [127.0.0.1]) by ppma02wdc.us.ibm.com (8.16.1.2/8.16.1.2) with SMTP id 2AFCKMnQ032586; Tue, 15 Nov 2022 12:25:35 GMT Received: from b01cxnp23033.gho.pok.ibm.com (b01cxnp23033.gho.pok.ibm.com [9.57.198.28]) by ppma02wdc.us.ibm.com with ESMTP id 3kt349m5w7-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 15 Nov 2022 12:25:35 +0000 Received: from smtpav03.wdc07v.mail.ibm.com ([9.208.128.112]) by b01cxnp23033.gho.pok.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 2AFCPX3H5243396 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Tue, 15 Nov 2022 12:25:33 GMT Received: from smtpav03.wdc07v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 3062958058; Tue, 15 Nov 2022 12:25:33 +0000 (GMT) Received: from smtpav03.wdc07v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 4AC755805C; Tue, 15 Nov 2022 12:25:32 +0000 (GMT) Received: from oro.sl.cloud9.ibm.com (unknown [9.59.192.176]) by smtpav03.wdc07v.mail.ibm.com (Postfix) with ESMTP; Tue, 15 Nov 2022 12:25:32 +0000 (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=8kQB9n4zTyQT9PkndWpkg4Ddnesz5bI1vScDXViOKcg=; b=qAcxYTNfuWv9fspC38LFlw6Wz1UiMz5GRfWO69W3tx0GcdLncOe8e/EyMAYrkaQICjXq 1fVW7FS4JoJJPwWT5wRzUmMS2S8BBYpOaOStYHoDVPUJiN1ouPKRiIQ3SowQxA76g8Hc s6Q4sxnGDdlQN8ml6usQ6+ON9ChmRLo9eLxncxUc42m2vUC+NZ52/31nnu00P1HCg8a7 fW2OTM0Nz1Aloq3qOGubQSO0uZJj+DvHaEYdnIo73J2JTbmBxzpc8Le03+NJp9uyRnqA LYGATrhm0YOV29ncrLP55OrNflBBnwatzzGukBqqTkrIMbzU7vwNzyx6CkCTWsJ7qOjt Gg== 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 v3] block/rbd: Add support for layered encryption Date: Tue, 15 Nov 2022 06:25:27 -0600 Message-Id: <20221115122527.2896476-1-oro@il.ibm.com> X-Mailer: git-send-email 2.25.1 MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-TM-AS-GCONF: 00 X-Proofpoint-GUID: aQ4X67Cl81-N9KFWI8O6avruRwH7WaBC X-Proofpoint-ORIG-GUID: JevV5-Nt7ZiEq0V6WqIPTtcxm4S_9mKY 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-15_06,2022-11-15_03,2022-06-22_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 mlxscore=0 phishscore=0 priorityscore=1501 bulkscore=0 spamscore=0 adultscore=0 impostorscore=0 lowpriorityscore=0 mlxlogscore=905 clxscore=1015 malwarescore=0 suspectscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2210170000 definitions=main-2211150083 Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=148.163.156.1; envelope-from=oro@il.ibm.com; helo=mx0a-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+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @ibm.com) X-ZM-MESSAGEID: 1668515826100100003 Content-Type: text/plain; charset="utf-8" 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 }; =20 +static const char rbd_layered_luks_header_verification[ + RBD_ENCRYPTION_LUKS_HEADER_VERIFICATION_LEN] =3D { + 'R', 'B', 'D', 'L', 0xBA, 0xBE, 0, 1 +}; + +static const char rbd_layered_luks2_header_verification[ + RBD_ENCRYPTION_LUKS_HEADER_VERIFICATION_LEN] =3D { + '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 =3D 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 =3D RBD_ENCRYPTION_FORMAT_LUKS; + opts =3D &luks_any_opts; + opts_size =3D sizeof(luks_any_opts); + r =3D 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 =3D passphrase; + luks_any_opts.passphrase_size =3D passphrase_len; + break; + } +#endif default: { r =3D -ENOTSUP; error_setg_errno( @@ -522,6 +552,74 @@ static int qemu_rbd_encryption_load(rbd_image_t image, =20 return 0; } + +#ifdef LIBRBD_SUPPORTS_ENCRYPTION_LOAD2 +static int qemu_rbd_encryption_load2(rbd_image_t image, + RbdEncryptionOptions *encrypt, + Error **errp) +{ + int r =3D 0; + int encrypt_count =3D 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 =3D encrypt; curr_encrypt->has_parent; + curr_encrypt =3D curr_encrypt->parent) { + ++encrypt_count; + } + + specs =3D g_new0(rbd_encryption_spec_t, encrypt_count); + + curr_encrypt =3D encrypt; + for (i =3D 0; i < encrypt_count; ++i) { + if (curr_encrypt->format !=3D RBD_IMAGE_ENCRYPTION_FORMAT_LUKS_ANY= ) { + r =3D -ENOTSUP; + error_setg_errno( + errp, -r, "unknown image encryption format: %u", + curr_encrypt->format); + goto exit; + } + + specs[i].format =3D RBD_ENCRYPTION_FORMAT_LUKS; + specs[i].opts_size =3D sizeof(rbd_encryption_luks_format_options_t= ); + + luks_any_opts =3D g_new0(rbd_encryption_luks_format_options_t, 1); + specs[i].opts =3D luks_any_opts; + + r =3D 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 =3D curr_encrypt->parent; + } + + r =3D rbd_encryption_load2(image, specs, encrypt_count); + if (r < 0) { + error_setg_errno(errp, -r, "layered encryption load fail"); + goto exit; + } + +exit: + for (i =3D 0; i < encrypt_count; ++i) { + luks_any_opts =3D specs[i].opts; + if (luks_any_opts) { + g_free((char*)luks_any_opts->passphrase); + g_free(luks_any_opts); + } + } + g_free(specs); + return r; +} +#endif #endif =20 /* FIXME Deprecate and remove keypairs or make it available in QMP. */ @@ -993,7 +1091,16 @@ static int qemu_rbd_open(BlockDriverState *bs, QDict = *options, int flags, =20 if (opts->has_encrypt) { #ifdef LIBRBD_SUPPORTS_ENCRYPTION - r =3D qemu_rbd_encryption_load(s->image, opts->encrypt, errp); + if (opts->encrypt->has_parent) { +#ifdef LIBRBD_SUPPORTS_ENCRYPTION_LOAD2 + r =3D qemu_rbd_encryption_load2(s->image, opts->encrypt, errp); +#else + r =3D -ENOTSUP; + error_setg(errp, "RBD library does not support layered encrypt= ion"); +#endif + } else { + r =3D qemu_rbd_encryption_load(s->image, opts->encrypt, errp); + } if (r < 0) { goto failed_post_open; } @@ -1284,6 +1391,16 @@ static ImageInfoSpecific *qemu_rbd_get_specific_info= (BlockDriverState *bs, spec_info->u.rbd.data->encryption_format =3D RBD_IMAGE_ENCRYPTION_FORMAT_LUKS2; spec_info->u.rbd.data->has_encryption_format =3D true; + } else if (memcmp(buf, rbd_layered_luks_header_verification, + RBD_ENCRYPTION_LUKS_HEADER_VERIFICATION_LEN) =3D=3D 0) { + spec_info->u.rbd.data->encryption_format =3D + RBD_IMAGE_ENCRYPTION_FORMAT_LUKS_LAYERED; + spec_info->u.rbd.data->has_encryption_format =3D true; + } else if (memcmp(buf, rbd_layered_luks2_header_verification, + RBD_ENCRYPTION_LUKS_HEADER_VERIFICATION_LEN) =3D=3D 0) { + spec_info->u.rbd.data->encryption_format =3D + RBD_IMAGE_ENCRYPTION_FORMAT_LUKS2_LAYERED; + spec_info->u.rbd.data->has_encryption_format =3D true; } else { spec_info->u.rbd.data->has_encryption_format =3D false; } diff --git a/qapi/block-core.json b/qapi/block-core.json index 882b266532..15715d990e 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' ]= } =20 ## # @RbdEncryptionOptionsLUKSBase: @@ -3798,6 +3808,15 @@ 'base': 'RbdEncryptionOptionsLUKSBase', 'data': { } } =20 +## +# @RbdEncryptionOptionsLUKSAny: +# +# Since: 7.2 +## +{ 'struct': 'RbdEncryptionOptionsLUKSAny', + 'base': 'RbdEncryptionOptionsLUKSBase', + 'data': { } } + ## # @RbdEncryptionCreateOptionsLUKS: # @@ -3819,13 +3838,23 @@ ## # @RbdEncryptionOptions: # +# @format: Encryption format. +# +# @parent: Parent image encryption options (for cloned images). +# Can be left unspecified if this cloned image is encrypted +# using the same format and secret as its parent image (i.e. +# not explicitly formatted) or if its parent image is 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'} } =20 ## # @RbdEncryptionCreateOptions: --=20 2.25.1