From patchwork Tue Jan 30 05:37:19 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Yong Huang X-Patchwork-Id: 13536903 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 901AAC4828C for ; Tue, 30 Jan 2024 05:40:48 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1rUgqW-0002rv-KN; Tue, 30 Jan 2024 00:39:44 -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 1rUgqQ-0002r0-Nc for qemu-devel@nongnu.org; Tue, 30 Jan 2024 00:39:38 -0500 Received: from mail-ua1-x934.google.com ([2607:f8b0:4864:20::934]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1rUgqO-0001MF-9P for qemu-devel@nongnu.org; Tue, 30 Jan 2024 00:39:38 -0500 Received: by mail-ua1-x934.google.com with SMTP id a1e0cc1a2514c-7d2dfa3bc64so507823241.2 for ; Mon, 29 Jan 2024 21:37:35 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=smartx-com.20230601.gappssmtp.com; s=20230601; t=1706593054; x=1707197854; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=mgBjKCmGIw1QzGuAtBe8Fn0BN4xSBkw1xT0mmLT2npc=; b=0we04U9bPNNYh1In4+leZUwv/OtiL6f+JjI5IEifrIWSh8/JQ3bDV7PLovTraKt9aj h+ecFJ76oHqTVeNcms5ybH177SNYbo1fCZtBLiwq+ps0lrIAMfic2pLwawnnLoVmJP7V UUXi6GQTtYLorl85vPRuZ30VMW+uLOE8gWmFt7peKe4+GswXbwYUmi/1BuL5F4Jw1wr/ Rg87e5OVZFG4TFRFkSLOOjxlpT5CHeZQVTm6RyduS4E7JAz6QbFS/IzFzWnDKU3gJiNY wQRoCn/l6SsiZvjrpA0cG4wqTbcoep1v97aDxeaqIGHPAd7u2DwmgHQGycw91hzf30/E bhSg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1706593054; x=1707197854; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=mgBjKCmGIw1QzGuAtBe8Fn0BN4xSBkw1xT0mmLT2npc=; b=wgWdSNl+oj0LgR+yK0R1ElSox9lmEzF3tqavqxHiW++PhJ9ja+0EuHBWmuCs68vJvG 9FWUQzyb+P1DlvbkwJI7kWo1/8Is+Lf1iZtBl4ob7OJya3W3B2j/5mkH4jAORe+U+Vot Ns2hLrHzMnX+oC8sOLDPS3BK1+fMBhwUTGsJi5Zh3eNgT6q0CL4Djo6Oi1t5krqvphFh dK+//FE0GDI3cLgmxNfOSerKvyPxbywyG8H8F4ds5Atyd3PlrYzuBMVICZja7lFRTQ7Y yN5BBp+cVuP/FqMbFEhdErNgrW5qsnVqlxZ3FzsgSuqlSzqVRIlWsnZZxJWaqP5ePbuo JCxQ== X-Gm-Message-State: AOJu0YwVdTxgO05TYJtaKWj3fv3GjNr9ibjb9yImpNdDhpYXl9xr4S9/ XKUAKzkr0yYrZ5Yd+EyVPQJSk0j2XZ9DEuzmi6cN1kXSGr41b/t+9LwBfXpjzmmLyneTNLT1CeJ 79RU= X-Google-Smtp-Source: AGHT+IHEdsnnvhbd1i+PHsLhVYF/9HKrKR3440uMhQ7nQMMkJVuPGhsv6/4PbqbLxLLaGualIi3jYw== X-Received: by 2002:a05:6102:2143:b0:46b:5b70:dfe1 with SMTP id h3-20020a056102214300b0046b5b70dfe1mr2287376vsg.2.1706593053347; Mon, 29 Jan 2024 21:37:33 -0800 (PST) Received: from anolis-dev.zelin.local ([221.122.98.162]) by smtp.gmail.com with ESMTPSA id bv123-20020a632e81000000b005c1ce3c960bsm7343532pgb.50.2024.01.29.21.37.31 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 29 Jan 2024 21:37:32 -0800 (PST) From: yong.huang@smartx.com To: qemu-devel@nongnu.org Cc: =?utf-8?q?Daniel_P_=2E_Berrang=C3=A9?= , Eric Blake , Markus Armbruster , Hanna Reitz , Kevin Wolf , yong.huang@smartx.com Subject: [PATCH v4 1/7] crypto: Support LUKS volume with detached header Date: Tue, 30 Jan 2024 13:37:19 +0800 Message-Id: X-Mailer: git-send-email 2.31.1 In-Reply-To: References: MIME-Version: 1.0 Received-SPF: none client-ip=2607:f8b0:4864:20::934; envelope-from=yong.huang@smartx.com; helo=mail-ua1-x934.google.com X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_NONE=0.001, T_SCC_BODY_TEXT_LINE=-0.01 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+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org From: Hyman Huang By enhancing the LUKS driver, it is possible to implement the LUKS volume with a detached header. Normally a LUKS volume has a layout: disk: | header | key material | disk payload data | With a detached LUKS header, you need 2 disks so getting: disk1: | header | key material | disk2: | disk payload data | There are a variety of benefits to doing this: * Secrecy - the disk2 cannot be identified as containing LUKS volume since there's no header * Control - if access to the disk1 is restricted, then even if someone has access to disk2 they can't unlock it. Might be useful if you have disks on NFS but want to restrict which host can launch a VM instance from it, by dynamically providing access to the header to a designated host * Flexibility - your application data volume may be a given size and it is inconvenient to resize it to add encryption.You can store the LUKS header separately and use the existing storage volume for payload * Recovery - corruption of a bit in the header may make the entire payload inaccessible. It might be convenient to take backups of the header. If your primary disk header becomes corrupt, you can unlock the data still by pointing to the backup detached header Take the raw-format image as an example to introduce the usage of the LUKS volume with a detached header: 1. prepare detached LUKS header images $ dd if=/dev/zero of=test-header.img bs=1M count=32 $ dd if=/dev/zero of=test-payload.img bs=1M count=1000 $ cryptsetup luksFormat --header test-header.img test-payload.img > --force-password --type luks1 2. block-add a protocol blockdev node of payload image $ virsh qemu-monitor-command vm '{"execute":"blockdev-add", > "arguments":{"node-name":"libvirt-1-storage", "driver":"file", > "filename":"test-payload.img"}}' 3. block-add a protocol blockdev node of LUKS header as above. $ virsh qemu-monitor-command vm '{"execute":"blockdev-add", > "arguments":{"node-name":"libvirt-2-storage", "driver":"file", > "filename": "test-header.img" }}' 4. object-add the secret for decrypting the cipher stored in LUKS header above $ virsh qemu-monitor-command vm '{"execute":"object-add", > "arguments":{"qom-type":"secret", "id": > "libvirt-2-storage-secret0", "data":"abc123"}}' 5. block-add the raw-drived blockdev format node $ virsh qemu-monitor-command vm '{"execute":"blockdev-add", > "arguments":{"node-name":"libvirt-1-format", "driver":"raw", > "file":"libvirt-1-storage"}}' 6. block-add the luks-drived blockdev to link the raw disk with the LUKS header by specifying the field "header" $ virsh qemu-monitor-command vm '{"execute":"blockdev-add", > "arguments":{"node-name":"libvirt-2-format", "driver":"luks", > "file":"libvirt-1-format", "header":"libvirt-2-storage", > "key-secret":"libvirt-2-format-secret0"}}' 7. hot-plug the virtio-blk device finally $ virsh qemu-monitor-command vm '{"execute":"device_add", > "arguments": {"num-queues":"1", "driver":"virtio-blk-pci", > "drive": "libvirt-2-format", "id":"virtio-disk2"}}' Starting a VM with a LUKS volume with detached header is somewhat similar to hot-plug in that both maintaining the same json command while the starting VM changes the "blockdev-add/device_add" parameters to "blockdev/device". Signed-off-by: Hyman Huang Reviewed-by: Daniel P. Berrangé --- block/crypto.c | 21 +++++++++++++++++++-- crypto/block-luks.c | 11 +++++++---- include/crypto/block.h | 5 +++++ qapi/block-core.json | 5 ++++- 4 files changed, 35 insertions(+), 7 deletions(-) diff --git a/block/crypto.c b/block/crypto.c index 921933a5e5..68656158e9 100644 --- a/block/crypto.c +++ b/block/crypto.c @@ -39,6 +39,7 @@ typedef struct BlockCrypto BlockCrypto; struct BlockCrypto { QCryptoBlock *block; bool updating_keys; + BdrvChild *header; /* Reference to the detached LUKS header */ }; @@ -63,12 +64,14 @@ static int block_crypto_read_func(QCryptoBlock *block, Error **errp) { BlockDriverState *bs = opaque; + BlockCrypto *crypto = bs->opaque; ssize_t ret; GLOBAL_STATE_CODE(); GRAPH_RDLOCK_GUARD_MAINLOOP(); - ret = bdrv_pread(bs->file, offset, buflen, buf, 0); + ret = bdrv_pread(crypto->header ? crypto->header : bs->file, + offset, buflen, buf, 0); if (ret < 0) { error_setg_errno(errp, -ret, "Could not read encryption header"); return ret; @@ -84,12 +87,14 @@ static int block_crypto_write_func(QCryptoBlock *block, Error **errp) { BlockDriverState *bs = opaque; + BlockCrypto *crypto = bs->opaque; ssize_t ret; GLOBAL_STATE_CODE(); GRAPH_RDLOCK_GUARD_MAINLOOP(); - ret = bdrv_pwrite(bs->file, offset, buflen, buf, 0); + ret = bdrv_pwrite(crypto->header ? crypto->header : bs->file, + offset, buflen, buf, 0); if (ret < 0) { error_setg_errno(errp, -ret, "Could not write encryption header"); return ret; @@ -262,6 +267,8 @@ static int block_crypto_open_generic(QCryptoBlockFormat format, int flags, Error **errp) { + ERRP_GUARD(); + BlockCrypto *crypto = bs->opaque; QemuOpts *opts = NULL; int ret; @@ -276,6 +283,13 @@ static int block_crypto_open_generic(QCryptoBlockFormat format, return ret; } + crypto->header = bdrv_open_child(NULL, options, "header", bs, + &child_of_bds, BDRV_CHILD_METADATA, + true, errp); + if (*errp != NULL) { + return -EINVAL; + } + GRAPH_RDLOCK_GUARD_MAINLOOP(); bs->supported_write_flags = BDRV_REQ_FUA & @@ -299,6 +313,9 @@ static int block_crypto_open_generic(QCryptoBlockFormat format, if (flags & BDRV_O_NO_IO) { cflags |= QCRYPTO_BLOCK_OPEN_NO_IO; } + if (crypto->header != NULL) { + cflags |= QCRYPTO_BLOCK_OPEN_DETACHED; + } crypto->block = qcrypto_block_open(open_opts, NULL, block_crypto_read_func, bs, diff --git a/crypto/block-luks.c b/crypto/block-luks.c index fb01ec38bb..10373aaba4 100644 --- a/crypto/block-luks.c +++ b/crypto/block-luks.c @@ -457,12 +457,15 @@ qcrypto_block_luks_load_header(QCryptoBlock *block, * Does basic sanity checks on the LUKS header */ static int -qcrypto_block_luks_check_header(const QCryptoBlockLUKS *luks, Error **errp) +qcrypto_block_luks_check_header(const QCryptoBlockLUKS *luks, + unsigned int flags, + Error **errp) { size_t i, j; unsigned int header_sectors = QCRYPTO_BLOCK_LUKS_KEY_SLOT_OFFSET / QCRYPTO_BLOCK_LUKS_SECTOR_SIZE; + bool detached = flags & QCRYPTO_BLOCK_OPEN_DETACHED; if (memcmp(luks->header.magic, qcrypto_block_luks_magic, QCRYPTO_BLOCK_LUKS_MAGIC_LEN) != 0) { @@ -494,7 +497,7 @@ qcrypto_block_luks_check_header(const QCryptoBlockLUKS *luks, Error **errp) return -1; } - if (luks->header.payload_offset_sector < + if (!detached && luks->header.payload_offset_sector < DIV_ROUND_UP(QCRYPTO_BLOCK_LUKS_KEY_SLOT_OFFSET, QCRYPTO_BLOCK_LUKS_SECTOR_SIZE)) { error_setg(errp, "LUKS payload is overlapping with the header"); @@ -543,7 +546,7 @@ qcrypto_block_luks_check_header(const QCryptoBlockLUKS *luks, Error **errp) return -1; } - if (start1 + len1 > luks->header.payload_offset_sector) { + if (!detached && start1 + len1 > luks->header.payload_offset_sector) { error_setg(errp, "Keyslot %zu is overlapping with the encrypted payload", i); @@ -1203,7 +1206,7 @@ qcrypto_block_luks_open(QCryptoBlock *block, goto fail; } - if (qcrypto_block_luks_check_header(luks, errp) < 0) { + if (qcrypto_block_luks_check_header(luks, flags, errp) < 0) { goto fail; } diff --git a/include/crypto/block.h b/include/crypto/block.h index 4f63a37872..d0d97f5d12 100644 --- a/include/crypto/block.h +++ b/include/crypto/block.h @@ -66,6 +66,7 @@ bool qcrypto_block_has_format(QCryptoBlockFormat format, typedef enum { QCRYPTO_BLOCK_OPEN_NO_IO = (1 << 0), + QCRYPTO_BLOCK_OPEN_DETACHED = (1 << 1), } QCryptoBlockOpenFlags; /** @@ -95,6 +96,10 @@ typedef enum { * metadata such as the payload offset. There will be * no cipher or ivgen objects available. * + * If @flags contains QCRYPTO_BLOCK_OPEN_DETACHED then + * the open process will be optimized to skip the LUKS + * payload overlap check. + * * If any part of initializing the encryption context * fails an error will be returned. This could be due * to the volume being in the wrong format, a cipher diff --git a/qapi/block-core.json b/qapi/block-core.json index 48c181e55d..ae604c6019 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -3365,11 +3365,14 @@ # decryption key (since 2.6). Mandatory except when doing a # metadata-only probe of the image. # +# @header: block device holding a detached LUKS header. (since 9.0) +# # Since: 2.9 ## { 'struct': 'BlockdevOptionsLUKS', 'base': 'BlockdevOptionsGenericFormat', - 'data': { '*key-secret': 'str' } } + 'data': { '*key-secret': 'str', + '*header': 'BlockdevRef'} } ## # @BlockdevOptionsGenericCOWFormat: From patchwork Tue Jan 30 05:37:20 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Yong Huang X-Patchwork-Id: 13536906 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id E6007C46CD2 for ; Tue, 30 Jan 2024 05:41:28 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1rUgqW-0002rt-7M; Tue, 30 Jan 2024 00:39:44 -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 1rUgqR-0002rG-Ug for qemu-devel@nongnu.org; Tue, 30 Jan 2024 00:39:40 -0500 Received: from mail-yw1-x112e.google.com ([2607:f8b0:4864:20::112e]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1rUgqP-0001Mf-Iy for qemu-devel@nongnu.org; Tue, 30 Jan 2024 00:39:39 -0500 Received: by mail-yw1-x112e.google.com with SMTP id 00721157ae682-5ffee6e8770so42069907b3.0 for ; Mon, 29 Jan 2024 21:37:37 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=smartx-com.20230601.gappssmtp.com; s=20230601; t=1706593056; x=1707197856; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=IaYK0tSoXobJSD9k/CLgH5G9458n5lr/GaWLdjptppA=; b=JBIh7pUGdbfKOm+LqDxCRxvB0FalYLi4AHu1IY5gxCJKDrdv8XJPf0am6TJ+CaXVDS vsDc6meXXvvE4CN51LhFltncYXgnoPte0odXPkn7iJ0R3ep1f90M3p0W5UQuuqhiFTSc bOORos/EanQlK1XmrnqZmr+ySJtHMem7Sp50sGcnPsys949vhx0wBDw/lpcQV6mSEM2Q oWYE8mlZflzk1hKP+EsvGRP6ZVPgH6N0UcZQdb0cj9sz/wZ68bcQxclwcy32zgVh8WRQ voJL9qyKrMtVgjplTaCDHTIOI8HW0eluK1S/g79Kh/e/2Fp/mlOLlFzWdYHLq8OerT2A HFAA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1706593056; x=1707197856; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=IaYK0tSoXobJSD9k/CLgH5G9458n5lr/GaWLdjptppA=; b=GfZ2oWFFvpq8eumh+6rGrYqoYfzrfDQXNwfdXasQpMr6yuO8RhWPLZxOtz7qH9Bbla Q36uMyyuh8DjAuBkaUuK2638jcoX6UBiCVDWZ5gSmbe//tKkSw1tY7wZKMfGSfUaE/X5 OFC2tmtP37cXuPlh7gWTdJExDqO4bpDZeWNbfxs9gzWPOXOT3Wph7eKgIOCDecf9uAyb bUTtjo3YPSWYVKsjTPS7VTgn/qFG4CvImmsflfesUzuZyKRu9ZlfTN6pANAvJA4Z4RpF Yjlc2oWRqrYJDKGNrsxua/rBtIJ+m41JNKInDiTa5q7fH5Bx9UXBmaJzAUwN8h+T9msW sBUw== X-Gm-Message-State: AOJu0YzlQ0nm/i0HrDiyMMwh1IZ2DSwkh+fph3ecY9u85klje6hbnK8P SByve/U6X3o8TKuQAvvCj8K5Qd0u15mVlF0oSdQLYjSwm4dIxzx356QdJZLAx0IlmPZnNw3R6qP w0rw= X-Google-Smtp-Source: AGHT+IHTINHPUm7ZNm8snvTOU2RFytyHVDhQRqNLbgYDNZFwYNHfZatNAlFFbDGlmyMF916YvQRIqw== X-Received: by 2002:a81:e505:0:b0:603:aa70:cd3f with SMTP id s5-20020a81e505000000b00603aa70cd3fmr5674727ywl.83.1706593055707; Mon, 29 Jan 2024 21:37:35 -0800 (PST) Received: from anolis-dev.zelin.local ([221.122.98.162]) by smtp.gmail.com with ESMTPSA id bv123-20020a632e81000000b005c1ce3c960bsm7343532pgb.50.2024.01.29.21.37.33 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 29 Jan 2024 21:37:35 -0800 (PST) From: yong.huang@smartx.com To: qemu-devel@nongnu.org Cc: =?utf-8?q?Daniel_P_=2E_Berrang=C3=A9?= , Eric Blake , Markus Armbruster , Hanna Reitz , Kevin Wolf , yong.huang@smartx.com Subject: [PATCH v4 2/7] qapi: Make parameter 'file' optional for BlockdevCreateOptionsLUKS Date: Tue, 30 Jan 2024 13:37:20 +0800 Message-Id: X-Mailer: git-send-email 2.31.1 In-Reply-To: References: MIME-Version: 1.0 Received-SPF: none client-ip=2607:f8b0:4864:20::112e; envelope-from=yong.huang@smartx.com; helo=mail-yw1-x112e.google.com X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_NONE=0.001, T_SCC_BODY_TEXT_LINE=-0.01 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+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org From: Hyman Huang To support detached LUKS header creation, make the existing 'file' field in BlockdevCreateOptionsLUKS optional. Signed-off-by: Hyman Huang Reviewed-by: Daniel P. Berrangé --- block/crypto.c | 21 ++++++++++++++------- qapi/block-core.json | 5 +++-- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/block/crypto.c b/block/crypto.c index 68656158e9..e87dc84111 100644 --- a/block/crypto.c +++ b/block/crypto.c @@ -663,9 +663,9 @@ block_crypto_co_create_luks(BlockdevCreateOptions *create_options, Error **errp) assert(create_options->driver == BLOCKDEV_DRIVER_LUKS); luks_opts = &create_options->u.luks; - bs = bdrv_co_open_blockdev_ref(luks_opts->file, errp); - if (bs == NULL) { - return -EIO; + if (luks_opts->file == NULL) { + error_setg(errp, "Formatting LUKS disk requires parameter 'file'"); + return -EINVAL; } create_opts = (QCryptoBlockCreateOptions) { @@ -677,10 +677,17 @@ block_crypto_co_create_luks(BlockdevCreateOptions *create_options, Error **errp) preallocation = luks_opts->preallocation; } - ret = block_crypto_co_create_generic(bs, luks_opts->size, &create_opts, - preallocation, errp); - if (ret < 0) { - goto fail; + if (luks_opts->file) { + bs = bdrv_co_open_blockdev_ref(luks_opts->file, errp); + if (bs == NULL) { + return -EIO; + } + + ret = block_crypto_co_create_generic(bs, luks_opts->size, &create_opts, + preallocation, errp); + if (ret < 0) { + goto fail; + } } ret = 0; diff --git a/qapi/block-core.json b/qapi/block-core.json index ae604c6019..69a88d613d 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -4957,7 +4957,8 @@ # # Driver specific image creation options for LUKS. # -# @file: Node to create the image format on +# @file: Node to create the image format on, mandatory except when +# 'preallocation' is not requested # # @size: Size of the virtual disk in bytes # @@ -4968,7 +4969,7 @@ ## { 'struct': 'BlockdevCreateOptionsLUKS', 'base': 'QCryptoBlockCreateOptionsLUKS', - 'data': { 'file': 'BlockdevRef', + 'data': { '*file': 'BlockdevRef', 'size': 'size', '*preallocation': 'PreallocMode' } } From patchwork Tue Jan 30 05:37:21 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Yong Huang X-Patchwork-Id: 13536907 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id C6CDAC46CD2 for ; Tue, 30 Jan 2024 05:42:03 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1rUgqX-0002sZ-J9; Tue, 30 Jan 2024 00:39:45 -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 1rUgqU-0002re-6q for qemu-devel@nongnu.org; Tue, 30 Jan 2024 00:39:43 -0500 Received: from mail-yw1-x1129.google.com ([2607:f8b0:4864:20::1129]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1rUgqR-0001N0-Tl for qemu-devel@nongnu.org; Tue, 30 Jan 2024 00:39:41 -0500 Received: by mail-yw1-x1129.google.com with SMTP id 00721157ae682-5ffdf06e009so35043937b3.3 for ; Mon, 29 Jan 2024 21:37:39 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=smartx-com.20230601.gappssmtp.com; s=20230601; t=1706593059; x=1707197859; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=GgIauGmyrGpKEXUINKH8zV3ggDfjrFXnkhV7HaAgky4=; b=o6bMqZWeRWXwshqrp+Qfd7VO2U8oVpObQE8ePIBlCEvQDeN8SPeHu9Ep+Cd2MxxI0M VD/Ffy5VaJwv/zk2hoj+lbLI6mYJypxNqBgAp2gDnFW+k0E3F6HKnCDw0OvwM9Xfu2Hy 6e4nGI/bYC77jG8+SGKzqqQfALEiFDEdyZFAZPGZBc80wrvWFZ+w+H7bPjTeQnn8rHbd zVq5mSYuCf2KocwOhp3OgTBza7rA1HW/YArPaOiMC+k2uv/AKXcV4LxDBgsDnWxR2ZCC UIf+E8zpd09fyqIWb5ytfS5tNIrlcp+tKjy/1NSolLbR8yIHUhP0One5DilWn6OstW/L 40Kg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1706593059; x=1707197859; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=GgIauGmyrGpKEXUINKH8zV3ggDfjrFXnkhV7HaAgky4=; b=EfOGYn3wY7tO9H9jRTvYL8ckroRj8Aw8uaqLoJ3vuIo4s7bcA/d3idgGrN2tRANBD9 jacS+RmVSkUbds+d6RP2CDkOBd22gxuvoa68OCWq3HSyY/XKcuhqt0R1rmipYf5Y9CiU pxkt3AJRYphvyq/JWyGfh0cHh+ulnOaPSvsrpDxUYGl1oG5CI9TFcYQ2ACmkqiLsqbzj UJguoL+jAqNJnLVn1NVdMx0nzWlRDlFYKqO6D7BGLMp4/s/Ci/E7CPH7WoEWko7+zgAf Vf8OBL0cVW2Qp/4PoKrIw4yCX5VD/kPn6cbfEyCDtlUivPftL1b4y77AWhH8OV4gTTAJ 4vwQ== X-Gm-Message-State: AOJu0YxnND99MRWDq1X5Cq+LHNuiw5C3uxT7B0bG3hBaYlJcF6MEnVt/ ZEuw0mUnTt5fkNyvMpt/uobu7CNt6W7IjY1CqZgpuUJWoz+JAJjDs0C34ew1IQ3i+wNL2WcOSAN uL6I= X-Google-Smtp-Source: AGHT+IEZHbVoS+l8rYL3uw7l10gW5QjIP0/w6qWR4FaGRV7XP9Kysqw70t8AoI7tLpxWiLyCzU1Epg== X-Received: by 2002:a81:ae50:0:b0:5ee:65b3:f289 with SMTP id g16-20020a81ae50000000b005ee65b3f289mr4843588ywk.3.1706593058052; Mon, 29 Jan 2024 21:37:38 -0800 (PST) Received: from anolis-dev.zelin.local ([221.122.98.162]) by smtp.gmail.com with ESMTPSA id bv123-20020a632e81000000b005c1ce3c960bsm7343532pgb.50.2024.01.29.21.37.35 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 29 Jan 2024 21:37:37 -0800 (PST) From: yong.huang@smartx.com To: qemu-devel@nongnu.org Cc: =?utf-8?q?Daniel_P_=2E_Berrang=C3=A9?= , Eric Blake , Markus Armbruster , Hanna Reitz , Kevin Wolf , yong.huang@smartx.com Subject: [PATCH v4 3/7] crypto: Modify the qcrypto_block_create to support creation flags Date: Tue, 30 Jan 2024 13:37:21 +0800 Message-Id: X-Mailer: git-send-email 2.31.1 In-Reply-To: References: MIME-Version: 1.0 Received-SPF: none client-ip=2607:f8b0:4864:20::1129; envelope-from=yong.huang@smartx.com; helo=mail-yw1-x1129.google.com X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_NONE=0.001, T_SCC_BODY_TEXT_LINE=-0.01 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+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org From: Hyman Huang Expand the signature of qcrypto_block_create to enable the formation of LUKS volumes with detachable headers. To accomplish that, introduce QCryptoBlockCreateFlags to instruct the creation process to set the payload_offset_sector to 0. Signed-off-by: Hyman Huang Reviewed-by: Daniel P. Berrangé --- block/crypto.c | 1 + block/qcow.c | 2 +- block/qcow2.c | 2 +- crypto/block-luks.c | 28 +++++++++++++++++++++------- crypto/block.c | 4 +++- crypto/blockpriv.h | 2 ++ include/crypto/block.h | 11 +++++++++++ tests/unit/test-crypto-block.c | 2 ++ 8 files changed, 42 insertions(+), 10 deletions(-) diff --git a/block/crypto.c b/block/crypto.c index e87dc84111..1b3f87922a 100644 --- a/block/crypto.c +++ b/block/crypto.c @@ -369,6 +369,7 @@ block_crypto_co_create_generic(BlockDriverState *bs, int64_t size, block_crypto_create_init_func, block_crypto_create_write_func, &data, + 0, errp); if (!crypto) { diff --git a/block/qcow.c b/block/qcow.c index c6d0e15f1e..ca8e1d5ec8 100644 --- a/block/qcow.c +++ b/block/qcow.c @@ -885,7 +885,7 @@ qcow_co_create(BlockdevCreateOptions *opts, Error **errp) header.crypt_method = cpu_to_be32(QCOW_CRYPT_AES); crypto = qcrypto_block_create(qcow_opts->encrypt, "encrypt.", - NULL, NULL, NULL, errp); + NULL, NULL, NULL, 0, errp); if (!crypto) { ret = -EINVAL; goto exit; diff --git a/block/qcow2.c b/block/qcow2.c index 9bee66fff5..204f5854cf 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -3216,7 +3216,7 @@ qcow2_set_up_encryption(BlockDriverState *bs, crypto = qcrypto_block_create(cryptoopts, "encrypt.", qcow2_crypto_hdr_init_func, qcow2_crypto_hdr_write_func, - bs, errp); + bs, 0, errp); if (!crypto) { return -EINVAL; } diff --git a/crypto/block-luks.c b/crypto/block-luks.c index 10373aaba4..8ad7cc44a5 100644 --- a/crypto/block-luks.c +++ b/crypto/block-luks.c @@ -1304,6 +1304,7 @@ qcrypto_block_luks_create(QCryptoBlock *block, const char *hash_alg; g_autofree char *cipher_mode_spec = NULL; uint64_t iters; + uint64_t detached_header_size; memcpy(&luks_opts, &options->u.luks, sizeof(luks_opts)); if (!luks_opts.has_iter_time) { @@ -1532,19 +1533,32 @@ qcrypto_block_luks_create(QCryptoBlock *block, slot->stripes = QCRYPTO_BLOCK_LUKS_STRIPES; } - /* The total size of the LUKS headers is the partition header + key - * slot headers, rounded up to the nearest sector, combined with - * the size of each master key material region, also rounded up - * to the nearest sector */ - luks->header.payload_offset_sector = header_sectors + - QCRYPTO_BLOCK_LUKS_NUM_KEY_SLOTS * split_key_sectors; + if (block->detached_header) { + /* + * For a detached LUKS header image, set the payload_offset_sector + * to 0 to specify the starting point for read/write + */ + luks->header.payload_offset_sector = 0; + } else { + /* + * The total size of the LUKS headers is the partition header + key + * slot headers, rounded up to the nearest sector, combined with + * the size of each master key material region, also rounded up + * to the nearest sector + */ + luks->header.payload_offset_sector = header_sectors + + QCRYPTO_BLOCK_LUKS_NUM_KEY_SLOTS * split_key_sectors; + } block->sector_size = QCRYPTO_BLOCK_LUKS_SECTOR_SIZE; block->payload_offset = luks->header.payload_offset_sector * block->sector_size; + detached_header_size = + (header_sectors + QCRYPTO_BLOCK_LUKS_NUM_KEY_SLOTS * + split_key_sectors) * block->sector_size; /* Reserve header space to match payload offset */ - initfunc(block, block->payload_offset, opaque, &local_err); + initfunc(block, detached_header_size, opaque, &local_err); if (local_err) { error_propagate(errp, local_err); goto error; diff --git a/crypto/block.c b/crypto/block.c index 7bb4b74a37..506ea1d1a3 100644 --- a/crypto/block.c +++ b/crypto/block.c @@ -87,6 +87,7 @@ QCryptoBlock *qcrypto_block_create(QCryptoBlockCreateOptions *options, QCryptoBlockInitFunc initfunc, QCryptoBlockWriteFunc writefunc, void *opaque, + unsigned int flags, Error **errp) { QCryptoBlock *block = g_new0(QCryptoBlock, 1); @@ -102,6 +103,7 @@ QCryptoBlock *qcrypto_block_create(QCryptoBlockCreateOptions *options, } block->driver = qcrypto_block_drivers[options->format]; + block->detached_header = flags & QCRYPTO_BLOCK_CREATE_DETACHED; if (block->driver->create(block, options, optprefix, initfunc, writefunc, opaque, errp) < 0) { @@ -146,7 +148,7 @@ qcrypto_block_calculate_payload_offset(QCryptoBlockCreateOptions *create_opts, qcrypto_block_create(create_opts, optprefix, qcrypto_block_headerlen_hdr_init_func, qcrypto_block_headerlen_hdr_write_func, - len, errp); + len, 0, errp); return crypto != NULL; } diff --git a/crypto/blockpriv.h b/crypto/blockpriv.h index 3c7ccea504..836f3b4726 100644 --- a/crypto/blockpriv.h +++ b/crypto/blockpriv.h @@ -42,6 +42,8 @@ struct QCryptoBlock { size_t niv; uint64_t payload_offset; /* In bytes */ uint64_t sector_size; /* In bytes */ + + bool detached_header; /* True if disk has a detached LUKS header */ }; struct QCryptoBlockDriver { diff --git a/include/crypto/block.h b/include/crypto/block.h index d0d97f5d12..92e823c9f2 100644 --- a/include/crypto/block.h +++ b/include/crypto/block.h @@ -116,6 +116,10 @@ QCryptoBlock *qcrypto_block_open(QCryptoBlockOpenOptions *options, size_t n_threads, Error **errp); +typedef enum { + QCRYPTO_BLOCK_CREATE_DETACHED = (1 << 0), +} QCryptoBlockCreateFlags; + /** * qcrypto_block_create: * @options: the encryption options @@ -123,6 +127,7 @@ QCryptoBlock *qcrypto_block_open(QCryptoBlockOpenOptions *options, * @initfunc: callback for initializing volume header * @writefunc: callback for writing data to the volume header * @opaque: data to pass to @initfunc and @writefunc + * @flags: bitmask of QCryptoBlockCreateFlags values * @errp: pointer to a NULL-initialized error object * * Create a new block encryption object for initializing @@ -134,6 +139,11 @@ QCryptoBlock *qcrypto_block_open(QCryptoBlockOpenOptions *options, * generating new master keys, etc as required. Any existing * data present on the volume will be irrevocably destroyed. * + * If @flags contains QCRYPTO_BLOCK_CREATE_DETACHED then + * the open process will set the payload_offset_sector to 0 + * to specify the starting point for the read/write of a + * detached LUKS header image. + * * If any part of initializing the encryption context * fails an error will be returned. This could be due * to the volume being in the wrong format, a cipher @@ -147,6 +157,7 @@ QCryptoBlock *qcrypto_block_create(QCryptoBlockCreateOptions *options, QCryptoBlockInitFunc initfunc, QCryptoBlockWriteFunc writefunc, void *opaque, + unsigned int flags, Error **errp); /** diff --git a/tests/unit/test-crypto-block.c b/tests/unit/test-crypto-block.c index 347cd5f3d7..6cfc817a92 100644 --- a/tests/unit/test-crypto-block.c +++ b/tests/unit/test-crypto-block.c @@ -283,6 +283,7 @@ static void test_block(gconstpointer opaque) test_block_init_func, test_block_write_func, &header, + 0, &error_abort); g_assert(blk); @@ -362,6 +363,7 @@ test_luks_bad_header(gconstpointer data) test_block_init_func, test_block_write_func, &buf, + 0, &error_abort); g_assert(blk); From patchwork Tue Jan 30 05:37:22 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Yong Huang X-Patchwork-Id: 13536902 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 0BFF1C48286 for ; Tue, 30 Jan 2024 05:40:47 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1rUgqa-0002st-3t; Tue, 30 Jan 2024 00:39:48 -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 1rUgqW-0002rw-In for qemu-devel@nongnu.org; Tue, 30 Jan 2024 00:39:44 -0500 Received: from mail-oo1-xc36.google.com ([2607:f8b0:4864:20::c36]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1rUgqU-0001NJ-OI for qemu-devel@nongnu.org; Tue, 30 Jan 2024 00:39:44 -0500 Received: by mail-oo1-xc36.google.com with SMTP id 006d021491bc7-59502aa878aso1803053eaf.1 for ; Mon, 29 Jan 2024 21:37:42 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=smartx-com.20230601.gappssmtp.com; s=20230601; t=1706593061; x=1707197861; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=2Zmg4sbSwcsBk7QBG9lZhae1I6QzpidLZEsTyVPwHJQ=; b=WV1D0NjD2ctIOMKVMJ314ln59FkZ0mEObSWnzHGGFniU6UcasUDBV2x76Yjma4um5/ /gmUa5T8efYDqKoaB8BTanWi0xlv/5Gli1ReLaqvFGhQwpYXuXHS0b/44uTxy2ZzqQfp jnYZ7+NSyAqhFDdCmYTaIj2xaxq11BvKnpV0/75hkJHXe7E6ReNwT9jTuXEas6LbACLg 1Ycqg8njBpyYT5qe1Y686hPVTHT5JcVgv2K/ZKxs88N1mtHSOInwNUAPag7dT3Zj1vax rwB3lgT4kRNPk8XtILX9xKG9t97Dtaacv+cEmCjHEkBUbOyVTGpsDgpO2gNfI0A8S3OW YjJw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1706593061; x=1707197861; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=2Zmg4sbSwcsBk7QBG9lZhae1I6QzpidLZEsTyVPwHJQ=; b=lxUqiFPVIwvfNMtAed/PmULCnY1hB7RMU75uRpHnqdAvrGLpdwBwxQdrGe3ssGrWE/ e7vyK9J9p+bIAXFiWX3/Wh3BmpNjV6ulQtf7GTRXMkI5jwh+ugZxDScgCNcu626hm/nH KXzK1fBijqQW4KO4q6crdaHqo69ZaQ1ABQ2wr7ff0HjKKocRHS/2M7Jkg9T/1L0ZrjQ+ Kh2mVvFn4jI+YA+sWFASk013QByxpFV1dUdxDvzuu5qVYv6qvkh6H+Rv5L3lkVaMv3RM GvR/W72rrN5G+HDVYf6yEUNUxDRiXpUYAaO8J7/f0WR5kzhHNQISVmctKTDOBfjtkdnN 8xRw== X-Gm-Message-State: AOJu0YxzcMIkKdoCwFVHTCFvyUUpmjE8yV8ss3A2IOTKLiU9NgQHr0ZB G7RCiusk5k26YvNWTv8QZ+FBveeHv+RXBHIyf7i1VI0G6LgeeorU5V05dtXRWFCiOBHIem4QAwy qzI0= X-Google-Smtp-Source: AGHT+IH/yItth8XF+5mVj37Yyx7z6K1F1FW6aeEqwAYcvco07wuR+knKc6CpofOhHp2en7k6V7u0JQ== X-Received: by 2002:a05:6358:72a4:b0:178:7194:b543 with SMTP id w36-20020a05635872a400b001787194b543mr3729757rwf.41.1706593060480; Mon, 29 Jan 2024 21:37:40 -0800 (PST) Received: from anolis-dev.zelin.local ([221.122.98.162]) by smtp.gmail.com with ESMTPSA id bv123-20020a632e81000000b005c1ce3c960bsm7343532pgb.50.2024.01.29.21.37.38 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 29 Jan 2024 21:37:40 -0800 (PST) From: yong.huang@smartx.com To: qemu-devel@nongnu.org Cc: =?utf-8?q?Daniel_P_=2E_Berrang=C3=A9?= , Eric Blake , Markus Armbruster , Hanna Reitz , Kevin Wolf , yong.huang@smartx.com Subject: [PATCH v4 4/7] block: Support detached LUKS header creation using blockdev-create Date: Tue, 30 Jan 2024 13:37:22 +0800 Message-Id: <9e35e621f12478822072e5c740ed65beb77f1238.1706586786.git.yong.huang@smartx.com> X-Mailer: git-send-email 2.31.1 In-Reply-To: References: MIME-Version: 1.0 Received-SPF: none client-ip=2607:f8b0:4864:20::c36; envelope-from=yong.huang@smartx.com; helo=mail-oo1-xc36.google.com X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_NONE=0.001, T_SCC_BODY_TEXT_LINE=-0.01 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+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org From: Hyman Huang Firstly, enable the ability to choose the block device containing a detachable LUKS header by adding the 'header' parameter to BlockdevCreateOptionsLUKS. Secondly, when formatting the LUKS volume with a detachable header, truncate the payload volume to length without a header size. Using the qmp blockdev command, create the LUKS volume with a detachable header as follows: 1. add the secret to lock/unlock the cipher stored in the detached LUKS header $ virsh qemu-monitor-command vm '{"execute":"object-add", > "arguments":{"qom-type": "secret", "id": "sec0", "data": "foo"}}' 2. create a header img with 0 size $ virsh qemu-monitor-command vm '{"execute":"blockdev-create", > "arguments":{"job-id":"job0", "options":{"driver":"file", > "filename":"/path/to/detached_luks_header.img", "size":0 }}}' 3. add protocol blockdev node for header $ virsh qemu-monitor-command vm '{"execute":"blockdev-add", > "arguments": {"driver":"file", "filename": > "/path/to/detached_luks_header.img", "node-name": > "detached-luks-header-storage"}}' 4. create a payload img with 0 size $ virsh qemu-monitor-command vm '{"execute":"blockdev-create", > "arguments":{"job-id":"job1", "options":{"driver":"file", > "filename":"/path/to/detached_luks_payload_raw.img", "size":0}}}' 5. add protocol blockdev node for payload $ virsh qemu-monitor-command vm '{"execute":"blockdev-add", > "arguments": {"driver":"file", "filename": > "/path/to/detached_luks_payload_raw.img", "node-name": > "luks-payload-raw-storage"}}' 6. do the formatting with 128M size $ virsh qemu-monitor-command c81_node1 '{"execute":"blockdev-create", > "arguments":{"job-id":"job2", "options":{"driver":"luks", "header": > "detached-luks-header-storage", "file":"luks-payload-raw-storage", > "size":134217728, "preallocation":"full", "key-secret":"sec0" }}}' Signed-off-by: Hyman Huang Reviewed-by: Daniel P. Berrangé --- block/crypto.c | 101 +++++++++++++++++++++++++++++++++++++++---- qapi/block-core.json | 3 ++ 2 files changed, 96 insertions(+), 8 deletions(-) diff --git a/block/crypto.c b/block/crypto.c index 1b3f87922a..8e7ee5e9ac 100644 --- a/block/crypto.c +++ b/block/crypto.c @@ -162,6 +162,48 @@ error: return ret; } +static int coroutine_fn GRAPH_UNLOCKED +block_crypto_co_format_luks_payload(BlockdevCreateOptionsLUKS *luks_opts, + Error **errp) +{ + BlockDriverState *bs = NULL; + BlockBackend *blk = NULL; + Error *local_error = NULL; + int ret; + + if (luks_opts->size > INT64_MAX) { + return -EFBIG; + } + + bs = bdrv_co_open_blockdev_ref(luks_opts->file, errp); + if (bs == NULL) { + return -EIO; + } + + blk = blk_co_new_with_bs(bs, BLK_PERM_WRITE | BLK_PERM_RESIZE, + BLK_PERM_ALL, errp); + if (!blk) { + ret = -EPERM; + goto fail; + } + + ret = blk_truncate(blk, luks_opts->size, true, + luks_opts->preallocation, 0, &local_error); + if (ret < 0) { + if (ret == -EFBIG) { + /* Replace the error message with a better one */ + error_free(local_error); + error_setg(errp, "The requested file size is too large"); + } + goto fail; + } + + ret = 0; + +fail: + bdrv_co_unref(bs); + return ret; +} static QemuOptsList block_crypto_runtime_opts_luks = { .name = "crypto", @@ -341,7 +383,9 @@ static int block_crypto_open_generic(QCryptoBlockFormat format, static int coroutine_fn GRAPH_UNLOCKED block_crypto_co_create_generic(BlockDriverState *bs, int64_t size, QCryptoBlockCreateOptions *opts, - PreallocMode prealloc, Error **errp) + PreallocMode prealloc, + unsigned int flags, + Error **errp) { int ret; BlockBackend *blk; @@ -369,7 +413,7 @@ block_crypto_co_create_generic(BlockDriverState *bs, int64_t size, block_crypto_create_init_func, block_crypto_create_write_func, &data, - 0, + flags, errp); if (!crypto) { @@ -656,16 +700,26 @@ static int coroutine_fn GRAPH_UNLOCKED block_crypto_co_create_luks(BlockdevCreateOptions *create_options, Error **errp) { BlockdevCreateOptionsLUKS *luks_opts; + BlockDriverState *hdr_bs = NULL; BlockDriverState *bs = NULL; QCryptoBlockCreateOptions create_opts; PreallocMode preallocation = PREALLOC_MODE_OFF; + unsigned int cflags = 0; int ret; assert(create_options->driver == BLOCKDEV_DRIVER_LUKS); luks_opts = &create_options->u.luks; - if (luks_opts->file == NULL) { - error_setg(errp, "Formatting LUKS disk requires parameter 'file'"); + if (luks_opts->header == NULL && luks_opts->file == NULL) { + error_setg(errp, "Either the parameter 'header' or 'file' must " + "be specified"); + return -EINVAL; + } + + if ((luks_opts->preallocation != PREALLOC_MODE_OFF) && + (luks_opts->file == NULL)) { + error_setg(errp, "Parameter 'preallocation' requires 'file' to be " + "specified for formatting LUKS disk"); return -EINVAL; } @@ -678,14 +732,38 @@ block_crypto_co_create_luks(BlockdevCreateOptions *create_options, Error **errp) preallocation = luks_opts->preallocation; } - if (luks_opts->file) { + if (luks_opts->header) { + /* LUKS volume with detached header */ + hdr_bs = bdrv_co_open_blockdev_ref(luks_opts->header, errp); + if (hdr_bs == NULL) { + return -EIO; + } + + cflags |= QCRYPTO_BLOCK_CREATE_DETACHED; + + /* Format the LUKS header node */ + ret = block_crypto_co_create_generic(hdr_bs, 0, &create_opts, + PREALLOC_MODE_OFF, cflags, errp); + if (ret < 0) { + goto fail; + } + + /* Format the LUKS payload node */ + if (luks_opts->file) { + ret = block_crypto_co_format_luks_payload(luks_opts, errp); + if (ret < 0) { + goto fail; + } + } + } else if (luks_opts->file) { + /* LUKS volume with none-detached header */ bs = bdrv_co_open_blockdev_ref(luks_opts->file, errp); if (bs == NULL) { return -EIO; } ret = block_crypto_co_create_generic(bs, luks_opts->size, &create_opts, - preallocation, errp); + preallocation, cflags, errp); if (ret < 0) { goto fail; } @@ -693,7 +771,13 @@ block_crypto_co_create_luks(BlockdevCreateOptions *create_options, Error **errp) ret = 0; fail: - bdrv_co_unref(bs); + if (hdr_bs != NULL) { + bdrv_co_unref(hdr_bs); + } + + if (bs != NULL) { + bdrv_co_unref(bs); + } return ret; } @@ -747,7 +831,8 @@ block_crypto_co_create_opts_luks(BlockDriver *drv, const char *filename, } /* Create format layer */ - ret = block_crypto_co_create_generic(bs, size, create_opts, prealloc, errp); + ret = block_crypto_co_create_generic(bs, size, create_opts, + prealloc, 0, errp); if (ret < 0) { goto fail; } diff --git a/qapi/block-core.json b/qapi/block-core.json index 69a88d613d..eab15d7dd9 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -4960,6 +4960,8 @@ # @file: Node to create the image format on, mandatory except when # 'preallocation' is not requested # +# @header: Block device holding a detached LUKS header. (since 9.0) +# # @size: Size of the virtual disk in bytes # # @preallocation: Preallocation mode for the new image (since: 4.2) @@ -4970,6 +4972,7 @@ { 'struct': 'BlockdevCreateOptionsLUKS', 'base': 'QCryptoBlockCreateOptionsLUKS', 'data': { '*file': 'BlockdevRef', + '*header': 'BlockdevRef', 'size': 'size', '*preallocation': 'PreallocMode' } } From patchwork Tue Jan 30 05:37:23 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Yong Huang X-Patchwork-Id: 13536901 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id F0668C46CD2 for ; Tue, 30 Jan 2024 05:40:47 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1rUgqi-0002uD-55; Tue, 30 Jan 2024 00:39:56 -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 1rUgqe-0002tb-V3 for qemu-devel@nongnu.org; Tue, 30 Jan 2024 00:39:52 -0500 Received: from mail-yw1-x1134.google.com ([2607:f8b0:4864:20::1134]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1rUgqW-0001NY-OT for qemu-devel@nongnu.org; Tue, 30 Jan 2024 00:39:46 -0500 Received: by mail-yw1-x1134.google.com with SMTP id 00721157ae682-603e7d19725so13626597b3.0 for ; Mon, 29 Jan 2024 21:37:44 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=smartx-com.20230601.gappssmtp.com; s=20230601; t=1706593063; x=1707197863; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=tzPI5ZhDw6r0Ms2tiVi1ga4ywHBkJRenawMuK5yu+b8=; b=Fx1BLk3Ey4o+HWaGrHLGRVWrFduBY42rza3JIYEOCJuf10gRNOa4t0aiaOvHFckWG9 T/j4FEDuNvRO3PvfvLSs09AX1uvnpVF1ZJ8c1YEblmmvZTz8HHVWngXuzewXP0/FY44N uvVbL8qAZN/IQRu3SUSwIpyUme2C1DiQTD3hvekfziFM+xgcXC7WXCkP13nURU76jJAD jlaDoSwaxndzRiZMG/fvr6UFKNyoOw1O3uGG7/hvrmygs+waM56ES+/8dDJcUWeOqKWq AJuuJckp6Xwcck+AWjJM+kNlB3g+mnjZiGeIGOMViGNvUg/vCUu5ekKGliCEyoerqdl9 h++Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1706593063; x=1707197863; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=tzPI5ZhDw6r0Ms2tiVi1ga4ywHBkJRenawMuK5yu+b8=; b=mvV32YhmAOQTuXpOKARP2nZF0oge0r8/3KzK6PnRSOL95p5ULLdcyHYDib5q9W1Rlh DBaaAY2U32HvEmfcvNTz5NsIUxOAywwGemDmAtoSuaicUJIEdpcSGdmXvAdLAqkCUNRh +y0roKq3tHnsNNcunhL1ZaqvSG2bk1uxiBeIrBBJxJCjzjSqzWFCsiY8tSvBChKypRJE 7tnzfeE//PtfGXg9iw3F0iQDCzSVy1OXhvVtgwEBBNAYY/9s8U/X/eVVbnBRTaI5hHQP 6iyMBzJhLUi2GNoBP5OgzKI7gTK/MOXZ7vBsRdo/RzoavHfpadX3WnpwGlw62Gk6EnR+ kP2Q== X-Gm-Message-State: AOJu0Yyd51sHbwE/vw4WT/6G6RY3sztyzezxQpaRgr7phpc7i5qZjg+K BHzD4sNfpU0Hy2hgY7R6smlCr9rxBBxYNfDUoWjZ2+s9yfgRk4FJrqpxsnNHhx5BqE/Fhd/51SV p4o4= X-Google-Smtp-Source: AGHT+IGIUC/LR1n0jPxa3coZEwW292LRhFWh84+rkQTHq9RXPWZD+rZJSG4Au/0kSt/C6acM2Cm8Yw== X-Received: by 2002:a5b:d0d:0:b0:dc2:66ab:84b0 with SMTP id y13-20020a5b0d0d000000b00dc266ab84b0mr5707041ybp.64.1706593062808; Mon, 29 Jan 2024 21:37:42 -0800 (PST) Received: from anolis-dev.zelin.local ([221.122.98.162]) by smtp.gmail.com with ESMTPSA id bv123-20020a632e81000000b005c1ce3c960bsm7343532pgb.50.2024.01.29.21.37.40 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 29 Jan 2024 21:37:42 -0800 (PST) From: yong.huang@smartx.com To: qemu-devel@nongnu.org Cc: =?utf-8?q?Daniel_P_=2E_Berrang=C3=A9?= , Eric Blake , Markus Armbruster , Hanna Reitz , Kevin Wolf , yong.huang@smartx.com Subject: [PATCH v4 5/7] block: Support detached LUKS header creation using qemu-img Date: Tue, 30 Jan 2024 13:37:23 +0800 Message-Id: X-Mailer: git-send-email 2.31.1 In-Reply-To: References: MIME-Version: 1.0 Received-SPF: none client-ip=2607:f8b0:4864:20::1134; envelope-from=yong.huang@smartx.com; helo=mail-yw1-x1134.google.com X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_NONE=0.001, T_SCC_BODY_TEXT_LINE=-0.01 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+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org From: Hyman Huang Even though a LUKS header might be created with cryptsetup, qemu-img should be enhanced to accommodate it as well. Add the 'detached-header' option to specify the creation of a detached LUKS header. This is how it is used: $ qemu-img create --object secret,id=sec0,data=abc123 -f luks > -o cipher-alg=aes-256,cipher-mode=xts -o key-secret=sec0 > -o detached-header=true header.luks Using qemu-img or cryptsetup tools to query information of an LUKS header image as follows: Assume a detached LUKS header image has been created by: $ dd if=/dev/zero of=test-header.img bs=1M count=32 $ dd if=/dev/zero of=test-payload.img bs=1M count=1000 $ cryptsetup luksFormat --header test-header.img test-payload.img > --force-password --type luks1 Header image information could be queried using cryptsetup: $ cryptsetup luksDump test-header.img or qemu-img: $ qemu-img info 'json:{"driver":"luks","file":{"filename": > "test-payload.img"},"header":{"filename":"test-header.img"}}' When using qemu-img, keep in mind that the entire disk information specified by the JSON-format string above must be supplied on the commandline; if not, an overlay check will reveal a problem with the LUKS volume check logic. Signed-off-by: Hyman Huang Reviewed-by: Daniel P. Berrangé --- block.c | 5 ++++- block/crypto.c | 10 +++++++++- block/crypto.h | 8 ++++++++ qapi/crypto.json | 5 ++++- 4 files changed, 25 insertions(+), 3 deletions(-) diff --git a/block.c b/block.c index 30afdcbba6..1ed9214f66 100644 --- a/block.c +++ b/block.c @@ -7357,7 +7357,10 @@ void bdrv_img_create(const char *filename, const char *fmt, goto out; } - if (size == -1) { + /* Parameter 'size' is not needed for detached LUKS header */ + if (size == -1 && + !(!strcmp(fmt, "luks") && + qemu_opt_get_bool(opts, "detached-header", false))) { error_setg(errp, "Image creation needs a size parameter"); goto out; } diff --git a/block/crypto.c b/block/crypto.c index 8e7ee5e9ac..65426d3a16 100644 --- a/block/crypto.c +++ b/block/crypto.c @@ -231,6 +231,7 @@ static QemuOptsList block_crypto_create_opts_luks = { BLOCK_CRYPTO_OPT_DEF_LUKS_IVGEN_HASH_ALG(""), BLOCK_CRYPTO_OPT_DEF_LUKS_HASH_ALG(""), BLOCK_CRYPTO_OPT_DEF_LUKS_ITER_TIME(""), + BLOCK_CRYPTO_OPT_DEF_LUKS_DETACHED_HEADER(""), { /* end of list */ } }, }; @@ -405,7 +406,7 @@ block_crypto_co_create_generic(BlockDriverState *bs, int64_t size, data = (struct BlockCryptoCreateData) { .blk = blk, - .size = size, + .size = flags & QCRYPTO_BLOCK_CREATE_DETACHED ? 0 : size, .prealloc = prealloc, }; @@ -791,6 +792,9 @@ block_crypto_co_create_opts_luks(BlockDriver *drv, const char *filename, PreallocMode prealloc; char *buf = NULL; int64_t size; + bool detached_hdr = + qemu_opt_get_bool(opts, "detached-header", false); + unsigned int cflags = 0; int ret; Error *local_err = NULL; @@ -830,6 +834,10 @@ block_crypto_co_create_opts_luks(BlockDriver *drv, const char *filename, goto fail; } + if (detached_hdr) { + cflags |= QCRYPTO_BLOCK_CREATE_DETACHED; + } + /* Create format layer */ ret = block_crypto_co_create_generic(bs, size, create_opts, prealloc, 0, errp); diff --git a/block/crypto.h b/block/crypto.h index 72e792c9af..dc3d2d5ed9 100644 --- a/block/crypto.h +++ b/block/crypto.h @@ -41,6 +41,7 @@ #define BLOCK_CRYPTO_OPT_LUKS_IVGEN_HASH_ALG "ivgen-hash-alg" #define BLOCK_CRYPTO_OPT_LUKS_HASH_ALG "hash-alg" #define BLOCK_CRYPTO_OPT_LUKS_ITER_TIME "iter-time" +#define BLOCK_CRYPTO_OPT_LUKS_DETACHED_HEADER "detached-header" #define BLOCK_CRYPTO_OPT_LUKS_KEYSLOT "keyslot" #define BLOCK_CRYPTO_OPT_LUKS_STATE "state" #define BLOCK_CRYPTO_OPT_LUKS_OLD_SECRET "old-secret" @@ -100,6 +101,13 @@ .help = "Select new state of affected keyslots (active/inactive)",\ } +#define BLOCK_CRYPTO_OPT_DEF_LUKS_DETACHED_HEADER(prefix) \ + { \ + .name = prefix BLOCK_CRYPTO_OPT_LUKS_DETACHED_HEADER, \ + .type = QEMU_OPT_BOOL, \ + .help = "Create a detached LUKS header", \ + } + #define BLOCK_CRYPTO_OPT_DEF_LUKS_KEYSLOT(prefix) \ { \ .name = prefix BLOCK_CRYPTO_OPT_LUKS_KEYSLOT, \ diff --git a/qapi/crypto.json b/qapi/crypto.json index fd3d46ebd1..62fd145223 100644 --- a/qapi/crypto.json +++ b/qapi/crypto.json @@ -223,6 +223,8 @@ # @iter-time: number of milliseconds to spend in PBKDF passphrase # processing. Currently defaults to 2000. (since 2.8) # +# @detached-header: create a detached LUKS header. (since 9.0) +# # Since: 2.6 ## { 'struct': 'QCryptoBlockCreateOptionsLUKS', @@ -232,7 +234,8 @@ '*ivgen-alg': 'QCryptoIVGenAlgorithm', '*ivgen-hash-alg': 'QCryptoHashAlgorithm', '*hash-alg': 'QCryptoHashAlgorithm', - '*iter-time': 'int'}} + '*iter-time': 'int', + '*detached-header': 'bool'}} ## # @QCryptoBlockOpenOptions: From patchwork Tue Jan 30 05:37:24 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Yong Huang X-Patchwork-Id: 13536900 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 09F0CC47DA9 for ; Tue, 30 Jan 2024 05:40:47 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1rUgql-0002uX-D5; Tue, 30 Jan 2024 00:40:00 -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 1rUgqg-0002tq-8d for qemu-devel@nongnu.org; Tue, 30 Jan 2024 00:39:54 -0500 Received: from mail-yb1-xb31.google.com ([2607:f8b0:4864:20::b31]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1rUgqZ-0001Nh-1G for qemu-devel@nongnu.org; Tue, 30 Jan 2024 00:39:54 -0500 Received: by mail-yb1-xb31.google.com with SMTP id 3f1490d57ef6-dc608c3718dso2988529276.1 for ; Mon, 29 Jan 2024 21:37:46 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=smartx-com.20230601.gappssmtp.com; s=20230601; t=1706593066; x=1707197866; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=shO/Z0O568FxrbBMQD3Us+o0eIumB7pwZZUUIjpimB0=; b=Rj7vF0E2zXvBVHvhLFBbEo8i4pJp3HVVslvd84WzWCj3esd99v4Y76G8OpGFoSlQH1 Uy3pwouZZFP0HlN7ZCRjFryhhw9s3xJL9v3DjTnrKPG3ccSqvdI5LbvZS20EMDl7uPsv MJkpUWenZ3QWNUuuYY4Gym/EvHhZrrH12n9oSpd3HgiPwad/ODPtaTOu7hzCz5Z/I7C1 uHBV5VZZDjiPFKDn1ukuZ0nbtGV3OW516boHm8ceu8lBQvD02cKARr7ItCZF2YiPK0wR WrY0VhiWuws9oNoGILpz1nxC0jydj4jqaimFfk9YAUmV7TeqkEzWyjBe+ReIYSQR6BLM TRUQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1706593066; x=1707197866; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=shO/Z0O568FxrbBMQD3Us+o0eIumB7pwZZUUIjpimB0=; b=IRW8Crg4EvOoFeKO7MyyWq99t/EyuImQRgNH+9QfsCdzFn6cXJjftHsStfEA5zY1nm sBLajX+YUKgPq5hUJIWn5MSC9dVmbtNloyGwCKAK70DyysJVjYFHJ7Oedom0ZvIMm2iF MoP4xM86cItu4sekw5cad9+LpB3U/kNG4jfVWnWFURHTy/+FgPL+iMUbkaAGQjkU1aGC NM0SkT7DmdYDWlsRjWNWwULJBcuN3/nXDAS5/wJzhNe30b3Uskf8Q1fvdNhIvRlWbTdt eYmpSUXfp4xSG0ssZMAvtm5+YdXxpgLXQGWpq+RnX4nn3dtTK7R00mu954QbDclgOJNP 865w== X-Gm-Message-State: AOJu0YzU1FnyMh5NTfUtAGeF29b7j5WhG+gChSD+3OtE4UaTcYPJZ8Kj s25TzfAvUFkdeh6dY187m6uq8QH+2X7mrhoZBt8cHir7RzGop/qrZY8KW0bFXQ9CMfZ/+YxgIt/ H0B4= X-Google-Smtp-Source: AGHT+IHzHPyU+n+Te9GtlFCtkODPx7Fjq9neQNQSI9Y91jzlXxzjaKDAYxIayDkTypZ2Tp5A2wBz/w== X-Received: by 2002:a81:e202:0:b0:600:769:179f with SMTP id p2-20020a81e202000000b006000769179fmr6338729ywl.17.1706593065168; Mon, 29 Jan 2024 21:37:45 -0800 (PST) Received: from anolis-dev.zelin.local ([221.122.98.162]) by smtp.gmail.com with ESMTPSA id bv123-20020a632e81000000b005c1ce3c960bsm7343532pgb.50.2024.01.29.21.37.43 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 29 Jan 2024 21:37:44 -0800 (PST) From: yong.huang@smartx.com To: qemu-devel@nongnu.org Cc: =?utf-8?q?Daniel_P_=2E_Berrang=C3=A9?= , Eric Blake , Markus Armbruster , Hanna Reitz , Kevin Wolf , yong.huang@smartx.com Subject: [PATCH v4 6/7] crypto: Introduce 'detached-header' field in QCryptoBlockInfoLUKS Date: Tue, 30 Jan 2024 13:37:24 +0800 Message-Id: <722845380ae359b452c525eb95103a1723f5a192.1706586786.git.yong.huang@smartx.com> X-Mailer: git-send-email 2.31.1 In-Reply-To: References: MIME-Version: 1.0 Received-SPF: none client-ip=2607:f8b0:4864:20::b31; envelope-from=yong.huang@smartx.com; helo=mail-yb1-xb31.google.com X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_NONE=0.001, T_SCC_BODY_TEXT_LINE=-0.01 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+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org From: Hyman Huang When querying the LUKS disk with the qemu-img tool or other APIs, add information about whether the LUKS header is detached. Additionally, update the test case with the appropriate modification. Signed-off-by: Hyman Huang Reviewed-by: Daniel P. Berrangé --- crypto/block-luks.c | 2 ++ qapi/crypto.json | 3 +++ tests/qemu-iotests/210.out | 4 ++++ 3 files changed, 9 insertions(+) diff --git a/crypto/block-luks.c b/crypto/block-luks.c index 8ad7cc44a5..3c168aa86f 100644 --- a/crypto/block-luks.c +++ b/crypto/block-luks.c @@ -1260,6 +1260,7 @@ qcrypto_block_luks_open(QCryptoBlock *block, block->sector_size = QCRYPTO_BLOCK_LUKS_SECTOR_SIZE; block->payload_offset = luks->header.payload_offset_sector * block->sector_size; + block->detached_header = (block->payload_offset == 0) ? true : false; return 0; @@ -1884,6 +1885,7 @@ static int qcrypto_block_luks_get_info(QCryptoBlock *block, info->u.luks.master_key_iters = luks->header.master_key_iterations; info->u.luks.uuid = g_strndup((const char *)luks->header.uuid, sizeof(luks->header.uuid)); + info->u.luks.detached_header = block->detached_header; for (i = 0; i < QCRYPTO_BLOCK_LUKS_NUM_KEY_SLOTS; i++) { slot = g_new0(QCryptoBlockInfoLUKSSlot, 1); diff --git a/qapi/crypto.json b/qapi/crypto.json index 62fd145223..f8b00cdc4d 100644 --- a/qapi/crypto.json +++ b/qapi/crypto.json @@ -314,6 +314,8 @@ # # @hash-alg: the master key hash algorithm # +# @detached-header: whether the LUKS header is detached (Since 9.0) +# # @payload-offset: offset to the payload data in bytes # # @master-key-iters: number of PBKDF2 iterations for key material @@ -330,6 +332,7 @@ 'ivgen-alg': 'QCryptoIVGenAlgorithm', '*ivgen-hash-alg': 'QCryptoHashAlgorithm', 'hash-alg': 'QCryptoHashAlgorithm', + 'detached-header': 'bool', 'payload-offset': 'int', 'master-key-iters': 'int', 'uuid': 'str', diff --git a/tests/qemu-iotests/210.out b/tests/qemu-iotests/210.out index 96d9f749dd..94b29b2120 100644 --- a/tests/qemu-iotests/210.out +++ b/tests/qemu-iotests/210.out @@ -18,6 +18,7 @@ virtual size: 128 MiB (134217728 bytes) encrypted: yes Format specific information: ivgen alg: plain64 + detached header: false hash alg: sha256 cipher alg: aes-256 uuid: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX @@ -70,6 +71,7 @@ virtual size: 64 MiB (67108864 bytes) encrypted: yes Format specific information: ivgen alg: plain64 + detached header: false hash alg: sha1 cipher alg: aes-128 uuid: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX @@ -125,6 +127,7 @@ virtual size: 0 B (0 bytes) encrypted: yes Format specific information: ivgen alg: plain64 + detached header: false hash alg: sha256 cipher alg: aes-256 uuid: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX @@ -195,6 +198,7 @@ virtual size: 0 B (0 bytes) encrypted: yes Format specific information: ivgen alg: plain64 + detached header: false hash alg: sha256 cipher alg: aes-256 uuid: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX From patchwork Tue Jan 30 05:37:25 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Yong Huang X-Patchwork-Id: 13536904 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id C3B96C46CD2 for ; Tue, 30 Jan 2024 05:41:15 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1rUgqm-0002uZ-64; Tue, 30 Jan 2024 00:40:01 -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 1rUgqg-0002u0-Ni for qemu-devel@nongnu.org; Tue, 30 Jan 2024 00:39:54 -0500 Received: from mail-oo1-xc2a.google.com ([2607:f8b0:4864:20::c2a]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1rUgqb-0001O6-EN for qemu-devel@nongnu.org; Tue, 30 Jan 2024 00:39:54 -0500 Received: by mail-oo1-xc2a.google.com with SMTP id 006d021491bc7-5961a2726aaso2031956eaf.0 for ; Mon, 29 Jan 2024 21:37:49 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=smartx-com.20230601.gappssmtp.com; s=20230601; t=1706593068; x=1707197868; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=QCfSOssekZN4zKobgArXjcljl64GHI25OWtrrgugOcQ=; b=ZQJHUY5VAHjuLKOPTQ7/5RIIQTz1yfc7HR7dmqiSDPmDVpQqyc/Ap80QZAB47Am3K0 a0jEcMLlB/GC5FFONuUx/g6P1MtmmvOO9zPTb9hPLdXLUBXm8NdG4O7ZVVIKchiJn4jH BAFz7Zdlbx7Rxv1y9teAS5VW+IkveIp2vxK5HE5Ek7YmTlS5QdkjJ1rb6Uukxz3Z+bTy QkwNHhMe55yNc00lBk1wlxmmz8NaJrSFYEZp3BXiTSn1i0/vtaPiReyKuGMjzfkBpiRJ ThSIEpVMhK2DxccTN4KTMKymZf4UTnDMcDSetF8TQY5wUjEEiOyorBzeg0hd9n3qIgzB /HAA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1706593068; x=1707197868; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=QCfSOssekZN4zKobgArXjcljl64GHI25OWtrrgugOcQ=; b=Zpjgtx7vRsslD/RAL1LTgRbkt7+S5IcEmBvPGo8RSysHwhfqX+YMCBGNT+oyQyBfpV ggDdbh2N0iv/uD/c5lUN7F8oCXvMFTl9W2m21IbPS8V7/Grm8zxFHwHFKSRaGynLNsB1 wlymHLIWYR7+0IIIOYxyFl9XRMIgSrpBn3xnvUxe4KeXOcwqnuq9T5MlT5BY2J2VOekz g1bzI+qSWFMBQOTkhh511F21//wv1us3bhR63hKIwSUFzr4g1OdN2HoFjyE6AfpJ8+i+ jOxvqzEQKABhgHIrJqs0KY3nu7OmXITgoE7zV7bIDrDO7yfDBKBQeGZcPwp82rhau/LX I/sg== X-Gm-Message-State: AOJu0YzgX06MMApGLOhZmfkH0KlL1rmJWp0MLOMMz964MZmtk/hiXNyC LdxPpKy0krrqMZBQPB6KK+7uh/oJ04+NO+nWicW6yIg+OfgS4tua/qF9GQ4Z5wEFUYehxk7TkTw pt/g= X-Google-Smtp-Source: AGHT+IG1xLeQGtKw934ZWtEDgUSX2T++i5eXiXbI5EV/glI55bM1oqNGlPc164gHKLZLOE+GjLWfjA== X-Received: by 2002:a05:6358:9216:b0:177:2984:3db8 with SMTP id d22-20020a056358921600b0017729843db8mr4205888rwb.20.1706593067526; Mon, 29 Jan 2024 21:37:47 -0800 (PST) Received: from anolis-dev.zelin.local ([221.122.98.162]) by smtp.gmail.com with ESMTPSA id bv123-20020a632e81000000b005c1ce3c960bsm7343532pgb.50.2024.01.29.21.37.45 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 29 Jan 2024 21:37:47 -0800 (PST) From: yong.huang@smartx.com To: qemu-devel@nongnu.org Cc: =?utf-8?q?Daniel_P_=2E_Berrang=C3=A9?= , Eric Blake , Markus Armbruster , Hanna Reitz , Kevin Wolf , yong.huang@smartx.com Subject: [PATCH v4 7/7] tests: Add case for LUKS volume with detached header Date: Tue, 30 Jan 2024 13:37:25 +0800 Message-Id: <87aa559fbc0c98a5b90ac4f3fa25cb7438a5c181.1706586786.git.yong.huang@smartx.com> X-Mailer: git-send-email 2.31.1 In-Reply-To: References: MIME-Version: 1.0 Received-SPF: none client-ip=2607:f8b0:4864:20::c2a; envelope-from=yong.huang@smartx.com; helo=mail-oo1-xc2a.google.com X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_NONE=0.001, T_SCC_BODY_TEXT_LINE=-0.01 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+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org From: Hyman Huang Also, add a section to the MAINTAINERS file for detached LUKS header, it only has a test case in it currently. Signed-off-by: Hyman Huang Reviewed-by: Daniel P. Berrangé --- MAINTAINERS | 5 + tests/qemu-iotests/tests/luks-detached-header | 218 ++++++++++++++++++ .../tests/luks-detached-header.out | 5 + 3 files changed, 228 insertions(+) create mode 100755 tests/qemu-iotests/tests/luks-detached-header create mode 100644 tests/qemu-iotests/tests/luks-detached-header.out diff --git a/MAINTAINERS b/MAINTAINERS index dfaca8323e..fddd3348c2 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3402,6 +3402,11 @@ F: migration/dirtyrate.c F: migration/dirtyrate.h F: include/sysemu/dirtyrate.h +Detached LUKS header +M: Hyman Huang +S: Maintained +F: tests/qemu-iotests/tests/luks-detached-header + D-Bus M: Marc-André Lureau S: Maintained diff --git a/tests/qemu-iotests/tests/luks-detached-header b/tests/qemu-iotests/tests/luks-detached-header new file mode 100755 index 0000000000..f0b5f3921c --- /dev/null +++ b/tests/qemu-iotests/tests/luks-detached-header @@ -0,0 +1,218 @@ +#!/usr/bin/env python3 +# group: rw auto +# +# Test LUKS volume with detached header +# +# Copyright (C) 2024 SmartX Inc. +# +# Authors: +# Hyman Huang +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# + +import os +import iotests +from iotests import imgfmt, qemu_img_create, img_info_log, qemu_img_info, QMPTestCase + + +image_size = 128 * 1024 * 1024 + +luks_img = os.path.join(iotests.test_dir, 'luks.img') +detached_header_img1 = os.path.join(iotests.test_dir, 'detached_header.img1') +detached_header_img2 = os.path.join(iotests.test_dir, 'detached_header.img2') +detached_payload_raw_img = os.path.join(iotests.test_dir, 'detached_payload_raw.img') +detached_payload_qcow2_img = os.path.join(iotests.test_dir, 'detached_payload_qcow2.img') +detached_header_raw_img = \ + "json:{\"driver\":\"luks\",\"file\":{\"filename\":\"%s\"},\"header\":{\"filename\":\"%s\"}}" % (detached_payload_raw_img, detached_header_img1) +detached_header_qcow2_img = \ + "json:{\"driver\":\"luks\",\"file\":{\"filename\":\"%s\"},\"header\":{\"filename\":\"%s\"}}" % (detached_payload_qcow2_img, detached_header_img2) + +secret_obj = 'secret,id=sec0,data=foo' +luks_opts = 'key-secret=sec0' + + +class TestDetachedLUKSHeader(QMPTestCase): + def setUp(self) -> None: + self.vm = iotests.VM() + self.vm.add_object(secret_obj) + self.vm.launch() + + # 1. Create the normal LUKS disk with 128M size + self.vm.blockdev_create({ 'driver': 'file', + 'filename': luks_img, + 'size': 0 }) + self.vm.qmp_log('blockdev-add', driver='file', filename=luks_img, + node_name='luks-1-storage') + result = self.vm.blockdev_create({ 'driver': imgfmt, + 'file': 'luks-1-storage', + 'key-secret': 'sec0', + 'size': image_size, + 'iter-time': 10 }) + # None is expected + self.assertEqual(result, None) + + # 2. Create the LUKS disk with detached header (raw) + + # Create detached LUKS header + self.vm.blockdev_create({ 'driver': 'file', + 'filename': detached_header_img1, + 'size': 0 }) + self.vm.qmp_log('blockdev-add', driver='file', filename=detached_header_img1, + node_name='luks-2-header-storage') + + # Create detached LUKS raw payload + self.vm.blockdev_create({ 'driver': 'file', + 'filename': detached_payload_raw_img, + 'size': 0 }) + self.vm.qmp_log('blockdev-add', driver='file', + filename=detached_payload_raw_img, + node_name='luks-2-payload-storage') + + # Format LUKS disk with detached header + result = self.vm.blockdev_create({ 'driver': imgfmt, + 'header': 'luks-2-header-storage', + 'file': 'luks-2-payload-storage', + 'key-secret': 'sec0', + 'preallocation': 'full', + 'size': image_size, + 'iter-time': 10 }) + self.assertEqual(result, None) + + self.vm.shutdown() + + # 3. Create the LUKS disk with detached header (qcow2) + + # Create detached LUKS header using qemu-img + res = qemu_img_create('-f', 'luks', '--object', secret_obj, '-o', luks_opts, + '-o', "detached-header=true", detached_header_img2) + assert res.returncode == 0 + + # Create detached LUKS qcow2 payload + res = qemu_img_create('-f', 'qcow2', detached_payload_qcow2_img, str(image_size)) + assert res.returncode == 0 + + def tearDown(self) -> None: + os.remove(luks_img) + os.remove(detached_header_img1) + os.remove(detached_header_img2) + os.remove(detached_payload_raw_img) + os.remove(detached_payload_qcow2_img) + + # Check if there was any qemu-io run that failed + if 'Pattern verification failed' in self.vm.get_log(): + print('ERROR: Pattern verification failed:') + print(self.vm.get_log()) + self.fail('qemu-io pattern verification failed') + + def test_img_creation(self) -> None: + # Check if the images created above are expected + + data = qemu_img_info(luks_img)['format-specific'] + self.assertEqual(data['type'], imgfmt) + self.assertEqual(data['data']['detached-header'], False) + + data = qemu_img_info(detached_header_raw_img)['format-specific'] + self.assertEqual(data['type'], imgfmt) + self.assertEqual(data['data']['detached-header'], True) + + data = qemu_img_info(detached_header_qcow2_img)['format-specific'] + self.assertEqual(data['type'], imgfmt) + self.assertEqual(data['data']['detached-header'], True) + + # Check if preallocation works + size = qemu_img_info(detached_payload_raw_img)['actual-size'] + self.assertGreaterEqual(size, image_size) + + def test_detached_luks_header(self) -> None: + self.vm.launch() + + # 1. Add the disk created above + + # Add normal LUKS disk + self.vm.qmp_log('blockdev-add', driver='file', filename=luks_img, + node_name='luks-1-storage') + result = self.vm.qmp_log('blockdev-add', driver='luks', file='luks-1-storage', + key_secret='sec0', node_name='luks-1-format') + + # Expected result{ "return": {} } + self.assert_qmp(result, 'return', {}) + + # Add detached LUKS header with raw payload + self.vm.qmp_log('blockdev-add', driver='file', filename=detached_header_img1, + node_name='luks-header1-storage') + + self.vm.qmp_log('blockdev-add', driver='file', filename=detached_payload_raw_img, + node_name='luks-2-payload-raw-storage') + + result = self.vm.qmp_log('blockdev-add', driver=imgfmt, + header='luks-header1-storage', + file='luks-2-payload-raw-storage', + key_secret='sec0', + node_name='luks-2-payload-raw-format') + self.assert_qmp(result, 'return', {}) + + # Add detached LUKS header with qcow2 payload + self.vm.qmp_log('blockdev-add', driver='file', filename=detached_header_img2, + node_name='luks-header2-storage') + + self.vm.qmp_log('blockdev-add', driver='file', filename=detached_payload_qcow2_img, + node_name='luks-3-payload-qcow2-storage') + + result = self.vm.qmp_log('blockdev-add', driver=imgfmt, + header='luks-header2-storage', + file='luks-3-payload-qcow2-storage', + key_secret='sec0', + node_name='luks-3-payload-qcow2-format') + self.assert_qmp(result, 'return', {}) + + # 2. Do I/O test + + # Do some I/O to the image to see whether it still works + # (Pattern verification will be checked by tearDown()) + + # Normal LUKS disk + result = self.vm.qmp_log('human-monitor-command', + command_line='qemu-io luks-1-format "write -P 40 0 64k"') + self.assert_qmp(result, 'return', '') + + result = self.vm.qmp_log('human-monitor-command', + command_line='qemu-io luks-1-format "read -P 40 0 64k"') + self.assert_qmp(result, 'return', '') + + # Detached LUKS header with raw payload + result = self.vm.qmp('human-monitor-command', + command_line='qemu-io luks-2-payload-raw-format "write -P 41 0 64k"') + self.assert_qmp(result, 'return', '') + + result = self.vm.qmp('human-monitor-command', + command_line='qemu-io luks-2-payload-raw-format "read -P 41 0 64k"') + self.assert_qmp(result, 'return', '') + + # Detached LUKS header with qcow2 payload + result = self.vm.qmp('human-monitor-command', + command_line='qemu-io luks-3-payload-qcow2-format "write -P 42 0 64k"') + self.assert_qmp(result, 'return', '') + + result = self.vm.qmp('human-monitor-command', + command_line='qemu-io luks-3-payload-qcow2-format "read -P 42 0 64k"') + self.assert_qmp(result, 'return', '') + + self.vm.shutdown() + + +if __name__ == '__main__': + # Test image creation and I/O + iotests.main(supported_fmts=['luks'], + supported_protocols=['file']) diff --git a/tests/qemu-iotests/tests/luks-detached-header.out b/tests/qemu-iotests/tests/luks-detached-header.out new file mode 100644 index 0000000000..fbc63e62f8 --- /dev/null +++ b/tests/qemu-iotests/tests/luks-detached-header.out @@ -0,0 +1,5 @@ +.. +---------------------------------------------------------------------- +Ran 2 tests + +OK