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.
This commit is contained in:
Milan Broz
2022-01-02 16:57:31 +01:00
parent 9cc749d9fa
commit 0fd1c62de9
6 changed files with 78 additions and 30 deletions

View File

@@ -138,6 +138,14 @@ AC_DEFUN([NO_FIPS], [
fi 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 ==========================================================================
dnl pwquality library (cryptsetup CLI only) dnl pwquality library (cryptsetup CLI only)
AC_ARG_ENABLE([pwquality], AC_ARG_ENABLE([pwquality],

View File

@@ -27,7 +27,9 @@ extern const keyslot_handler reenc_keyslot;
static const keyslot_handler *keyslot_handlers[LUKS2_KEYSLOTS_MAX] = { static const keyslot_handler *keyslot_handlers[LUKS2_KEYSLOTS_MAX] = {
&luks2_keyslot, &luks2_keyslot,
#if USE_LUKS2_REENCRYPTION
&reenc_keyslot, &reenc_keyslot,
#endif
NULL NULL
}; };

View File

@@ -22,6 +22,7 @@
#include "luks2_internal.h" #include "luks2_internal.h"
#include "utils_device_locking.h" #include "utils_device_locking.h"
#if USE_LUKS2_REENCRYPTION
static json_object *reencrypt_segment(struct luks2_hdr *hdr, unsigned new) static json_object *reencrypt_segment(struct luks2_hdr *hdr, unsigned new)
{ {
return LUKS2_get_segment_by_flag(hdr, new ? "backup-final" : "backup-previous"); 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); return reencrypt_data_offset(hdr, 0);
} }
#endif
static int reencrypt_digest(struct luks2_hdr *hdr, unsigned new) static int reencrypt_digest(struct luks2_hdr *hdr, unsigned new)
{ {
int segment = LUKS2_get_segment_id_by_flag(hdr, new ? "backup-final" : "backup-previous"); 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); return json_object_get_string(jobj_hash);
} }
#if USE_LUKS2_REENCRYPTION
static uint32_t reencrypt_alignment(struct luks2_hdr *hdr) static uint32_t reencrypt_alignment(struct luks2_hdr *hdr)
{ {
json_object *jobj_keyslot, *jobj_area, *jobj_type, *jobj_hash, *jobj_sector_size; 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; return rh->jobj_segs_post ? 0 : -EINVAL;
} }
#endif
static uint64_t reencrypt_data_shift(struct luks2_hdr *hdr) static uint64_t reencrypt_data_shift(struct luks2_hdr *hdr)
{ {
json_object *jobj_keyslot, *jobj_area, *jobj_data_shift; 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); crypt_unlock_internal(cd, rh->reenc_lock);
free(rh); free(rh);
} }
#if USE_LUKS2_REENCRYPTION
static size_t reencrypt_get_alignment(struct crypt_device *cd, static size_t reencrypt_get_alignment(struct crypt_device *cd,
struct luks2_hdr *hdr) struct luks2_hdr *hdr)
{ {
@@ -2545,7 +2546,7 @@ static int reencrypt_load(struct crypt_device *cd, struct luks2_hdr *hdr,
return 0; return 0;
} }
#endif
/* internal only */ /* internal only */
int crypt_reencrypt_lock(struct crypt_device *cd, const char *uuid, struct crypt_lock_handle **reencrypt_lock) 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); crypt_unlock_internal(cd, reencrypt_lock);
} }
#if USE_LUKS2_REENCRYPTION
static int reencrypt_lock_and_verify(struct crypt_device *cd, struct luks2_hdr *hdr, static int reencrypt_lock_and_verify(struct crypt_device *cd, struct luks2_hdr *hdr,
struct crypt_lock_handle **reencrypt_lock) 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); crypt_reencrypt_unlock(cd, reencrypt_lock);
return r; return r;
} }
#endif
static int reencrypt_init_by_passphrase(struct crypt_device *cd, static int reencrypt_init_by_passphrase(struct crypt_device *cd,
const char *name, const char *name,
const char *passphrase, const char *passphrase,
@@ -2853,6 +2854,7 @@ static int reencrypt_init_by_passphrase(struct crypt_device *cd,
const char *cipher_mode, const char *cipher_mode,
const struct crypt_params_reencrypt *params) const struct crypt_params_reencrypt *params)
{ {
#if USE_LUKS2_REENCRYPTION
int r; int r;
crypt_reencrypt_info ri; crypt_reencrypt_info ri;
struct volume_key *vks = NULL; struct volume_key *vks = NULL;
@@ -2908,6 +2910,10 @@ out:
crypt_drop_keyring_key(cd, vks); crypt_drop_keyring_key(cd, vks);
crypt_free_volume_key(vks); crypt_free_volume_key(vks);
return r < 0 ? r : LUKS2_find_keyslot(hdr, "reencrypt"); 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, 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); 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, static reenc_status_t reencrypt_step(struct crypt_device *cd,
struct luks2_hdr *hdr, struct luks2_hdr *hdr,
struct luks2_reenc_context *rh, struct luks2_reenc_context *rh,
@@ -3200,10 +3207,11 @@ static int reencrypt_teardown(struct crypt_device *cd, struct luks2_hdr *hdr,
return r; return r;
} }
#endif
int crypt_reencrypt(struct crypt_device *cd, int crypt_reencrypt(struct crypt_device *cd,
int (*progress)(uint64_t size, uint64_t offset, void *usrptr)) int (*progress)(uint64_t size, uint64_t offset, void *usrptr))
{ {
#if USE_LUKS2_REENCRYPTION
int r; int r;
crypt_reencrypt_info ri; crypt_reencrypt_info ri;
struct luks2_hdr *hdr; struct luks2_hdr *hdr;
@@ -3261,8 +3269,12 @@ int crypt_reencrypt(struct crypt_device *cd,
r = reencrypt_teardown(cd, hdr, rh, rs, quit, progress); r = reencrypt_teardown(cd, hdr, rh, rs, quit, progress);
return r; 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, static int reencrypt_recovery(struct crypt_device *cd,
struct luks2_hdr *hdr, struct luks2_hdr *hdr,
uint64_t device_size, uint64_t device_size,
@@ -3298,7 +3310,7 @@ err:
return r; return r;
} }
#endif
/* /*
* use only for calculation of minimal data device size. * use only for calculation of minimal data device size.
* The real data offset is taken directly from segments! * 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; return blockwise ? data_offset : data_offset << SECTOR_SHIFT;
} }
#if USE_LUKS2_REENCRYPTION
/* internal only */ /* 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) 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; return r < 0 ? r : keyslot;
} }
#endif
crypt_reencrypt_info LUKS2_reencrypt_status(struct crypt_device *cd, struct crypt_params_reencrypt *params) crypt_reencrypt_info LUKS2_reencrypt_status(struct crypt_device *cd, struct crypt_params_reencrypt *params)
{ {
crypt_reencrypt_info ri; crypt_reencrypt_info ri;

View File

@@ -3708,21 +3708,6 @@ out:
return r; 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 */ /* See fixmes in _open_and_activate_luks2 */
int update_reencryption_flag(struct crypt_device *cd, int enable, bool commit); int update_reencryption_flag(struct crypt_device *cd, int enable, bool commit);
@@ -3764,6 +3749,22 @@ out:
return r < 0 ? r : keyslot; 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, static int _open_all_keys(struct crypt_device *cd,
struct luks2_hdr *hdr, struct luks2_hdr *hdr,
int keyslot, int keyslot,
@@ -3925,6 +3926,28 @@ static int _open_and_activate_luks2(struct crypt_device *cd,
return r; 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, static int _activate_by_passphrase(struct crypt_device *cd,
const char *name, const char *name,

View File

@@ -3622,7 +3622,7 @@ static void Luks2Flags(void)
CRYPT_FREE(cd); CRYPT_FREE(cd);
} }
#if KERNEL_KEYRING && USE_LUKS2_REENCRYPTION
static int test_progress(uint64_t size, uint64_t offset, void *usrptr) static int test_progress(uint64_t size, uint64_t offset, void *usrptr)
{ {
while (--test_progress_steps) while (--test_progress_steps)
@@ -3633,7 +3633,6 @@ static int test_progress(uint64_t size, uint64_t offset, void *usrptr)
static void Luks2Reencryption(void) static void Luks2Reencryption(void)
{ {
/* reencryption currently depends on kernel keyring support */ /* reencryption currently depends on kernel keyring support */
#if KERNEL_KEYRING
/* NOTES: /* NOTES:
* - reencryption requires luks2 parameters. can we avoid it? * - reencryption requires luks2 parameters. can we avoid it?
*/ */
@@ -4302,8 +4301,8 @@ static void Luks2Reencryption(void)
CRYPT_FREE(cd); CRYPT_FREE(cd);
_cleanup_dmdevices(); _cleanup_dmdevices();
#endif
} }
#endif
static void Luks2Repair(void) static void Luks2Repair(void)
{ {
@@ -4419,7 +4418,9 @@ int main(int argc, char *argv[])
RUN_(Luks2Integrity, "LUKS2 with data integrity"); RUN_(Luks2Integrity, "LUKS2 with data integrity");
RUN_(Luks2Refresh, "Active device table refresh"); RUN_(Luks2Refresh, "Active device table refresh");
RUN_(Luks2Flags, "LUKS2 persistent flags"); RUN_(Luks2Flags, "LUKS2 persistent flags");
#if KERNEL_KEYRING && USE_LUKS2_REENCRYPTION
RUN_(Luks2Reencryption, "LUKS2 reencryption"); RUN_(Luks2Reencryption, "LUKS2 reencryption");
#endif
RUN_(Luks2Repair, "LUKS2 repair"); // test disables metadata locking. Run always last! RUN_(Luks2Repair, "LUKS2 repair"); // test disables metadata locking. Run always last!
_cleanup(); _cleanup();

View File

@@ -114,6 +114,7 @@ function fail()
function skip() function skip()
{ {
[ -n "$1" ] && echo "$1" [ -n "$1" ] && echo "$1"
remove_mapping
exit 77 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 echo $PWD1 | $CRYPTSETUP -q luksFormat --type luks2 -s 128 -c aes-cbc-essiv:sha256 --offset 8192 $FAST_PBKDF_ARGON $DEV || fail
wipe $PWD1 wipe $PWD1
check_hash $PWD1 $HASH1 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 echo $PWD1 | $CRYPTSETUP reencrypt $DEV -q $FAST_PBKDF_ARGON || fail
check_hash $PWD1 $HASH1 check_hash $PWD1 $HASH1
echo $PWD1 | $CRYPTSETUP reencrypt $DEV -q -s 256 -c twofish-cbc-essiv:sha256 --resilience journal $FAST_PBKDF_ARGON || fail echo $PWD1 | $CRYPTSETUP reencrypt $DEV -q -s 256 -c twofish-cbc-essiv:sha256 --resilience journal $FAST_PBKDF_ARGON || fail