From 0fd1c62de9c53958a8ef5d436273284e166254c9 Mon Sep 17 00:00:00 2001 From: Milan Broz Date: Sun, 2 Jan 2022 16:57:31 +0100 Subject: [PATCH] Add disable-luks2 reencryption configure option. The option --disable-luks2-reencryption completely disable LUKS2 reencryption code. When used, the libcryptsetup library can read metadata with reencryption code, but all reencryption API calls and cryptsetup reencrypt commands are disabled. Devices with online reencryption in progress cannot be activated. This option can cause some incompatibilities. Please use with care. --- configure.ac | 8 ++++++ lib/luks2/luks2_keyslot.c | 2 ++ lib/luks2/luks2_reencrypt.c | 36 ++++++++++++++++-------- lib/setup.c | 53 +++++++++++++++++++++++++---------- tests/api-test-2.c | 7 +++-- tests/luks2-reencryption-test | 2 ++ 6 files changed, 78 insertions(+), 30 deletions(-) diff --git a/configure.ac b/configure.ac index 0d2d9d02..5a2d825d 100644 --- a/configure.ac +++ b/configure.ac @@ -138,6 +138,14 @@ AC_DEFUN([NO_FIPS], [ fi ]) +dnl LUKS2 online reencryption +AC_ARG_ENABLE([luks2-reencryption], + AS_HELP_STRING([--disable-luks2-reencryption], [disable LUKS2 online reencryption extension]), + [], [enable_luks2_reencryption=yes]) +if test "x$enable_luks2_reencryption" = "xyes"; then + AC_DEFINE(USE_LUKS2_REENCRYPTION, 1, [Use LUKS2 online reencryption extension]) +fi + dnl ========================================================================== dnl pwquality library (cryptsetup CLI only) AC_ARG_ENABLE([pwquality], diff --git a/lib/luks2/luks2_keyslot.c b/lib/luks2/luks2_keyslot.c index d853fc8e..310314c1 100644 --- a/lib/luks2/luks2_keyslot.c +++ b/lib/luks2/luks2_keyslot.c @@ -27,7 +27,9 @@ extern const keyslot_handler reenc_keyslot; static const keyslot_handler *keyslot_handlers[LUKS2_KEYSLOTS_MAX] = { &luks2_keyslot, +#if USE_LUKS2_REENCRYPTION &reenc_keyslot, +#endif NULL }; diff --git a/lib/luks2/luks2_reencrypt.c b/lib/luks2/luks2_reencrypt.c index c99577cc..d7ead304 100644 --- a/lib/luks2/luks2_reencrypt.c +++ b/lib/luks2/luks2_reencrypt.c @@ -22,6 +22,7 @@ #include "luks2_internal.h" #include "utils_device_locking.h" +#if USE_LUKS2_REENCRYPTION static json_object *reencrypt_segment(struct luks2_hdr *hdr, unsigned new) { return LUKS2_get_segment_by_flag(hdr, new ? "backup-final" : "backup-previous"); @@ -85,7 +86,7 @@ static uint64_t reencrypt_get_data_offset_old(struct luks2_hdr *hdr) { return reencrypt_data_offset(hdr, 0); } - +#endif static int reencrypt_digest(struct luks2_hdr *hdr, unsigned new) { int segment = LUKS2_get_segment_id_by_flag(hdr, new ? "backup-final" : "backup-previous"); @@ -144,7 +145,7 @@ static const char *reencrypt_resilience_hash(struct luks2_hdr *hdr) return json_object_get_string(jobj_hash); } - +#if USE_LUKS2_REENCRYPTION static uint32_t reencrypt_alignment(struct luks2_hdr *hdr) { json_object *jobj_keyslot, *jobj_area, *jobj_type, *jobj_hash, *jobj_sector_size; @@ -560,7 +561,7 @@ static int reencrypt_make_post_segments(struct crypt_device *cd, return rh->jobj_segs_post ? 0 : -EINVAL; } - +#endif static uint64_t reencrypt_data_shift(struct luks2_hdr *hdr) { json_object *jobj_keyslot, *jobj_area, *jobj_data_shift; @@ -666,7 +667,7 @@ void LUKS2_reenc_context_free(struct crypt_device *cd, struct luks2_reenc_contex crypt_unlock_internal(cd, rh->reenc_lock); free(rh); } - +#if USE_LUKS2_REENCRYPTION static size_t reencrypt_get_alignment(struct crypt_device *cd, struct luks2_hdr *hdr) { @@ -2545,7 +2546,7 @@ static int reencrypt_load(struct crypt_device *cd, struct luks2_hdr *hdr, return 0; } - +#endif /* internal only */ int crypt_reencrypt_lock(struct crypt_device *cd, const char *uuid, struct crypt_lock_handle **reencrypt_lock) { @@ -2587,7 +2588,7 @@ void crypt_reencrypt_unlock(struct crypt_device *cd, struct crypt_lock_handle *r { crypt_unlock_internal(cd, reencrypt_lock); } - +#if USE_LUKS2_REENCRYPTION static int reencrypt_lock_and_verify(struct crypt_device *cd, struct luks2_hdr *hdr, struct crypt_lock_handle **reencrypt_lock) { @@ -2842,7 +2843,7 @@ static int reencrypt_recovery_by_passphrase(struct crypt_device *cd, crypt_reencrypt_unlock(cd, reencrypt_lock); return r; } - +#endif static int reencrypt_init_by_passphrase(struct crypt_device *cd, const char *name, const char *passphrase, @@ -2853,6 +2854,7 @@ static int reencrypt_init_by_passphrase(struct crypt_device *cd, const char *cipher_mode, const struct crypt_params_reencrypt *params) { +#if USE_LUKS2_REENCRYPTION int r; crypt_reencrypt_info ri; struct volume_key *vks = NULL; @@ -2908,6 +2910,10 @@ out: crypt_drop_keyring_key(cd, vks); crypt_free_volume_key(vks); return r < 0 ? r : LUKS2_find_keyslot(hdr, "reencrypt"); +#else + log_err(cd, _("This operation is not supported for this device type.")); + return -ENOTSUP; +#endif } int crypt_reencrypt_init_by_keyring(struct crypt_device *cd, @@ -2960,6 +2966,7 @@ int crypt_reencrypt_init_by_passphrase(struct crypt_device *cd, return reencrypt_init_by_passphrase(cd, name, passphrase, passphrase_size, keyslot_old, keyslot_new, cipher, cipher_mode, params); } +#if USE_LUKS2_REENCRYPTION static reenc_status_t reencrypt_step(struct crypt_device *cd, struct luks2_hdr *hdr, struct luks2_reenc_context *rh, @@ -3200,10 +3207,11 @@ static int reencrypt_teardown(struct crypt_device *cd, struct luks2_hdr *hdr, return r; } - +#endif int crypt_reencrypt(struct crypt_device *cd, int (*progress)(uint64_t size, uint64_t offset, void *usrptr)) { +#if USE_LUKS2_REENCRYPTION int r; crypt_reencrypt_info ri; struct luks2_hdr *hdr; @@ -3261,8 +3269,12 @@ int crypt_reencrypt(struct crypt_device *cd, r = reencrypt_teardown(cd, hdr, rh, rs, quit, progress); return r; +#else + log_err(cd, _("This operation is not supported for this device type.")); + return -ENOTSUP; +#endif } - +#if USE_LUKS2_REENCRYPTION static int reencrypt_recovery(struct crypt_device *cd, struct luks2_hdr *hdr, uint64_t device_size, @@ -3298,7 +3310,7 @@ err: return r; } - +#endif /* * use only for calculation of minimal data device size. * The real data offset is taken directly from segments! @@ -3313,7 +3325,7 @@ int LUKS2_reencrypt_data_offset(struct luks2_hdr *hdr, bool blockwise) return blockwise ? data_offset : data_offset << SECTOR_SHIFT; } - +#if USE_LUKS2_REENCRYPTION /* internal only */ int luks2_check_device_size(struct crypt_device *cd, struct luks2_hdr *hdr, uint64_t check_size, uint64_t *dev_size, bool activation, bool dynamic) { @@ -3403,7 +3415,7 @@ err: return r < 0 ? r : keyslot; } - +#endif crypt_reencrypt_info LUKS2_reencrypt_status(struct crypt_device *cd, struct crypt_params_reencrypt *params) { crypt_reencrypt_info ri; diff --git a/lib/setup.c b/lib/setup.c index 2e63ae9f..326c6441 100644 --- a/lib/setup.c +++ b/lib/setup.c @@ -3708,21 +3708,6 @@ out: return r; } -static int load_all_keys(struct crypt_device *cd, struct luks2_hdr *hdr, struct volume_key *vks) -{ - int r; - struct volume_key *vk = vks; - - while (vk) { - r = LUKS2_volume_key_load_in_keyring_by_digest(cd, hdr, vk, crypt_volume_key_get_id(vk)); - if (r < 0) - return r; - vk = vk->next; - } - - return 0; -} - /* See fixmes in _open_and_activate_luks2 */ int update_reencryption_flag(struct crypt_device *cd, int enable, bool commit); @@ -3764,6 +3749,22 @@ out: return r < 0 ? r : keyslot; } +#if USE_LUKS2_REENCRYPTION +static int load_all_keys(struct crypt_device *cd, struct luks2_hdr *hdr, struct volume_key *vks) +{ + int r; + struct volume_key *vk = vks; + + while (vk) { + r = LUKS2_volume_key_load_in_keyring_by_digest(cd, hdr, vk, crypt_volume_key_get_id(vk)); + if (r < 0) + return r; + vk = vk->next; + } + + return 0; +} + static int _open_all_keys(struct crypt_device *cd, struct luks2_hdr *hdr, int keyslot, @@ -3925,6 +3926,28 @@ static int _open_and_activate_luks2(struct crypt_device *cd, return r; } +#else +static int _open_and_activate_luks2(struct crypt_device *cd, + int keyslot, + const char *name, + const char *passphrase, + size_t passphrase_size, + uint32_t flags) +{ + crypt_reencrypt_info ri; + + ri = LUKS2_reenc_status(&cd->u.luks2.hdr); + if (ri == CRYPT_REENCRYPT_INVALID) + return -EINVAL; + + if (ri > CRYPT_REENCRYPT_NONE) { + log_err(cd, _("This operation is not supported for this device type.")); + return -ENOTSUP; + } + + return _open_and_activate(cd, keyslot, name, passphrase, passphrase_size, flags); +} +#endif static int _activate_by_passphrase(struct crypt_device *cd, const char *name, diff --git a/tests/api-test-2.c b/tests/api-test-2.c index b3cce668..baf3c3bc 100644 --- a/tests/api-test-2.c +++ b/tests/api-test-2.c @@ -3622,7 +3622,7 @@ static void Luks2Flags(void) CRYPT_FREE(cd); } - +#if KERNEL_KEYRING && USE_LUKS2_REENCRYPTION static int test_progress(uint64_t size, uint64_t offset, void *usrptr) { while (--test_progress_steps) @@ -3633,7 +3633,6 @@ static int test_progress(uint64_t size, uint64_t offset, void *usrptr) static void Luks2Reencryption(void) { /* reencryption currently depends on kernel keyring support */ -#if KERNEL_KEYRING /* NOTES: * - reencryption requires luks2 parameters. can we avoid it? */ @@ -4302,8 +4301,8 @@ static void Luks2Reencryption(void) CRYPT_FREE(cd); _cleanup_dmdevices(); -#endif } +#endif static void Luks2Repair(void) { @@ -4419,7 +4418,9 @@ int main(int argc, char *argv[]) RUN_(Luks2Integrity, "LUKS2 with data integrity"); RUN_(Luks2Refresh, "Active device table refresh"); RUN_(Luks2Flags, "LUKS2 persistent flags"); +#if KERNEL_KEYRING && USE_LUKS2_REENCRYPTION RUN_(Luks2Reencryption, "LUKS2 reencryption"); +#endif RUN_(Luks2Repair, "LUKS2 repair"); // test disables metadata locking. Run always last! _cleanup(); diff --git a/tests/luks2-reencryption-test b/tests/luks2-reencryption-test index 688c396f..9f23d371 100755 --- a/tests/luks2-reencryption-test +++ b/tests/luks2-reencryption-test @@ -114,6 +114,7 @@ function fail() function skip() { [ -n "$1" ] && echo "$1" + remove_mapping exit 77 } @@ -745,6 +746,7 @@ prepare sector_size=512 physblk_exp=3 dev_size_mb=32 echo $PWD1 | $CRYPTSETUP -q luksFormat --type luks2 -s 128 -c aes-cbc-essiv:sha256 --offset 8192 $FAST_PBKDF_ARGON $DEV || fail wipe $PWD1 check_hash $PWD1 $HASH1 +echo $PWD1 | $CRYPTSETUP reencrypt $DEV -q $FAST_PBKDF_ARGON 2>&1 | tail -1 | grep -q "not supported" && skip " No reenryption support, test skipped." echo $PWD1 | $CRYPTSETUP reencrypt $DEV -q $FAST_PBKDF_ARGON || fail check_hash $PWD1 $HASH1 echo $PWD1 | $CRYPTSETUP reencrypt $DEV -q -s 256 -c twofish-cbc-essiv:sha256 --resilience journal $FAST_PBKDF_ARGON || fail