diff --git a/SOURCES/cryptsetup-2.3.7-Add-CRYPT_REENCRYPT_REPAIR_NEEDED-flag.patch b/SOURCES/cryptsetup-2.3.7-Add-CRYPT_REENCRYPT_REPAIR_NEEDED-flag.patch new file mode 100644 index 0000000..88192e8 --- /dev/null +++ b/SOURCES/cryptsetup-2.3.7-Add-CRYPT_REENCRYPT_REPAIR_NEEDED-flag.patch @@ -0,0 +1,206 @@ +diff -rupN cryptsetup-2.3.3.old/lib/libcryptsetup.h cryptsetup-2.3.3/lib/libcryptsetup.h +--- cryptsetup-2.3.3.old/lib/libcryptsetup.h 2022-01-18 09:15:34.523672069 +0100 ++++ cryptsetup-2.3.3/lib/libcryptsetup.h 2022-01-18 09:16:43.251047191 +0100 +@@ -2194,6 +2194,8 @@ int crypt_activate_by_token(struct crypt + #define CRYPT_REENCRYPT_RESUME_ONLY (1 << 2) + /** Run reencryption recovery only. (in) */ + #define CRYPT_REENCRYPT_RECOVERY (1 << 3) ++/** Reencryption requires metadata protection. (in/out) */ ++#define CRYPT_REENCRYPT_REPAIR_NEEDED (1 << 4) + + /** + * Reencryption direction +diff -rupN cryptsetup-2.3.3.old/lib/luks2/luks2.h cryptsetup-2.3.3/lib/luks2/luks2.h +--- cryptsetup-2.3.3.old/lib/luks2/luks2.h 2022-01-18 09:15:34.520672053 +0100 ++++ cryptsetup-2.3.3/lib/luks2/luks2.h 2022-01-18 09:16:43.252047196 +0100 +@@ -561,6 +561,8 @@ int LUKS2_config_set_flags(struct crypt_ + int LUKS2_config_get_requirements(struct crypt_device *cd, struct luks2_hdr *hdr, uint32_t *reqs); + int LUKS2_config_set_requirements(struct crypt_device *cd, struct luks2_hdr *hdr, uint32_t reqs, bool commit); + ++int LUKS2_config_get_reencrypt_version(struct luks2_hdr *hdr, uint32_t *version); ++ + int LUKS2_unmet_requirements(struct crypt_device *cd, struct luks2_hdr *hdr, uint32_t reqs_mask, int quiet); + + int LUKS2_key_description_by_segment(struct crypt_device *cd, +diff -rupN cryptsetup-2.3.3.old/lib/luks2/luks2_json_metadata.c cryptsetup-2.3.3/lib/luks2/luks2_json_metadata.c +--- cryptsetup-2.3.3.old/lib/luks2/luks2_json_metadata.c 2022-01-18 09:15:34.521672058 +0100 ++++ cryptsetup-2.3.3/lib/luks2/luks2_json_metadata.c 2022-01-18 09:16:43.253047201 +0100 +@@ -1469,6 +1469,49 @@ static const struct requirement_flag *ge + return &unknown_requirement_flag; + } + ++int LUKS2_config_get_reencrypt_version(struct luks2_hdr *hdr, uint32_t *version) ++{ ++ json_object *jobj_config, *jobj_requirements, *jobj_mandatory, *jobj; ++ int i, len; ++ const struct requirement_flag *req; ++ ++ assert(hdr && version); ++ if (!hdr || !version) ++ return -EINVAL; ++ ++ if (!json_object_object_get_ex(hdr->jobj, "config", &jobj_config)) ++ return -EINVAL; ++ ++ if (!json_object_object_get_ex(jobj_config, "requirements", &jobj_requirements)) ++ return -ENOENT; ++ ++ if (!json_object_object_get_ex(jobj_requirements, "mandatory", &jobj_mandatory)) ++ return -ENOENT; ++ ++ len = (int) json_object_array_length(jobj_mandatory); ++ if (len <= 0) ++ return -ENOENT; ++ ++ for (i = 0; i < len; i++) { ++ jobj = json_object_array_get_idx(jobj_mandatory, i); ++ ++ /* search for requirements prefixed with "online-reencrypt" */ ++ if (strncmp(json_object_get_string(jobj), "online-reencrypt", 16)) ++ continue; ++ ++ /* check current library is aware of the requirement */ ++ req = get_requirement_by_name(json_object_get_string(jobj)); ++ if (req->flag == (uint32_t)CRYPT_REQUIREMENT_UNKNOWN) ++ continue; ++ ++ *version = req->version; ++ ++ return 0; ++ } ++ ++ return -ENOENT; ++} ++ + static const struct requirement_flag *stored_requirement_name_by_id(struct crypt_device *cd, struct luks2_hdr *hdr, uint32_t req_id) + { + json_object *jobj_config, *jobj_requirements, *jobj_mandatory, *jobj; +diff -rupN cryptsetup-2.3.3.old/lib/luks2/luks2_reencrypt.c cryptsetup-2.3.3/lib/luks2/luks2_reencrypt.c +--- cryptsetup-2.3.3.old/lib/luks2/luks2_reencrypt.c 2022-01-18 09:15:34.520672053 +0100 ++++ cryptsetup-2.3.3/lib/luks2/luks2_reencrypt.c 2022-01-18 09:25:26.870913236 +0100 +@@ -2888,6 +2888,85 @@ static int reencrypt_recovery_by_passphr + return r; + } + ++static int reencrypt_repair_by_passphrase( ++ struct crypt_device *cd, ++ struct luks2_hdr *hdr, ++ int keyslot_old, ++ int keyslot_new, ++ const char *passphrase, ++ size_t passphrase_size) ++{ ++ int r; ++ struct crypt_lock_handle *reencrypt_lock; ++ struct luks2_reenc_context *rh; ++ crypt_reencrypt_info ri; ++ struct volume_key *vks = NULL; ++ ++ log_dbg(cd, "Loading LUKS2 reencryption context for metadata repair."); ++ ++ rh = crypt_get_reenc_context(cd); ++ if (rh) { ++ LUKS2_reenc_context_free(cd, rh); ++ crypt_set_reenc_context(cd, NULL); ++ rh = NULL; ++ } ++ ++ ri = LUKS2_reenc_status(hdr); ++ if (ri == CRYPT_REENCRYPT_INVALID) ++ return -EINVAL; ++ ++ if (ri < CRYPT_REENCRYPT_CLEAN) { ++ log_err(cd, _("Device is not in reencryption.")); ++ return -EINVAL; ++ } ++ ++ r = crypt_reencrypt_lock(cd, &reencrypt_lock); ++ if (r < 0) { ++ if (r == -EBUSY) ++ log_err(cd, _("Reencryption process is already running.")); ++ else ++ log_err(cd, _("Failed to acquire reencryption lock.")); ++ return r; ++ } ++ ++ /* With reencryption lock held, reload device context and verify metadata state */ ++ r = crypt_load(cd, CRYPT_LUKS2, NULL); ++ if (r) ++ goto out; ++ ++ ri = LUKS2_reenc_status(hdr); ++ if (ri == CRYPT_REENCRYPT_INVALID) { ++ r = -EINVAL; ++ goto out; ++ } ++ if (ri == CRYPT_REENCRYPT_NONE) { ++ r = 0; ++ goto out; ++ } ++ ++ r = LUKS2_keyslot_open_all_segments(cd, keyslot_old, keyslot_new, passphrase, passphrase_size, &vks); ++ if (r < 0) ++ goto out; ++ ++ r = LUKS2_keyslot_reencrypt_digest_create(cd, hdr, vks); ++ crypt_free_volume_key(vks); ++ vks = NULL; ++ if (r < 0) ++ goto out; ++ ++ /* removes online-reencrypt flag v1 */ ++ if ((r = reencrypt_update_flag(cd, 0, false))) ++ goto out; ++ ++ /* adds online-reencrypt flag v2 and commits metadata */ ++ r = reencrypt_update_flag(cd, 1, true); ++out: ++ crypt_reencrypt_unlock(cd, reencrypt_lock); ++ crypt_free_volume_key(vks); ++ return r; ++ ++} ++ + static int reencrypt_init_by_passphrase(struct crypt_device *cd, + const char *name, + const char *passphrase, +@@ -2904,6 +2983,10 @@ static int reencrypt_init_by_passphrase( + uint32_t flags = params ? params->flags : 0; + struct luks2_hdr *hdr = crypt_get_hdr(cd, CRYPT_LUKS2); + ++ /* short-circuit in reencryption metadata update and finish immediately. */ ++ if (flags & CRYPT_REENCRYPT_REPAIR_NEEDED) ++ return reencrypt_repair_by_passphrase(cd, hdr, keyslot_old, keyslot_new, passphrase, passphrase_size); ++ + /* short-circuit in recovery and finish immediately. */ + if (flags & CRYPT_REENCRYPT_RECOVERY) + return reencrypt_recovery_by_passphrase(cd, hdr, keyslot_old, keyslot_new, passphrase, passphrase_size); +@@ -3459,12 +3542,28 @@ err: + crypt_reencrypt_info LUKS2_reencrypt_status(struct crypt_device *cd, struct crypt_params_reencrypt *params) + { + crypt_reencrypt_info ri; ++ int digest; ++ uint32_t version; + struct luks2_hdr *hdr = crypt_get_hdr(cd, CRYPT_LUKS2); + + ri = LUKS2_reenc_status(hdr); + if (ri == CRYPT_REENCRYPT_NONE || ri == CRYPT_REENCRYPT_INVALID || !params) + return ri; + ++ digest = LUKS2_digest_by_keyslot(hdr, LUKS2_find_keyslot(hdr, "reencrypt")); ++ if (digest < 0 && digest != -ENOENT) ++ return CRYPT_REENCRYPT_INVALID; ++ ++ /* ++ * In case there's an old "online-reencrypt" requirement or reencryption ++ * keyslot digest is missing inform caller reencryption metadata requires repair. ++ */ ++ if (!LUKS2_config_get_reencrypt_version(hdr, &version) && ++ (version < 2 || digest == -ENOENT)) { ++ params->flags |= CRYPT_REENCRYPT_REPAIR_NEEDED; ++ return ri; ++ } ++ + params->mode = reencrypt_mode(hdr); + params->direction = reencrypt_direction(hdr); + params->resilience = reencrypt_resilience_type(hdr); diff --git a/SOURCES/cryptsetup-2.3.7-Add-reencryption-mangle-test.patch b/SOURCES/cryptsetup-2.3.7-Add-reencryption-mangle-test.patch new file mode 100644 index 0000000..b023602 --- /dev/null +++ b/SOURCES/cryptsetup-2.3.7-Add-reencryption-mangle-test.patch @@ -0,0 +1,502 @@ +diff -rupN cryptsetup-2.3.3.old/tests/luks2-reencryption-mangle-test cryptsetup-2.3.3/tests/luks2-reencryption-mangle-test +--- cryptsetup-2.3.3.old/tests/luks2-reencryption-mangle-test 1970-01-01 01:00:00.000000000 +0100 ++++ cryptsetup-2.3.3/tests/luks2-reencryption-mangle-test 2022-01-13 17:01:26.605785131 +0100 +@@ -0,0 +1,470 @@ ++#!/bin/bash ++ ++PS4='$LINENO:' ++[ -z "$CRYPTSETUP_PATH" ] && CRYPTSETUP_PATH=".." ++CRYPTSETUP=$CRYPTSETUP_PATH/cryptsetup ++CRYPTSETUP_RAW=$CRYPTSETUP ++ ++CRYPTSETUP_VALGRIND=../.libs/cryptsetup ++CRYPTSETUP_LIB_VALGRIND=../.libs ++IMG=reenc-mangle-data ++IMG_HDR=$IMG.hdr ++IMG_JSON=$IMG.json ++KEY1=key1 ++DEV_NAME=reenc3492834 ++ ++FAST_PBKDF2="--pbkdf pbkdf2 --pbkdf-force-iterations 1000" ++CS_PWPARAMS="--disable-keyring --key-file $KEY1" ++CS_PARAMS="-q --disable-locks $CS_PWPARAMS" ++JSON_MSIZE=16384 ++ ++function remove_mapping() ++{ ++ [ -b /dev/mapper/$DEV_NAME ] && dmsetup remove --retry $DEV_NAME ++ rm -f $IMG $IMG_HDR $IMG_JSON $KEY1 >/dev/null 2>&1 ++} ++ ++function fail() ++{ ++ local frame=0 ++ [ -n "$1" ] && echo "$1" ++ echo "FAILED backtrace:" ++ while caller $frame; do ((frame++)); done ++ remove_mapping ++ exit 2 ++} ++ ++function skip() ++{ ++ [ -n "$1" ] && echo "$1" ++ remove_mapping ++ exit 77 ++} ++ ++function bin_check() ++{ ++ which $1 >/dev/null 2>&1 || skip "WARNING: test require $1 binary, test skipped." ++} ++ ++function img_json_save() ++{ ++ # FIXME: why --json-file cannot be used? ++ #$CRYPTSETUP luksDump --dump-json-metadata $IMG | jq -c -M | tr -d '\n' >$IMG_JSON ++ local LUKS2_JSON_SIZE=$(($JSON_MSIZE - 4096)) ++ _dd if=$IMG count=$LUKS2_JSON_SIZE skip=4096 | jq -c -M | tr -d '\n' >$IMG_JSON ++} ++ ++function img_json_dump() ++{ ++ img_json_save ++ jq . $IMG_JSON ++} ++ ++function img_hash_save() ++{ ++ IMG_HASH=$(sha256sum $IMG | cut -d' ' -f 1) ++} ++ ++function img_hash_unchanged() ++{ ++ local IMG_HASH2=$(sha256sum $IMG | cut -d' ' -f 1) ++ [ "$IMG_HASH" != "$IMG_HASH2" ] && fail "Image changed!" ++} ++ ++function img_prepare_raw() # $1 options ++{ ++ remove_mapping ++ ++ if [ ! -e $KEY1 ]; then ++ dd if=/dev/urandom of=$KEY1 count=1 bs=32 >/dev/null 2>&1 ++ fi ++ ++ truncate -s 32M $IMG || fail ++ $CRYPTSETUP luksFormat $FAST_PBKDF2 $CS_PARAMS --luks2-metadata-size $JSON_MSIZE $IMG $1 || fail ++} ++ ++function img_prepare() # $1 options ++{ ++ img_prepare_raw ++ # FIXME: resilience is not saved here (always none)? ++ $CRYPTSETUP reencrypt $IMG $CS_PARAMS -q --init-only --resilience none $1 >/dev/null 2>&1 ++ [ $? -ne 0 ] && skip "Reencryption unsupported, test skipped." ++ img_json_save ++ img_hash_save ++} ++ ++function _dd() ++{ ++ dd $@ status=none conv=notrunc bs=1 ++} ++ ++# header mangle functions ++function img_update_json() ++{ ++ local LUKS2_BIN1_OFFSET=448 ++ local LUKS2_BIN2_OFFSET=$((LUKS2_BIN1_OFFSET + $JSON_MSIZE)) ++ local LUKS2_JSON_SIZE=$(($JSON_MSIZE - 4096)) ++ ++ # if present jq script, mangle JSON ++ if [ -n "$1" ]; then ++ local JSON=$(cat $IMG_JSON) ++ echo $JSON | jq -M -c "$1" >$IMG_JSON || fail ++ local JSON=$(cat $IMG_JSON) ++ echo $JSON | tr -d '\n' >$IMG_JSON || fail ++ fi ++ ++ # wipe JSON areas ++ _dd if=/dev/zero of=$IMG count=$LUKS2_JSON_SIZE seek=4096 ++ _dd if=/dev/zero of=$IMG count=$LUKS2_JSON_SIZE seek=$(($JSON_MSIZE + 4096)) ++ ++ # write JSON data ++ _dd if=$IMG_JSON of=$IMG count=$LUKS2_JSON_SIZE seek=4096 ++ _dd if=$IMG_JSON of=$IMG count=$LUKS2_JSON_SIZE seek=$(($JSON_MSIZE + 4096)) ++ ++ # erase sha256 checksums ++ _dd if=/dev/zero of=$IMG count=64 seek=$LUKS2_BIN1_OFFSET ++ _dd if=/dev/zero of=$IMG count=64 seek=$LUKS2_BIN2_OFFSET ++ ++ # calculate sha256 and write chexksums ++ local SUM1_HEX=$(_dd if=$IMG count=$JSON_MSIZE | sha256sum | cut -d ' ' -f 1) ++ echo $SUM1_HEX | xxd -r -p | _dd of=$IMG seek=$LUKS2_BIN1_OFFSET count=64 || fail ++ ++ local SUM2_HEX=$(_dd if=$IMG skip=$JSON_MSIZE count=$JSON_MSIZE | sha256sum | cut -d ' ' -f 1) ++ echo $SUM2_HEX | xxd -r -p | _dd of=$IMG seek=$LUKS2_BIN2_OFFSET count=64 || fail ++ ++ img_hash_save ++} ++ ++function img_check_ok() ++{ ++ if [ $(id -u) == 0 ]; then ++ $CRYPTSETUP open $CS_PWPARAMS $IMG $DEV_NAME || fail ++ $CRYPTSETUP close $DEV_NAME || fail ++ fi ++ ++ $CRYPTSETUP repair $IMG $CS_PARAMS || fail ++} ++ ++function img_check_fail() ++{ ++ if [ $(id -u) == 0 ]; then ++ $CRYPTSETUP open $CS_PWPARAMS $IMG $DEV_NAME 2>/dev/null && fail ++ fi ++ ++ $CRYPTSETUP repair $IMG $CS_PARAMS 2>/dev/null && fail ++ img_hash_unchanged ++} ++ ++function img_run_reenc_ok() ++{ ++local EXPECT_TIMEOUT=5 ++[ -n "$VALG" ] && EXPECT_TIMEOUT=60 ++# For now, we cannot run reencryption in batch mode for non-block device. Just fake the terminal here. ++expect_run - >/dev/null </dev/null 2>&1 && fail ++ ++remove_mapping ++exit 0 +diff -rupN cryptsetup-2.3.3.old/tests/Makefile.am cryptsetup-2.3.3/tests/Makefile.am +--- cryptsetup-2.3.3.old/tests/Makefile.am 2022-01-13 17:01:05.450651531 +0100 ++++ cryptsetup-2.3.3/tests/Makefile.am 2022-01-13 17:03:47.726676343 +0100 +@@ -25,7 +25,7 @@ TESTS += verity-compat-test + endif + + if REENCRYPT +-TESTS += reencryption-compat-test reencryption-compat-test2 luks2-reencryption-test ++TESTS += reencryption-compat-test reencryption-compat-test2 luks2-reencryption-test luks2-reencryption-mangle-test + endif + + if INTEGRITYSETUP +@@ -57,6 +57,7 @@ EXTRA_DIST = compatimage.img.xz compatv1 + reencryption-compat-test \ + reencryption-compat-test2 \ + luks2-reencryption-test \ ++ luks2-reencryption-mangle-test \ + tcrypt-compat-test \ + luks1-compat-test \ + luks2-validation-test generators \ +@@ -119,6 +120,7 @@ valgrind-check: api-test api-test-2 diff + @INFOSTRING="api-test-000" ./valg-api.sh ./api-test + @INFOSTRING="api-test-002" ./valg-api.sh ./api-test-2 + @VALG=1 ./luks2-reencryption-test ++ @VALG=1 ./luks2-reencryption-mangle-test + @VALG=1 ./compat-test + + .PHONY: valgrind-check diff --git a/SOURCES/cryptsetup-2.3.7-Add-segments-validation-for-reencryption.patch b/SOURCES/cryptsetup-2.3.7-Add-segments-validation-for-reencryption.patch new file mode 100644 index 0000000..9b6cd63 --- /dev/null +++ b/SOURCES/cryptsetup-2.3.7-Add-segments-validation-for-reencryption.patch @@ -0,0 +1,113 @@ +diff -rupN cryptsetup-2.3.3.old/lib/luks2/luks2_internal.h cryptsetup-2.3.3/lib/luks2/luks2_internal.h +--- cryptsetup-2.3.3.old/lib/luks2/luks2_internal.h 2022-01-17 16:14:07.530136302 +0100 ++++ cryptsetup-2.3.3/lib/luks2/luks2_internal.h 2022-01-17 16:15:29.134422136 +0100 +@@ -207,5 +207,6 @@ static inline const char *crypt_reencryp + } + + bool json_segment_contains_flag(json_object *jobj_segment, const char *flag_str, size_t len); ++bool json_segment_cmp(json_object *jobj_segment_1, json_object *jobj_segment_2); + + #endif +diff -rupN cryptsetup-2.3.3.old/lib/luks2/luks2_json_metadata.c cryptsetup-2.3.3/lib/luks2/luks2_json_metadata.c +--- cryptsetup-2.3.3.old/lib/luks2/luks2_json_metadata.c 2022-01-17 16:14:07.530136302 +0100 ++++ cryptsetup-2.3.3/lib/luks2/luks2_json_metadata.c 2022-01-17 16:16:34.382650680 +0100 +@@ -606,6 +606,63 @@ static int reqs_reencrypt_online(uint32_ + return reqs & CRYPT_REQUIREMENT_ONLINE_REENCRYPT; + } + ++/* ++ * Config section requirements object must be valid. ++ * Also general segments section must be validated first. ++ */ ++static int validate_reencrypt_segments(struct crypt_device *cd, json_object *hdr_jobj, json_object *jobj_segments, int first_backup, int segments_count) ++{ ++ json_object *jobj, *jobj_backup_previous = NULL, *jobj_backup_final = NULL; ++ uint32_t reqs; ++ int i, r; ++ struct luks2_hdr dummy = { ++ .jobj = hdr_jobj ++ }; ++ ++ r = LUKS2_config_get_requirements(cd, &dummy, &reqs); ++ if (r) ++ return 1; ++ ++ if (reqs_reencrypt_online(reqs)) { ++ for (i = first_backup; i < segments_count; i++) { ++ jobj = json_segments_get_segment(jobj_segments, i); ++ if (!jobj) ++ return 1; ++ if (json_segment_contains_flag(jobj, "backup-final", 0)) ++ jobj_backup_final = jobj; ++ else if (json_segment_contains_flag(jobj, "backup-previous", 0)) ++ jobj_backup_previous = jobj; ++ } ++ ++ if (!jobj_backup_final || !jobj_backup_previous) { ++ log_dbg(cd, "Backup segment is missing."); ++ return 1; ++ } ++ ++ for (i = 0; i < first_backup; i++) { ++ jobj = json_segments_get_segment(jobj_segments, i); ++ if (!jobj) ++ return 1; ++ ++ if (json_segment_contains_flag(jobj, "in-reencryption", 0)) { ++ if (!json_segment_cmp(jobj, jobj_backup_final)) { ++ log_dbg(cd, "Segment in reencryption does not match backup final segment."); ++ return 1; ++ } ++ continue; ++ } ++ ++ if (!json_segment_cmp(jobj, jobj_backup_final) && ++ !json_segment_cmp(jobj, jobj_backup_previous)) { ++ log_dbg(cd, "Segment does not match neither backup final or backup previous segment."); ++ return 1; ++ } ++ } ++ } ++ ++ return 0; ++} ++ + static int hdr_validate_segments(struct crypt_device *cd, json_object *hdr_jobj) + { + json_object *jobj_segments, *jobj_digests, *jobj_offset, *jobj_size, *jobj_type, *jobj_flags, *jobj; +@@ -732,7 +789,7 @@ static int hdr_validate_segments(struct + } + } + +- return 0; ++ return validate_reencrypt_segments(cd, hdr_jobj, jobj_segments, first_backup, count); + } + + uint64_t LUKS2_metadata_size(json_object *jobj) +diff -rupN cryptsetup-2.3.3.old/lib/luks2/luks2_segment.c cryptsetup-2.3.3/lib/luks2/luks2_segment.c +--- cryptsetup-2.3.3.old/lib/luks2/luks2_segment.c 2022-01-17 16:14:07.531136305 +0100 ++++ cryptsetup-2.3.3/lib/luks2/luks2_segment.c 2022-01-17 16:14:43.952263876 +0100 +@@ -410,3 +410,23 @@ json_object *LUKS2_get_segment_by_flag(s + + return jobj_segment; + } ++ ++/* compares key characteristics of both segments */ ++bool json_segment_cmp(json_object *jobj_segment_1, json_object *jobj_segment_2) ++{ ++ const char *type = json_segment_type(jobj_segment_1); ++ const char *type2 = json_segment_type(jobj_segment_2); ++ ++ if (!type || !type2) ++ return false; ++ ++ if (strcmp(type, type2)) ++ return false; ++ ++ if (!strcmp(type, "crypt")) ++ return (json_segment_get_sector_size(jobj_segment_1) == json_segment_get_sector_size(jobj_segment_2) && ++ !strcmp(json_segment_get_cipher(jobj_segment_1), ++ json_segment_get_cipher(jobj_segment_2))); ++ ++ return true; ++} diff --git a/SOURCES/cryptsetup-2.3.7-Allow-reencryption-metadata-repair-from-cryptsetup.patch b/SOURCES/cryptsetup-2.3.7-Allow-reencryption-metadata-repair-from-cryptsetup.patch new file mode 100644 index 0000000..357f533 --- /dev/null +++ b/SOURCES/cryptsetup-2.3.7-Allow-reencryption-metadata-repair-from-cryptsetup.patch @@ -0,0 +1,219 @@ +diff -rupN cryptsetup-2.3.3.old/man/cryptsetup.8 cryptsetup-2.3.3/man/cryptsetup.8 +--- cryptsetup-2.3.3.old/man/cryptsetup.8 2022-01-13 17:19:58.082434394 +0100 ++++ cryptsetup-2.3.3/man/cryptsetup.8 2022-01-13 17:20:19.860557992 +0100 +@@ -803,6 +803,13 @@ are fixable. This command will only chan + any key-slot data. You may enforce LUKS version by adding \-\-type + option. + ++It also repairs (upgrades) LUKS2 reencryption metadata by adding ++metadata digest that protects it against malicious changes. ++ ++If LUKS2 reencryption was interrupted in the middle of writting ++reencryption segment the repair command can be used to perform ++reencryption recovery so that reencryption can continue later. ++ + \fBWARNING:\fR Always create a binary backup of the original + header before calling this command. + .PP +diff -rupN cryptsetup-2.3.3.old/src/cryptsetup.c cryptsetup-2.3.3/src/cryptsetup.c +--- cryptsetup-2.3.3.old/src/cryptsetup.c 2022-01-13 17:19:58.064434292 +0100 ++++ cryptsetup-2.3.3/src/cryptsetup.c 2022-01-13 17:21:29.108950976 +0100 +@@ -1072,17 +1072,59 @@ static int set_keyslot_params(struct cry + return crypt_set_pbkdf_type(cd, &pbkdf); + } + +-static int _do_luks2_reencrypt_recovery(struct crypt_device *cd) ++static int reencrypt_metadata_repair(struct crypt_device *cd) ++{ ++ char *password; ++ size_t passwordLen; ++ int r; ++ struct crypt_params_reencrypt params = { ++ .flags = CRYPT_REENCRYPT_REPAIR_NEEDED ++ }; ++ ++ if (!opt_batch_mode && ++ !yesDialog(_("Unprotected LUKS2 reencryption metadata detected. " ++ "Please verify the reencryption operation is desirable (see luksDump output)\n" ++ "and continue (upgrade metadata) only if you acknowledge the operation as genuine."), ++ _("Operation aborted.\n"))) ++ return -EINVAL; ++ ++ r = tools_get_key(_("Enter passphrase to protect and uppgrade reencryption metadata: "), ++ &password, &passwordLen, opt_keyfile_offset, ++ opt_keyfile_size, opt_key_file, opt_timeout, ++ _verify_passphrase(0), 0, cd); ++ if (r < 0) ++ return r; ++ ++ r = crypt_reencrypt_init_by_passphrase(cd, NULL, password, passwordLen, ++ opt_key_slot, opt_key_slot, NULL, NULL, ¶ms); ++ tools_passphrase_msg(r); ++ if (r < 0) ++ goto out; ++ ++ r = crypt_activate_by_passphrase(cd, NULL, opt_key_slot, ++ password, passwordLen, 0); ++ tools_passphrase_msg(r); ++ if (r >= 0) ++ r = 0; ++ ++out: ++ crypt_safe_free(password); ++ return r; ++} ++ ++static int luks2_reencrypt_repair(struct crypt_device *cd) + { + int r; + size_t passwordLen; + const char *msg; + char *password = NULL; +- struct crypt_params_reencrypt recovery_params = { +- .flags = CRYPT_REENCRYPT_RECOVERY +- }; ++ struct crypt_params_reencrypt params = {}; ++ ++ crypt_reencrypt_info ri = crypt_reencrypt_status(cd, ¶ms); ++ ++ if (params.flags & CRYPT_REENCRYPT_REPAIR_NEEDED) ++ return reencrypt_metadata_repair(cd); + +- crypt_reencrypt_info ri = crypt_reencrypt_status(cd, NULL); + switch (ri) { + case CRYPT_REENCRYPT_NONE: + return 0; +@@ -1120,7 +1162,8 @@ static int _do_luks2_reencrypt_recovery( + } + + r = crypt_reencrypt_init_by_passphrase(cd, NULL, password, passwordLen, +- opt_key_slot, opt_key_slot, NULL, NULL, &recovery_params); ++ opt_key_slot, opt_key_slot, NULL, NULL, ++ &(struct crypt_params_reencrypt){ .flags = CRYPT_REENCRYPT_RECOVERY }); + if (r > 0) + r = 0; + out: +@@ -1155,8 +1198,9 @@ static int action_luksRepair(void) + if (r == 0) + r = crypt_repair(cd, luksType(opt_type), NULL); + skip_repair: ++ /* Header is ok, check if reencryption metadata needs repair/recovery. */ + if (!r && crypt_get_type(cd) && !strcmp(crypt_get_type(cd), CRYPT_LUKS2)) +- r = _do_luks2_reencrypt_recovery(cd); ++ r = luks2_reencrypt_repair(cd); + out: + crypt_free(cd); + return r; +diff -rupN cryptsetup-2.3.3.old/tests/luks2-reencryption-mangle-test cryptsetup-2.3.3/tests/luks2-reencryption-mangle-test +--- cryptsetup-2.3.3.old/tests/luks2-reencryption-mangle-test 2022-01-13 17:19:58.073434343 +0100 ++++ cryptsetup-2.3.3/tests/luks2-reencryption-mangle-test 2022-01-13 17:20:19.861557997 +0100 +@@ -172,6 +172,42 @@ EOF + [ $? -eq 0 ] || fail "Expect script failed." + } + ++function img_run_reenc_fail() ++{ ++local EXPECT_TIMEOUT=5 ++[ -n "$VALG" ] && EXPECT_TIMEOUT=60 ++# For now, we cannot run reencryption in batch mode for non-block device. Just fake the terminal here. ++expect_run - >/dev/null </dev/null && fail ++ fi ++ ++ img_run_reenc_fail ++ ++ # repair metadata ++ $CRYPTSETUP repair $IMG $CS_PARAMS || fail ++ ++ img_check_ok ++ img_run_reenc_ok ++} ++ + function valgrind_setup() + { + bin_check valgrind +@@ -212,10 +248,10 @@ img_check_ok + img_run_reenc_ok + img_check_ok + +-# Simulate old reencryption with no digest ++# Simulate old reencryption with no digest (repairable) + img_prepare + img_update_json 'del(.digests."2") | .config.requirements.mandatory = ["online-reencrypt"]' +-img_check_fail ++img_check_fail_repair_ok + + # This must fail for new releases + echo "[2] Old reencryption in-progress (journal)" +@@ -236,7 +272,7 @@ img_update_json ' + .digests."0".segments = ["1","2"] | + .digests."1".segments = ["0","3"] | + .config.requirements.mandatory = ["online-reencrypt"]' +-img_check_fail ++img_check_fail_repair_ok + + echo "[3] Old reencryption in-progress (checksum)" + img_prepare +@@ -258,7 +294,7 @@ img_update_json ' + .digests."0".segments = ["1","2"] | + .digests."1".segments = ["0","3"] | + .config.requirements.mandatory = ["online-reencrypt"]' +-img_check_fail ++img_check_fail_repair_ok + + # Note: older tools cannot create this from commandline + echo "[4] Old decryption in-progress (journal)" +@@ -289,7 +325,7 @@ img_update_json ' + } | + .digests."0".segments = ["1","2"] | + .config.requirements.mandatory = ["online-reencrypt"]' +-img_check_fail ++img_check_fail_repair_ok + + echo "[5] Old decryption in-progress (checksum)" + img_prepare +@@ -321,7 +357,7 @@ img_update_json ' + } | + .digests."0".segments = ["1","2"] | + .config.requirements.mandatory = ["online-reencrypt"]' +-img_check_fail ++img_check_fail_repair_ok + + # Note - offset is set to work with the old version (with a datashift bug) + echo "[6] Old reencryption in-progress (datashift)" +@@ -344,7 +380,7 @@ img_update_json ' + .digests."0".segments = ["0","2"] | + .digests."1".segments = ["1","3"] | + .config.requirements.mandatory = ["online-reencrypt"]' +-img_check_fail ++img_check_fail_repair_ok + + # + # NEW metadata (with reenc digest) +@@ -360,7 +396,7 @@ img_check_ok + # Repair must validate not only metadata, but also reencryption digest. + img_prepare + img_update_json 'del(.digests."2")' +-img_check_fail ++img_check_fail_repair_ok + + img_prepare '--reduce-device-size 2M' + img_update_json '.keyslots."2".area.shift_size = ((.keyslots."2".area.shift_size|tonumber / 2)|tostring)' diff --git a/SOURCES/cryptsetup-2.3.7-Do-not-run-reencryption-recovery-when-not-needed.patch b/SOURCES/cryptsetup-2.3.7-Do-not-run-reencryption-recovery-when-not-needed.patch new file mode 100644 index 0000000..a1b1d6d --- /dev/null +++ b/SOURCES/cryptsetup-2.3.7-Do-not-run-reencryption-recovery-when-not-needed.patch @@ -0,0 +1,65 @@ +From 18cb1eeeb9d320d9fb4f9bc3289a23f6694f9d60 Mon Sep 17 00:00:00 2001 +From: Milan Broz +Date: Sun, 2 Jan 2022 16:57:31 +0100 +Subject: [PATCH 13/28] Do not run reencryption recovery when not needed. + +--- + src/cryptsetup.c | 20 +++++++++++++------- + 1 file changed, 13 insertions(+), 7 deletions(-) + +diff --git a/src/cryptsetup.c b/src/cryptsetup.c +index 5547b3cc..206575c7 100644 +--- a/src/cryptsetup.c ++++ b/src/cryptsetup.c +@@ -1125,6 +1125,7 @@ static int _do_luks2_reencrypt_recovery(struct crypt_device *cd) + { + int r; + size_t passwordLen; ++ const char *msg; + char *password = NULL; + struct crypt_params_reencrypt recovery_params = { + .flags = CRYPT_REENCRYPT_RECOVERY +@@ -1133,12 +1134,8 @@ static int _do_luks2_reencrypt_recovery(struct crypt_device *cd) + crypt_reencrypt_info ri = crypt_reencrypt_status(cd, NULL); + switch (ri) { + case CRYPT_REENCRYPT_NONE: +- /* fall through */ ++ return 0; + case CRYPT_REENCRYPT_CLEAN: +- r = noDialog(_("Seems device does not require reencryption recovery.\n" +- "Do you want to proceed anyway?"), NULL); +- if (!r) +- return 0; + break; + case CRYPT_REENCRYPT_CRASH: + r = yesDialog(_("Really proceed with LUKS2 reencryption recovery?"), +@@ -1150,8 +1147,12 @@ static int _do_luks2_reencrypt_recovery(struct crypt_device *cd) + return -EINVAL; + } + +- r = tools_get_key(_("Enter passphrase for reencryption recovery: "), +- &password, &passwordLen, opt_keyfile_offset, ++ if (ri == CRYPT_REENCRYPT_CLEAN) ++ msg = _("Enter passphrase to verify reencryption metadata digest: "); ++ else ++ msg = _("Enter passphrase for reencryption recovery: "); ++ ++ r = tools_get_key(msg, &password, &passwordLen, opt_keyfile_offset, + opt_keyfile_size, opt_key_file, opt_timeout, + _verify_passphrase(0), 0, cd); + if (r < 0) +@@ -1162,6 +1163,11 @@ static int _do_luks2_reencrypt_recovery(struct crypt_device *cd) + if (r < 0) + goto out; + ++ if (ri == CRYPT_REENCRYPT_CLEAN) { ++ r = 0; ++ goto out; ++ } ++ + r = crypt_reencrypt_init_by_passphrase(cd, NULL, password, passwordLen, + opt_key_slot, opt_key_slot, NULL, NULL, &recovery_params); + if (r > 0) +-- +2.27.0 + diff --git a/SOURCES/cryptsetup-2.3.7-Expose-json_segment_contains_flag-to-internal-librar.patch b/SOURCES/cryptsetup-2.3.7-Expose-json_segment_contains_flag-to-internal-librar.patch new file mode 100644 index 0000000..bde7685 --- /dev/null +++ b/SOURCES/cryptsetup-2.3.7-Expose-json_segment_contains_flag-to-internal-librar.patch @@ -0,0 +1,22 @@ +diff -rupN cryptsetup-2.3.3.old/lib/luks2/luks2_internal.h cryptsetup-2.3.3/lib/luks2/luks2_internal.h +--- cryptsetup-2.3.3.old/lib/luks2/luks2_internal.h 2022-01-17 16:10:00.756271915 +0100 ++++ cryptsetup-2.3.3/lib/luks2/luks2_internal.h 2022-01-17 16:11:59.845689051 +0100 +@@ -206,4 +206,6 @@ static inline const char *crypt_reencryp + return ""; + } + ++bool json_segment_contains_flag(json_object *jobj_segment, const char *flag_str, size_t len); ++ + #endif +diff -rupN cryptsetup-2.3.3.old/lib/luks2/luks2_segment.c cryptsetup-2.3.3/lib/luks2/luks2_segment.c +--- cryptsetup-2.3.3.old/lib/luks2/luks2_segment.c 2022-01-17 16:10:00.756271915 +0100 ++++ cryptsetup-2.3.3/lib/luks2/luks2_segment.c 2022-01-17 16:10:34.422389838 +0100 +@@ -123,7 +123,7 @@ static json_object *json_segment_get_fla + return jobj; + } + +-static bool json_segment_contains_flag(json_object *jobj_segment, const char *flag_str, size_t len) ++bool json_segment_contains_flag(json_object *jobj_segment, const char *flag_str, size_t len) + { + int r, i; + json_object *jobj, *jobj_flags = json_segment_get_flags(jobj_segment); diff --git a/SOURCES/cryptsetup-2.3.7-Fix-CVE-2021-4122-LUKS2-reencryption-crash-recovery-.patch b/SOURCES/cryptsetup-2.3.7-Fix-CVE-2021-4122-LUKS2-reencryption-crash-recovery-.patch new file mode 100644 index 0000000..b1085dd --- /dev/null +++ b/SOURCES/cryptsetup-2.3.7-Fix-CVE-2021-4122-LUKS2-reencryption-crash-recovery-.patch @@ -0,0 +1,783 @@ +diff -rupN cryptsetup-2.3.3.old/lib/luks2/luks2.h cryptsetup-2.3.3/lib/luks2/luks2.h +--- cryptsetup-2.3.3.old/lib/luks2/luks2.h 2022-01-17 15:03:03.689201103 +0100 ++++ cryptsetup-2.3.3/lib/luks2/luks2.h 2022-01-17 15:06:42.149966321 +0100 +@@ -606,4 +606,8 @@ void crypt_reencrypt_unlock(struct crypt + + 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_reencrypt_digest_verify(struct crypt_device *cd, ++ struct luks2_hdr *hdr, ++ struct volume_key *vks); ++ + #endif +diff -rupN cryptsetup-2.3.3.old/lib/luks2/luks2_internal.h cryptsetup-2.3.3/lib/luks2/luks2_internal.h +--- cryptsetup-2.3.3.old/lib/luks2/luks2_internal.h 2022-01-17 15:03:03.689201103 +0100 ++++ cryptsetup-2.3.3/lib/luks2/luks2_internal.h 2022-01-17 15:51:20.125346606 +0100 +@@ -128,6 +128,12 @@ int placeholder_keyslot_alloc(struct cry + /* validate all keyslot implementations in hdr json */ + int LUKS2_keyslots_validate(struct crypt_device *cd, json_object *hdr_jobj); + ++int LUKS2_keyslot_jobj_area(json_object *jobj_keyslot, uint64_t *offset, uint64_t *length); ++ ++int LUKS2_keyslot_reencrypt_digest_create(struct crypt_device *cd, ++ struct luks2_hdr *hdr, ++ struct volume_key *vks); ++ + typedef struct { + const char *name; + keyslot_alloc_func alloc; +diff -rupN cryptsetup-2.3.3.old/lib/luks2/luks2_json_metadata.c cryptsetup-2.3.3/lib/luks2/luks2_json_metadata.c +--- cryptsetup-2.3.3.old/lib/luks2/luks2_json_metadata.c 2022-01-17 15:03:03.689201103 +0100 ++++ cryptsetup-2.3.3/lib/luks2/luks2_json_metadata.c 2022-01-17 15:05:48.165777220 +0100 +@@ -1371,24 +1371,63 @@ int LUKS2_config_set_flags(struct crypt_ + */ + + /* LUKS2 library requirements */ +-static const struct { ++struct requirement_flag { + uint32_t flag; ++ uint32_t version; + const char *description; +-} requirements_flags[] = { +- { CRYPT_REQUIREMENT_OFFLINE_REENCRYPT, "offline-reencrypt" }, +- { CRYPT_REQUIREMENT_ONLINE_REENCRYPT, "online-reencrypt" }, +- { 0, NULL } + }; + +-static uint32_t get_requirement_by_name(const char *requirement) ++static const struct requirement_flag unknown_requirement_flag = { CRYPT_REQUIREMENT_UNKNOWN, 0, NULL }; ++ ++static const struct requirement_flag requirements_flags[] = { ++ { CRYPT_REQUIREMENT_OFFLINE_REENCRYPT,1, "offline-reencrypt" }, ++ { CRYPT_REQUIREMENT_ONLINE_REENCRYPT, 2, "online-reencrypt-v2" }, ++ { CRYPT_REQUIREMENT_ONLINE_REENCRYPT, 1, "online-reencrypt" }, ++ { 0, 0, NULL } ++}; ++ ++static const struct requirement_flag *get_requirement_by_name(const char *requirement) + { + int i; + + for (i = 0; requirements_flags[i].description; i++) + if (!strcmp(requirement, requirements_flags[i].description)) +- return requirements_flags[i].flag; ++ return requirements_flags + i; ++ ++ return &unknown_requirement_flag; ++} ++ ++static const struct requirement_flag *stored_requirement_name_by_id(struct crypt_device *cd, struct luks2_hdr *hdr, uint32_t req_id) ++{ ++ json_object *jobj_config, *jobj_requirements, *jobj_mandatory, *jobj; ++ int i, len; ++ const struct requirement_flag *req; ++ ++ assert(hdr); ++ if (!hdr) ++ return NULL; ++ ++ if (!json_object_object_get_ex(hdr->jobj, "config", &jobj_config)) ++ return NULL; ++ ++ if (!json_object_object_get_ex(jobj_config, "requirements", &jobj_requirements)) ++ return NULL; ++ ++ if (!json_object_object_get_ex(jobj_requirements, "mandatory", &jobj_mandatory)) ++ return NULL; ++ ++ len = (int) json_object_array_length(jobj_mandatory); ++ if (len <= 0) ++ return 0; ++ ++ for (i = 0; i < len; i++) { ++ jobj = json_object_array_get_idx(jobj_mandatory, i); ++ req = get_requirement_by_name(json_object_get_string(jobj)); ++ if (req->flag == req_id) ++ return req; ++ } + +- return CRYPT_REQUIREMENT_UNKNOWN; ++ return NULL; + } + + /* +@@ -1398,7 +1437,7 @@ int LUKS2_config_get_requirements(struct + { + json_object *jobj_config, *jobj_requirements, *jobj_mandatory, *jobj; + int i, len; +- uint32_t req; ++ const struct requirement_flag *req; + + assert(hdr); + if (!hdr || !reqs) +@@ -1425,8 +1464,8 @@ int LUKS2_config_get_requirements(struct + jobj = json_object_array_get_idx(jobj_mandatory, i); + req = get_requirement_by_name(json_object_get_string(jobj)); + log_dbg(cd, "%s - %sknown", json_object_get_string(jobj), +- reqs_unknown(req) ? "un" : ""); +- *reqs |= req; ++ reqs_unknown(req->flag) ? "un" : ""); ++ *reqs |= req->flag; + } + + return 0; +@@ -1436,6 +1475,8 @@ int LUKS2_config_set_requirements(struct + { + json_object *jobj_config, *jobj_requirements, *jobj_mandatory, *jobj; + int i, r = -EINVAL; ++ const struct requirement_flag *req; ++ uint32_t req_id; + + if (!hdr) + return -EINVAL; +@@ -1445,8 +1486,14 @@ int LUKS2_config_set_requirements(struct + return -ENOMEM; + + for (i = 0; requirements_flags[i].description; i++) { +- if (reqs & requirements_flags[i].flag) { +- jobj = json_object_new_string(requirements_flags[i].description); ++ req_id = reqs & requirements_flags[i].flag; ++ if (req_id) { ++ /* retain already stored version of requirement flag */ ++ req = stored_requirement_name_by_id(cd, hdr, req_id); ++ if (req) ++ jobj = json_object_new_string(req->description); ++ else ++ jobj = json_object_new_string(requirements_flags[i].description); + if (!jobj) { + r = -ENOMEM; + goto err; +diff -rupN cryptsetup-2.3.3.old/lib/luks2/luks2_keyslot.c cryptsetup-2.3.3/lib/luks2/luks2_keyslot.c +--- cryptsetup-2.3.3.old/lib/luks2/luks2_keyslot.c 2022-01-17 15:03:03.689201103 +0100 ++++ cryptsetup-2.3.3/lib/luks2/luks2_keyslot.c 2022-01-17 15:05:48.165777220 +0100 +@@ -281,19 +281,9 @@ crypt_keyslot_info LUKS2_keyslot_info(st + return CRYPT_SLOT_ACTIVE; + } + +-int LUKS2_keyslot_area(struct luks2_hdr *hdr, +- int keyslot, +- uint64_t *offset, +- uint64_t *length) ++int LUKS2_keyslot_jobj_area(json_object *jobj_keyslot, uint64_t *offset, uint64_t *length) + { +- json_object *jobj_keyslot, *jobj_area, *jobj; +- +- if(LUKS2_keyslot_info(hdr, keyslot) == CRYPT_SLOT_INVALID) +- return -EINVAL; +- +- jobj_keyslot = LUKS2_get_keyslot_jobj(hdr, keyslot); +- if (!jobj_keyslot) +- return -ENOENT; ++ json_object *jobj_area, *jobj; + + if (!json_object_object_get_ex(jobj_keyslot, "area", &jobj_area)) + return -EINVAL; +@@ -309,6 +299,23 @@ int LUKS2_keyslot_area(struct luks2_hdr + return 0; + } + ++int LUKS2_keyslot_area(struct luks2_hdr *hdr, ++ int keyslot, ++ uint64_t *offset, ++ uint64_t *length) ++{ ++ json_object *jobj_keyslot; ++ ++ if (LUKS2_keyslot_info(hdr, keyslot) == CRYPT_SLOT_INVALID) ++ return -EINVAL; ++ ++ jobj_keyslot = LUKS2_get_keyslot_jobj(hdr, keyslot); ++ if (!jobj_keyslot) ++ return -ENOENT; ++ ++ return LUKS2_keyslot_jobj_area(jobj_keyslot, offset, length); ++} ++ + static int _open_and_verify(struct crypt_device *cd, + struct luks2_hdr *hdr, + const keyslot_handler *h, +diff -rupN cryptsetup-2.3.3.old/lib/luks2/luks2_keyslot_reenc.c cryptsetup-2.3.3/lib/luks2/luks2_keyslot_reenc.c +--- cryptsetup-2.3.3.old/lib/luks2/luks2_keyslot_reenc.c 2022-01-17 15:03:03.689201103 +0100 ++++ cryptsetup-2.3.3/lib/luks2/luks2_keyslot_reenc.c 2022-01-17 15:59:15.897013127 +0100 +@@ -179,6 +179,7 @@ static int reenc_keyslot_store(struct cr + int reenc_keyslot_update(struct crypt_device *cd, + const struct luks2_reenc_context *rh) + { ++ int r; + json_object *jobj_keyslot, *jobj_area, *jobj_area_type; + struct luks2_hdr *hdr; + +@@ -208,11 +209,23 @@ int reenc_keyslot_update(struct crypt_de + } else + log_dbg(cd, "No update of reencrypt keyslot needed."); + +- return 0; ++ r = LUKS2_keyslot_reencrypt_digest_create(cd, hdr, rh->vks); ++ if (r < 0) ++ log_err(cd, "Failed to refresh reencryption verification digest."); ++ ++ return r; + } + + static int reenc_keyslot_wipe(struct crypt_device *cd, int keyslot) + { ++ struct luks2_hdr *hdr; ++ ++ if (!(hdr = crypt_get_hdr(cd, CRYPT_LUKS2))) ++ return -EINVAL; ++ ++ /* remove reencryption verification data */ ++ LUKS2_digest_assign(cd, hdr, keyslot, CRYPT_ANY_DIGEST, 0, 0); ++ + return 0; + } + +diff -rupN cryptsetup-2.3.3.old/lib/luks2/luks2_reencrypt.c cryptsetup-2.3.3/lib/luks2/luks2_reencrypt.c +--- cryptsetup-2.3.3.old/lib/luks2/luks2_reencrypt.c 2022-01-17 15:03:03.689201103 +0100 ++++ cryptsetup-2.3.3/lib/luks2/luks2_reencrypt.c 2022-01-17 15:57:08.906568302 +0100 +@@ -2390,6 +2390,10 @@ static int reencrypt_init(struct crypt_d + if (r < 0) + goto err; + ++ r = LUKS2_keyslot_reencrypt_digest_create(cd, hdr, *vks); ++ if (r < 0) ++ goto err; ++ + if (name && params->mode != CRYPT_REENCRYPT_ENCRYPT) { + r = reencrypt_verify_and_upload_keys(cd, hdr, LUKS2_reencrypt_digest_old(hdr), LUKS2_reencrypt_digest_new(hdr), *vks); + if (r) +@@ -2520,20 +2524,28 @@ static int reencrypt_context_update(stru + static int reencrypt_load(struct crypt_device *cd, struct luks2_hdr *hdr, + uint64_t device_size, + const struct crypt_params_reencrypt *params, ++ struct volume_key *vks, + struct luks2_reenc_context **rh) + { + int r; + struct luks2_reenc_context *tmp = NULL; + crypt_reencrypt_info ri = LUKS2_reenc_status(hdr); + ++ if (ri == CRYPT_REENCRYPT_NONE) { ++ log_err(cd, _("Device not marked for LUKS2 reencryption.")); ++ return -EINVAL; ++ } else if (ri == CRYPT_REENCRYPT_INVALID) ++ return -EINVAL; ++ ++ r = LUKS2_reencrypt_digest_verify(cd, hdr, vks); ++ if (r < 0) ++ return r; ++ + if (ri == CRYPT_REENCRYPT_CLEAN) + r = reencrypt_load_clean(cd, hdr, device_size, &tmp, params); + else if (ri == CRYPT_REENCRYPT_CRASH) + r = reencrypt_load_crashed(cd, hdr, device_size, &tmp); +- else if (ri == CRYPT_REENCRYPT_NONE) { +- log_err(cd, _("Device not marked for LUKS2 reencryption.")); +- return -EINVAL; +- } else ++ else + r = -EINVAL; + + if (r < 0 || !tmp) { +@@ -2781,7 +2793,7 @@ static int reencrypt_load_by_passphrase( + rparams.device_size = required_size; + } + +- r = reencrypt_load(cd, hdr, device_size, &rparams, &rh); ++ r = reencrypt_load(cd, hdr, device_size, &rparams, *vks, &rh); + if (r < 0 || !rh) + goto err; + +@@ -3001,13 +3013,6 @@ static reenc_status_t reencrypt_step(str + { + int r; + +- /* update reencrypt keyslot protection parameters in memory only */ +- r = reenc_keyslot_update(cd, rh); +- if (r < 0) { +- log_dbg(cd, "Keyslot update failed."); +- return REENC_ERR; +- } +- + /* in memory only */ + r = reencrypt_make_segments(cd, hdr, rh, device_size); + if (r) +@@ -3272,6 +3277,15 @@ int crypt_reencrypt(struct crypt_device + + rs = REENC_OK; + ++ /* update reencrypt keyslot protection parameters in memory only */ ++ if (!quit && (rh->device_size > rh->progress)) { ++ r = reenc_keyslot_update(cd, rh); ++ if (r < 0) { ++ log_dbg(cd, "Keyslot update failed."); ++ return reencrypt_teardown(cd, hdr, rh, REENC_ERR, quit, progress); ++ } ++ } ++ + while (!quit && (rh->device_size > rh->progress)) { + rs = reencrypt_step(cd, hdr, rh, rh->device_size, rh->online); + if (rs != REENC_OK) +@@ -3304,7 +3318,7 @@ static int reencrypt_recovery(struct cry + int r; + struct luks2_reenc_context *rh = NULL; + +- r = reencrypt_load(cd, hdr, device_size, NULL, &rh); ++ r = reencrypt_load(cd, hdr, device_size, NULL, vks, &rh); + if (r < 0) { + log_err(cd, _("Failed to load LUKS2 reencryption context.")); + return r; +diff -rupN cryptsetup-2.3.3.old/lib/luks2/luks2_reencrypt_digest.c cryptsetup-2.3.3/lib/luks2/luks2_reencrypt_digest.c +--- cryptsetup-2.3.3.old/lib/luks2/luks2_reencrypt_digest.c 1970-01-01 01:00:00.000000000 +0100 ++++ cryptsetup-2.3.3/lib/luks2/luks2_reencrypt_digest.c 2022-01-17 15:05:48.166777223 +0100 +@@ -0,0 +1,381 @@ ++/* ++ * LUKS - Linux Unified Key Setup v2, reencryption digest helpers ++ * ++ * Copyright (C) 2022, Red Hat, Inc. All rights reserved. ++ * Copyright (C) 2022, Ondrej Kozina ++ * Copyright (C) 2022, Milan Broz ++ * ++ * 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, write to the Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ++ */ ++ ++#include "luks2_internal.h" ++#include ++ ++#define MAX_STR 64 ++ ++struct jtype { ++ enum { JNONE = 0, JSTR, JU64, JX64, JU32 } type; ++ json_object *jobj; ++ const char *id; ++}; ++ ++static size_t sr(struct jtype *j, uint8_t *ptr) ++{ ++ json_object *jobj; ++ size_t len = 0; ++ uint64_t u64; ++ uint32_t u32; ++ ++ if (!json_object_is_type(j->jobj, json_type_object)) ++ return 0; ++ ++ if (!json_object_object_get_ex(j->jobj, j->id, &jobj)) ++ return 0; ++ ++ switch(j->type) { ++ case JSTR: /* JSON string */ ++ if (!json_object_is_type(jobj, json_type_string)) ++ return 0; ++ len = strlen(json_object_get_string(jobj)); ++ if (len > MAX_STR) ++ return 0; ++ if (ptr) ++ memcpy(ptr, json_object_get_string(jobj), len); ++ break; ++ case JU64: /* Unsigned 64bit integer stored as string */ ++ if (!json_object_is_type(jobj, json_type_string)) ++ break; ++ len = sizeof(u64); ++ if (ptr) { ++ u64 = cpu_to_be64(crypt_jobj_get_uint64(jobj)); ++ memcpy(ptr, &u64, len); ++ } ++ break; ++ case JX64: /* Unsigned 64bit segment size (allows "dynamic") */ ++ if (!json_object_is_type(jobj, json_type_string)) ++ break; ++ if (!strcmp(json_object_get_string(jobj), "dynamic")) { ++ len = strlen("dynamic"); ++ if (ptr) ++ memcpy(ptr, json_object_get_string(jobj), len); ++ } else { ++ len = sizeof(u64); ++ u64 = cpu_to_be64(crypt_jobj_get_uint64(jobj)); ++ if (ptr) ++ memcpy(ptr, &u64, len); ++ } ++ break; ++ case JU32: /* Unsigned 32bit integer, stored as JSON int */ ++ if (!json_object_is_type(jobj, json_type_int)) ++ return 0; ++ len = sizeof(u32); ++ if (ptr) { ++ u32 = cpu_to_be32(crypt_jobj_get_uint32(jobj)); ++ memcpy(ptr, &u32, len); ++ } ++ break; ++ case JNONE: ++ return 0; ++ }; ++ ++ return len; ++} ++ ++static size_t srs(struct jtype j[], uint8_t *ptr) ++{ ++ size_t l, len = 0; ++ ++ while(j->jobj) { ++ l = sr(j, ptr); ++ if (!l) ++ return 0; ++ len += l; ++ if (ptr) ++ ptr += l; ++ j++; ++ } ++ return len; ++} ++ ++static size_t segment_linear_serialize(json_object *jobj_segment, uint8_t *buffer) ++{ ++ struct jtype j[] = { ++ { JSTR, jobj_segment, "type" }, ++ { JU64, jobj_segment, "offset" }, ++ { JX64, jobj_segment, "size" }, ++ {} ++ }; ++ return srs(j, buffer); ++} ++ ++static size_t segment_crypt_serialize(json_object *jobj_segment, uint8_t *buffer) ++{ ++ struct jtype j[] = { ++ { JSTR, jobj_segment, "type" }, ++ { JU64, jobj_segment, "offset" }, ++ { JX64, jobj_segment, "size" }, ++ { JU64, jobj_segment, "iv_tweak" }, ++ { JSTR, jobj_segment, "encryption" }, ++ { JU32, jobj_segment, "sector_size" }, ++ {} ++ }; ++ return srs(j, buffer); ++} ++ ++static size_t segment_serialize(json_object *jobj_segment, uint8_t *buffer) ++{ ++ json_object *jobj_type; ++ const char *segment_type; ++ ++ if (!json_object_object_get_ex(jobj_segment, "type", &jobj_type)) ++ return 0; ++ ++ if (!(segment_type = json_object_get_string(jobj_type))) ++ return 0; ++ ++ if (!strcmp(segment_type, "crypt")) ++ return segment_crypt_serialize(jobj_segment, buffer); ++ else if (!strcmp(segment_type, "linear")) ++ return segment_linear_serialize(jobj_segment, buffer); ++ ++ return 0; ++} ++ ++static size_t backup_segments_serialize(struct luks2_hdr *hdr, uint8_t *buffer) ++{ ++ json_object *jobj_segment; ++ size_t l, len = 0; ++ ++ jobj_segment = LUKS2_get_segment_by_flag(hdr, "backup-previous"); ++ if (!jobj_segment || !(l = segment_serialize(jobj_segment, buffer))) ++ return 0; ++ len += l; ++ if (buffer) ++ buffer += l; ++ ++ jobj_segment = LUKS2_get_segment_by_flag(hdr, "backup-final"); ++ if (!jobj_segment || !(l = segment_serialize(jobj_segment, buffer))) ++ return 0; ++ len += l; ++ if (buffer) ++ buffer += l; ++ ++ jobj_segment = LUKS2_get_segment_by_flag(hdr, "backup-moved-segment"); ++ if (jobj_segment) { ++ if (!(l = segment_serialize(jobj_segment, buffer))) ++ return 0; ++ len += l; ++ } ++ ++ return len; ++} ++ ++static size_t reenc_keyslot_serialize(struct luks2_hdr *hdr, uint8_t *buffer) ++{ ++ json_object *jobj_keyslot, *jobj_area, *jobj_type; ++ const char *area_type; ++ int keyslot_reencrypt; ++ ++ keyslot_reencrypt = LUKS2_find_keyslot(hdr, "reencrypt"); ++ if (keyslot_reencrypt < 0) ++ return 0; ++ ++ if (!(jobj_keyslot = LUKS2_get_keyslot_jobj(hdr, keyslot_reencrypt))) ++ return 0; ++ ++ if (!json_object_object_get_ex(jobj_keyslot, "area", &jobj_area)) ++ return 0; ++ ++ if (!json_object_object_get_ex(jobj_area, "type", &jobj_type)) ++ return 0; ++ ++ if (!(area_type = json_object_get_string(jobj_type))) ++ return 0; ++ ++ struct jtype j[] = { ++ { JSTR, jobj_keyslot, "mode" }, ++ { JSTR, jobj_keyslot, "direction" }, ++ { JSTR, jobj_area, "type" }, ++ { JU64, jobj_area, "offset" }, ++ { JU64, jobj_area, "size" }, ++ {} ++ }; ++ struct jtype j_datashift[] = { ++ { JSTR, jobj_keyslot, "mode" }, ++ { JSTR, jobj_keyslot, "direction" }, ++ { JSTR, jobj_area, "type" }, ++ { JU64, jobj_area, "offset" }, ++ { JU64, jobj_area, "size" }, ++ { JU64, jobj_area, "shift_size" }, ++ {} ++ }; ++ struct jtype j_checksum[] = { ++ { JSTR, jobj_keyslot, "mode" }, ++ { JSTR, jobj_keyslot, "direction" }, ++ { JSTR, jobj_area, "type" }, ++ { JU64, jobj_area, "offset" }, ++ { JU64, jobj_area, "size" }, ++ { JSTR, jobj_area, "hash" }, ++ { JU32, jobj_area, "sector_size" }, ++ {} ++ }; ++ ++ if (!strcmp(area_type, "datashift")) ++ return srs(j_datashift, buffer); ++ else if (!strcmp(area_type, "checksum")) ++ return srs(j_checksum, buffer); ++ ++ return srs(j, buffer); ++} ++ ++static size_t blob_serialize(void *blob, size_t length, uint8_t *buffer) ++{ ++ if (buffer) ++ memcpy(buffer, blob, length); ++ ++ return length; ++} ++ ++static int reencrypt_assembly_verification_data(struct crypt_device *cd, ++ struct luks2_hdr *hdr, ++ struct volume_key *vks, ++ struct volume_key **verification_data) ++{ ++ uint8_t *ptr; ++ int digest_new, digest_old; ++ struct volume_key *data = NULL, *vk_old = NULL, *vk_new = NULL; ++ size_t keyslot_data_len, segments_data_len, data_len = 2; ++ ++ /* Keys - calculate length */ ++ digest_new = LUKS2_reencrypt_digest_new(hdr); ++ digest_old = LUKS2_reencrypt_digest_old(hdr); ++ ++ if (digest_old >= 0) { ++ vk_old = crypt_volume_key_by_id(vks, digest_old); ++ if (!vk_old) ++ return -EINVAL; ++ data_len += blob_serialize(vk_old->key, vk_old->keylength, NULL); ++ } ++ ++ if (digest_new >= 0 && digest_old != digest_new) { ++ vk_new = crypt_volume_key_by_id(vks, digest_new); ++ if (!vk_new) ++ return -EINVAL; ++ data_len += blob_serialize(vk_new->key, vk_new->keylength, NULL); ++ } ++ ++ if (data_len == 2) ++ return -EINVAL; ++ ++ /* Metadata - calculate length */ ++ if (!(keyslot_data_len = reenc_keyslot_serialize(hdr, NULL))) ++ return -EINVAL; ++ data_len += keyslot_data_len; ++ ++ if (!(segments_data_len = backup_segments_serialize(hdr, NULL))) ++ return -EINVAL; ++ data_len += segments_data_len; ++ ++ /* Alloc and fill serialization data */ ++ data = crypt_alloc_volume_key(data_len, NULL); ++ if (!data) ++ return -ENOMEM; ++ ++ ptr = (uint8_t*)data->key; ++ ++ /* v2 */ ++ *ptr++ = 0x76; ++ *ptr++ = 0x32; ++ ++ if (vk_old) ++ ptr += blob_serialize(vk_old->key, vk_old->keylength, ptr); ++ ++ if (vk_new) ++ ptr += blob_serialize(vk_new->key, vk_new->keylength, ptr); ++ ++ if (!reenc_keyslot_serialize(hdr, ptr)) ++ goto bad; ++ ptr += keyslot_data_len; ++ ++ if (!backup_segments_serialize(hdr, ptr)) ++ goto bad; ++ ptr += segments_data_len; ++ ++ assert((size_t)(ptr - (uint8_t*)data->key) == data_len); ++ ++ *verification_data = data; ++ ++ return 0; ++bad: ++ crypt_free_volume_key(data); ++ return -EINVAL; ++} ++ ++int LUKS2_keyslot_reencrypt_digest_create(struct crypt_device *cd, ++ struct luks2_hdr *hdr, ++ struct volume_key *vks) ++{ ++ int digest_reencrypt, keyslot_reencrypt, r; ++ struct volume_key *data; ++ ++ keyslot_reencrypt = LUKS2_find_keyslot(hdr, "reencrypt"); ++ if (keyslot_reencrypt < 0) ++ return keyslot_reencrypt; ++ ++ r = reencrypt_assembly_verification_data(cd, hdr, vks, &data); ++ if (r < 0) ++ return r; ++ ++ r = LUKS2_digest_create(cd, "pbkdf2", hdr, data); ++ crypt_free_volume_key(data); ++ if (r < 0) ++ return r; ++ ++ digest_reencrypt = r; ++ ++ r = LUKS2_digest_assign(cd, hdr, keyslot_reencrypt, CRYPT_ANY_DIGEST, 0, 0); ++ if (r < 0) ++ return r; ++ ++ return LUKS2_digest_assign(cd, hdr, keyslot_reencrypt, digest_reencrypt, 1, 0); ++} ++ ++int LUKS2_reencrypt_digest_verify(struct crypt_device *cd, ++ struct luks2_hdr *hdr, ++ struct volume_key *vks) ++{ ++ int r, keyslot_reencrypt; ++ struct volume_key *data; ++ ++ keyslot_reencrypt = LUKS2_find_keyslot(hdr, "reencrypt"); ++ if (keyslot_reencrypt < 0) ++ return keyslot_reencrypt; ++ ++ r = reencrypt_assembly_verification_data(cd, hdr, vks, &data); ++ if (r < 0) ++ return r; ++ ++ r = LUKS2_digest_verify(cd, hdr, data, keyslot_reencrypt); ++ crypt_free_volume_key(data); ++ ++ if (r < 0) { ++ if (r == -ENOENT) ++ log_dbg(cd, "Reencryption digest is missing."); ++ log_err(cd, _("Reencryption metadata is invalid.")); ++ } else ++ log_dbg(cd, "Reencryption metadata verified."); ++ ++ return r; ++} +diff -rupN cryptsetup-2.3.3.old/lib/Makemodule.am cryptsetup-2.3.3/lib/Makemodule.am +--- cryptsetup-2.3.3.old/lib/Makemodule.am 2022-01-17 15:03:03.687201096 +0100 ++++ cryptsetup-2.3.3/lib/Makemodule.am 2022-01-17 15:05:48.164777216 +0100 +@@ -104,6 +104,7 @@ libcryptsetup_la_SOURCES = \ + lib/luks2/luks2_keyslot_luks2.c \ + lib/luks2/luks2_keyslot_reenc.c \ + lib/luks2/luks2_reencrypt.c \ ++ lib/luks2/luks2_reencrypt_digest.c \ + lib/luks2/luks2_segment.c \ + lib/luks2/luks2_token_keyring.c \ + lib/luks2/luks2_token.c \ +diff -rupN cryptsetup-2.3.3.old/lib/setup.c cryptsetup-2.3.3/lib/setup.c +--- cryptsetup-2.3.3.old/lib/setup.c 2022-01-17 15:03:03.686201093 +0100 ++++ cryptsetup-2.3.3/lib/setup.c 2022-01-17 16:00:07.797194917 +0100 +@@ -4032,6 +4032,12 @@ static int _open_and_activate_reencrypt_ + keyslot = r; + } + ++ if (r >= 0) { ++ r = LUKS2_reencrypt_digest_verify(cd, hdr, vks); ++ if (r < 0) ++ goto err; ++ } ++ + log_dbg(cd, "Entering clean reencryption state mode."); + + if (r >= 0) +@@ -4059,8 +4065,9 @@ static int _open_and_activate_luks2(stru + uint32_t flags) + { + crypt_reencrypt_info ri; +- int r; ++ int r, rv; + struct luks2_hdr *hdr = &cd->u.luks2.hdr; ++ struct volume_key *vks = NULL; + + ri = LUKS2_reenc_status(hdr); + if (ri == CRYPT_REENCRYPT_INVALID) +@@ -4070,9 +4077,17 @@ static int _open_and_activate_luks2(stru + if (name) + r = _open_and_activate_reencrypt_device(cd, hdr, keyslot, name, passphrase, + passphrase_size, flags); +- else ++ else { + r = _open_all_keys(cd, hdr, keyslot, passphrase, +- passphrase_size, flags, NULL); ++ passphrase_size, flags, &vks); ++ if (r < 0) ++ return r; ++ ++ rv = LUKS2_reencrypt_digest_verify(cd, hdr, vks); ++ crypt_free_volume_key(vks); ++ if (rv < 0) ++ return rv; ++ } + } else + r = _open_and_activate(cd, keyslot, name, passphrase, + passphrase_size, flags); +diff -rupN cryptsetup-2.3.3.old/po/POTFILES.in cryptsetup-2.3.3/po/POTFILES.in +--- cryptsetup-2.3.3.old/po/POTFILES.in 2022-01-17 15:03:03.694201121 +0100 ++++ cryptsetup-2.3.3/po/POTFILES.in 2022-01-17 15:05:48.166777223 +0100 +@@ -37,6 +37,7 @@ lib/luks2/luks2_keyslot_luks2.c + lib/luks2/luks2_keyslot_reenc.c + lib/luks2/luks2_luks1_convert.c + lib/luks2/luks2_reencrypt.c ++lib/luks2/luks2_reencrypt_digest.c + lib/luks2/luks2_segment.c + lib/luks2/luks2_token.c + lib/luks2/luks2_token_keyring.c diff --git a/SOURCES/cryptsetup-2.3.7-Fix-reencrypt-mangle-test-for-older-jq.patch b/SOURCES/cryptsetup-2.3.7-Fix-reencrypt-mangle-test-for-older-jq.patch new file mode 100644 index 0000000..05f06f2 --- /dev/null +++ b/SOURCES/cryptsetup-2.3.7-Fix-reencrypt-mangle-test-for-older-jq.patch @@ -0,0 +1,25 @@ +From b1ef7cc3cdfb708bb08c90425a7dbdef383da84c Mon Sep 17 00:00:00 2001 +From: Milan Broz +Date: Thu, 13 Jan 2022 10:12:45 +0100 +Subject: [PATCH 27/28] Fix reencrypt mangle test for older jq. + +--- + tests/luks2-reencryption-mangle-test | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/tests/luks2-reencryption-mangle-test b/tests/luks2-reencryption-mangle-test +index 0cca23a0..8f308f5d 100755 +--- a/tests/luks2-reencryption-mangle-test ++++ b/tests/luks2-reencryption-mangle-test +@@ -51,7 +51,7 @@ function img_json_save() + # FIXME: why --json-file cannot be used? + #$CRYPTSETUP luksDump --dump-json-metadata $IMG | jq -c -M | tr -d '\n' >$IMG_JSON + local LUKS2_JSON_SIZE=$(($JSON_MSIZE - 4096)) +- _dd if=$IMG count=$LUKS2_JSON_SIZE skip=4096 | jq -c -M | tr -d '\n' >$IMG_JSON ++ _dd if=$IMG count=$LUKS2_JSON_SIZE skip=4096 | jq -c -M . | tr -d '\n' >$IMG_JSON + } + + function img_json_dump() +-- +2.27.0 + diff --git a/SOURCES/cryptsetup-2.3.7-Make-reencryption-flag-and-keyslot-inseparable.patch b/SOURCES/cryptsetup-2.3.7-Make-reencryption-flag-and-keyslot-inseparable.patch new file mode 100644 index 0000000..c713b56 --- /dev/null +++ b/SOURCES/cryptsetup-2.3.7-Make-reencryption-flag-and-keyslot-inseparable.patch @@ -0,0 +1,93 @@ +From c75d740f9abd8a005975517008f780b16d103b0a Mon Sep 17 00:00:00 2001 +From: Ondrej Kozina +Date: Thu, 6 Jan 2022 12:24:26 +0100 +Subject: [PATCH 20/28] Make reencryption flag and keyslot inseparable. + +LUKS2 validation code now requires reencrypt keyslot together with +online-reencryption flag or none of those. +--- + lib/luks2/luks2_keyslot.c | 25 +++++++++++++++++++++++++ + lib/luks2/luks2_reencrypt.c | 17 +++++++++++------ + 2 files changed, 36 insertions(+), 6 deletions(-) + +diff --git a/lib/luks2/luks2_keyslot.c b/lib/luks2/luks2_keyslot.c +index 2ad5632c..d93f2dda 100644 +--- a/lib/luks2/luks2_keyslot.c ++++ b/lib/luks2/luks2_keyslot.c +@@ -878,10 +878,17 @@ int LUKS2_keyslots_validate(struct crypt_device *cd, json_object *hdr_jobj) + const keyslot_handler *h; + int keyslot; + json_object *jobj_keyslots, *jobj_type; ++ uint32_t reqs, reencrypt_count = 0; ++ struct luks2_hdr dummy = { ++ .jobj = hdr_jobj ++ }; + + if (!json_object_object_get_ex(hdr_jobj, "keyslots", &jobj_keyslots)) + return -EINVAL; + ++ if (LUKS2_config_get_requirements(cd, &dummy, &reqs)) ++ return -EINVAL; ++ + json_object_object_foreach(jobj_keyslots, slot, val) { + keyslot = atoi(slot); + json_object_object_get_ex(val, "type", &jobj_type); +@@ -897,6 +904,24 @@ int LUKS2_keyslots_validate(struct crypt_device *cd, json_object *hdr_jobj) + log_dbg(cd, "Keyslot %d is not assigned to exactly 1 digest.", keyslot); + return -EINVAL; + } ++ ++ if (!strcmp(h->name, "reencrypt")) ++ reencrypt_count++; ++ } ++ ++ if ((reqs & CRYPT_REQUIREMENT_ONLINE_REENCRYPT) && reencrypt_count == 0) { ++ log_dbg(cd, "Missing reencryption keyslot."); ++ return -EINVAL; ++ } ++ ++ if (!(reqs & CRYPT_REQUIREMENT_ONLINE_REENCRYPT) && reencrypt_count) { ++ log_dbg(cd, "Missing reencryption requirement flag."); ++ return -EINVAL; ++ } ++ ++ if (reencrypt_count > 1) { ++ log_dbg(cd, "Too many reencryption keyslots."); ++ return -EINVAL; + } + + return 0; +diff --git a/lib/luks2/luks2_reencrypt.c b/lib/luks2/luks2_reencrypt.c +index f68675de..104871a4 100644 +--- a/lib/luks2/luks2_reencrypt.c ++++ b/lib/luks2/luks2_reencrypt.c +@@ -3301,15 +3301,20 @@ static int reencrypt_teardown_ok(struct crypt_device *cd, struct luks2_hdr *hdr, + log_dbg(cd, "Failed to set new keyslots area size."); + if (rh->digest_old >= 0 && rh->digest_new != rh->digest_old) + for (i = 0; i < LUKS2_KEYSLOTS_MAX; i++) +- if (LUKS2_digest_by_keyslot(hdr, i) == rh->digest_old) +- crypt_keyslot_destroy(cd, i); +- crypt_keyslot_destroy(cd, rh->reenc_keyslot); ++ if (LUKS2_digest_by_keyslot(hdr, i) == rh->digest_old && crypt_keyslot_destroy(cd, i)) ++ log_err(cd, _("Failed to remove unused (unbound) keyslot %d."), i); ++ + if (reencrypt_erase_backup_segments(cd, hdr)) + log_dbg(cd, "Failed to erase backup segments"); + +- /* do we need atomic erase? */ +- if (reencrypt_update_flag(cd, 0, true)) +- log_err(cd, _("Failed to disable reencryption requirement flag.")); ++ if (reencrypt_update_flag(cd, 0, false)) ++ log_dbg(cd, "Failed to disable reencryption requirement flag."); ++ ++ /* metadata commit point also removing reencryption flag on-disk */ ++ if (crypt_keyslot_destroy(cd, rh->reenc_keyslot)) { ++ log_err(cd, _("Failed to remove reencryption keyslot.")); ++ return -EINVAL; ++ } + } + + return 0; +-- +2.27.0 + diff --git a/SOURCES/cryptsetup-2.3.7-Move-requirement-helpers-for-later-changes.patch b/SOURCES/cryptsetup-2.3.7-Move-requirement-helpers-for-later-changes.patch new file mode 100644 index 0000000..5472e17 --- /dev/null +++ b/SOURCES/cryptsetup-2.3.7-Move-requirement-helpers-for-later-changes.patch @@ -0,0 +1,60 @@ +From 4e98b65c04b624888b39216c81da17b2d0aedfb8 Mon Sep 17 00:00:00 2001 +From: Ondrej Kozina +Date: Thu, 6 Jan 2022 14:28:36 +0100 +Subject: [PATCH 15/28] Move requirement helpers for later changes. + +--- + lib/luks2/luks2_json_metadata.c | 30 +++++++++++++++--------------- + 1 file changed, 15 insertions(+), 15 deletions(-) + +diff --git a/lib/luks2/luks2_json_metadata.c b/lib/luks2/luks2_json_metadata.c +index 6071b077..e45a9739 100644 +--- a/lib/luks2/luks2_json_metadata.c ++++ b/lib/luks2/luks2_json_metadata.c +@@ -591,6 +591,21 @@ static bool validate_segment_intervals(struct crypt_device *cd, + return true; + } + ++static int reqs_unknown(uint32_t reqs) ++{ ++ return reqs & CRYPT_REQUIREMENT_UNKNOWN; ++} ++ ++static int reqs_reencrypt(uint32_t reqs) ++{ ++ return reqs & CRYPT_REQUIREMENT_OFFLINE_REENCRYPT; ++} ++ ++static int reqs_reencrypt_online(uint32_t reqs) ++{ ++ return reqs & CRYPT_REQUIREMENT_ONLINE_REENCRYPT; ++} ++ + static int hdr_validate_segments(struct crypt_device *cd, json_object *hdr_jobj) + { + json_object *jobj_segments, *jobj_digests, *jobj_offset, *jobj_size, *jobj_type, *jobj_flags, *jobj; +@@ -1138,21 +1153,6 @@ int LUKS2_hdr_backup(struct crypt_device *cd, struct luks2_hdr *hdr, + return r; + } + +-static int reqs_unknown(uint32_t reqs) +-{ +- return reqs & CRYPT_REQUIREMENT_UNKNOWN; +-} +- +-static int reqs_reencrypt(uint32_t reqs) +-{ +- return reqs & CRYPT_REQUIREMENT_OFFLINE_REENCRYPT; +-} +- +-static int reqs_reencrypt_online(uint32_t reqs) +-{ +- return reqs & CRYPT_REQUIREMENT_ONLINE_REENCRYPT; +-} +- + int LUKS2_hdr_restore(struct crypt_device *cd, struct luks2_hdr *hdr, + const char *backup_file) + { +-- +2.27.0 + diff --git a/SOURCES/cryptsetup-2.3.7-Reenc-keyslot-must-have-key_size-1.patch b/SOURCES/cryptsetup-2.3.7-Reenc-keyslot-must-have-key_size-1.patch new file mode 100644 index 0000000..ab0f971 --- /dev/null +++ b/SOURCES/cryptsetup-2.3.7-Reenc-keyslot-must-have-key_size-1.patch @@ -0,0 +1,45 @@ +From 7eeb45537af1db8a29b4e2956545ccde8ad13d32 Mon Sep 17 00:00:00 2001 +From: Milan Broz +Date: Sun, 2 Jan 2022 16:57:31 +0100 +Subject: [PATCH 12/28] Reenc keyslot must have key_size == 1. + +--- + lib/luks2/luks2_keyslot_reenc.c | 10 ++++++++-- + 1 file changed, 8 insertions(+), 2 deletions(-) + +diff --git a/lib/luks2/luks2_keyslot_reenc.c b/lib/luks2/luks2_keyslot_reenc.c +index 1956fe27..9da7007d 100644 +--- a/lib/luks2/luks2_keyslot_reenc.c ++++ b/lib/luks2/luks2_keyslot_reenc.c +@@ -230,7 +230,7 @@ static int reenc_keyslot_dump(struct crypt_device *cd, int keyslot) + + static int reenc_keyslot_validate(struct crypt_device *cd, json_object *jobj_keyslot) + { +- json_object *jobj_mode, *jobj_area, *jobj_type, *jobj_shift_size, *jobj_hash, *jobj_sector_size, *jobj_direction; ++ json_object *jobj_mode, *jobj_area, *jobj_type, *jobj_shift_size, *jobj_hash, *jobj_sector_size, *jobj_direction, *jobj_key_size; + const char *mode, *type, *direction; + uint32_t sector_size; + uint64_t shift_size; +@@ -250,12 +250,18 @@ static int reenc_keyslot_validate(struct crypt_device *cd, json_object *jobj_key + !json_object_object_get_ex(jobj_area, "type", &jobj_type)) + return -EINVAL; + ++ jobj_key_size = json_contains(cd, jobj_keyslot, "", "reencrypt keyslot", "key_size", json_type_int); + jobj_mode = json_contains(cd, jobj_keyslot, "", "reencrypt keyslot", "mode", json_type_string); + jobj_direction = json_contains(cd, jobj_keyslot, "", "reencrypt keyslot", "direction", json_type_string); + +- if (!jobj_mode || !jobj_direction) ++ if (!jobj_mode || !jobj_direction || !jobj_key_size) + return -EINVAL; + ++ if (!validate_json_uint32(jobj_key_size) || crypt_jobj_get_uint32(jobj_key_size) != 1) { ++ log_dbg(cd, "Illegal reencrypt key size."); ++ return -EINVAL; ++ } ++ + mode = json_object_get_string(jobj_mode); + type = json_object_get_string(jobj_type); + direction = json_object_get_string(jobj_direction); +-- +2.27.0 + diff --git a/SOURCES/cryptsetup-2.3.7-Rename-LUKS2_keyslot_reencrypt_create-function.patch b/SOURCES/cryptsetup-2.3.7-Rename-LUKS2_keyslot_reencrypt_create-function.patch new file mode 100644 index 0000000..f45d18e --- /dev/null +++ b/SOURCES/cryptsetup-2.3.7-Rename-LUKS2_keyslot_reencrypt_create-function.patch @@ -0,0 +1,46 @@ +diff -rupN cryptsetup-2.3.3.old/lib/luks2/luks2.h cryptsetup-2.3.3/lib/luks2/luks2.h +--- cryptsetup-2.3.3.old/lib/luks2/luks2.h 2022-01-17 16:17:59.479948764 +0100 ++++ cryptsetup-2.3.3/lib/luks2/luks2.h 2022-01-17 16:20:30.466477626 +0100 +@@ -284,7 +284,7 @@ int LUKS2_keyslot_reencrypt_store(struct + const void *buffer, + size_t buffer_length); + +-int LUKS2_keyslot_reencrypt_create(struct crypt_device *cd, ++int LUKS2_keyslot_reencrypt_allocate(struct crypt_device *cd, + struct luks2_hdr *hdr, + int keyslot, + const struct crypt_params_reencrypt *params); +diff -rupN cryptsetup-2.3.3.old/lib/luks2/luks2_keyslot.c cryptsetup-2.3.3/lib/luks2/luks2_keyslot.c +--- cryptsetup-2.3.3.old/lib/luks2/luks2_keyslot.c 2022-01-17 16:17:59.478948761 +0100 ++++ cryptsetup-2.3.3/lib/luks2/luks2_keyslot.c 2022-01-17 16:19:00.458162353 +0100 +@@ -596,7 +596,7 @@ int LUKS2_keyslot_open(struct crypt_devi + return r; + } + +-int LUKS2_keyslot_reencrypt_create(struct crypt_device *cd, ++int LUKS2_keyslot_reencrypt_allocate(struct crypt_device *cd, + struct luks2_hdr *hdr, + int keyslot, + const struct crypt_params_reencrypt *params) +@@ -626,9 +626,6 @@ int LUKS2_keyslot_reencrypt_create(struc + return r; + } + +- if (LUKS2_hdr_validate(cd, hdr->jobj, hdr->hdr_size - LUKS2_HDR_BIN_LEN)) +- return -EINVAL; +- + return 0; + } + +diff -rupN cryptsetup-2.3.3.old/lib/luks2/luks2_reencrypt.c cryptsetup-2.3.3/lib/luks2/luks2_reencrypt.c +--- cryptsetup-2.3.3.old/lib/luks2/luks2_reencrypt.c 2022-01-17 16:17:59.478948761 +0100 ++++ cryptsetup-2.3.3/lib/luks2/luks2_reencrypt.c 2022-01-17 16:19:00.459162357 +0100 +@@ -2375,7 +2375,7 @@ static int reencrypt_init(struct crypt_d + goto err; + } + +- r = LUKS2_keyslot_reencrypt_create(cd, hdr, reencrypt_keyslot, ++ r = LUKS2_keyslot_reencrypt_allocate(cd, hdr, reencrypt_keyslot, + params); + if (r < 0) + goto err; diff --git a/SOURCES/cryptsetup-2.3.7-Split-requirements-validation-from-config-section-va.patch b/SOURCES/cryptsetup-2.3.7-Split-requirements-validation-from-config-section-va.patch new file mode 100644 index 0000000..fa15843 --- /dev/null +++ b/SOURCES/cryptsetup-2.3.7-Split-requirements-validation-from-config-section-va.patch @@ -0,0 +1,57 @@ +From d0169a303de017ff0c847a5f752a2449a76fdd17 Mon Sep 17 00:00:00 2001 +From: Ondrej Kozina +Date: Thu, 6 Jan 2022 14:47:44 +0100 +Subject: [PATCH 17/28] Split requirements validation from config section + validation. + +--- + lib/luks2/luks2_json_metadata.c | 17 ++++++++++++++++- + 1 file changed, 16 insertions(+), 1 deletion(-) + +diff --git a/lib/luks2/luks2_json_metadata.c b/lib/luks2/luks2_json_metadata.c +index e45a9739..9109b07a 100644 +--- a/lib/luks2/luks2_json_metadata.c ++++ b/lib/luks2/luks2_json_metadata.c +@@ -855,9 +855,10 @@ static int hdr_validate_digests(struct crypt_device *cd, json_object *hdr_jobj) + return 0; + } + ++/* requirements being validated in stand-alone routine */ + static int hdr_validate_config(struct crypt_device *cd, json_object *hdr_jobj) + { +- json_object *jobj_config, *jobj, *jobj1; ++ json_object *jobj_config, *jobj; + int i; + uint64_t keyslots_size, metadata_size, segment_offset; + +@@ -912,6 +913,19 @@ static int hdr_validate_config(struct crypt_device *cd, json_object *hdr_jobj) + return 1; + } + ++ return 0; ++} ++ ++static int hdr_validate_requirements(struct crypt_device *cd, json_object *hdr_jobj) ++{ ++ int i; ++ json_object *jobj_config, *jobj, *jobj1; ++ ++ if (!json_object_object_get_ex(hdr_jobj, "config", &jobj_config)) { ++ log_dbg(cd, "Missing config section."); ++ return 1; ++ } ++ + /* Requirements object is optional */ + if (json_object_object_get_ex(jobj_config, "requirements", &jobj)) { + if (!json_contains(cd, jobj_config, "section", "Config", "requirements", json_type_object)) +@@ -937,6 +951,7 @@ int LUKS2_hdr_validate(struct crypt_device *cd, json_object *hdr_jobj, uint64_t + struct { + int (*validate)(struct crypt_device *, json_object *); + } checks[] = { ++ { hdr_validate_requirements }, + { hdr_validate_tokens }, + { hdr_validate_digests }, + { hdr_validate_segments }, +-- +2.27.0 + diff --git a/SOURCES/cryptsetup-Makefile-in.patch b/SOURCES/cryptsetup-Makefile-in.patch new file mode 100644 index 0000000..e17289b --- /dev/null +++ b/SOURCES/cryptsetup-Makefile-in.patch @@ -0,0 +1,74 @@ +diff -rupN cryptsetup-2.3.3.old/Makefile.in cryptsetup-2.3.3/Makefile.in +--- cryptsetup-2.3.3.old/Makefile.in 2020-05-28 11:32:48.000000000 +0200 ++++ cryptsetup-2.3.3/Makefile.in 2022-01-14 14:58:17.797173340 +0100 +@@ -292,6 +292,7 @@ am_libcryptsetup_la_OBJECTS = lib/libcry + lib/luks2/libcryptsetup_la-luks2_keyslot_luks2.lo \ + lib/luks2/libcryptsetup_la-luks2_keyslot_reenc.lo \ + lib/luks2/libcryptsetup_la-luks2_reencrypt.lo \ ++ lib/luks2/libcryptsetup_la-luks2_reencrypt_digest.lo \ + lib/luks2/libcryptsetup_la-luks2_segment.lo \ + lib/luks2/libcryptsetup_la-luks2_token_keyring.lo \ + lib/luks2/libcryptsetup_la-luks2_token.lo \ +@@ -530,6 +531,7 @@ am__depfiles_remade = lib/$(DEPDIR)/libc + lib/luks2/$(DEPDIR)/libcryptsetup_la-luks2_keyslot_reenc.Plo \ + lib/luks2/$(DEPDIR)/libcryptsetup_la-luks2_luks1_convert.Plo \ + lib/luks2/$(DEPDIR)/libcryptsetup_la-luks2_reencrypt.Plo \ ++ lib/luks2/$(DEPDIR)/libcryptsetup_la-luks2_reencrypt_digest.Plo \ + lib/luks2/$(DEPDIR)/libcryptsetup_la-luks2_segment.Plo \ + lib/luks2/$(DEPDIR)/libcryptsetup_la-luks2_token.Plo \ + lib/luks2/$(DEPDIR)/libcryptsetup_la-luks2_token_keyring.Plo \ +@@ -1005,6 +1009,7 @@ libcryptsetup_la_SOURCES = \ + lib/luks2/luks2_keyslot_luks2.c \ + lib/luks2/luks2_keyslot_reenc.c \ + lib/luks2/luks2_reencrypt.c \ ++ lib/luks2/luks2_reencrypt_digest.c \ + lib/luks2/luks2_segment.c \ + lib/luks2/luks2_token_keyring.c \ + lib/luks2/luks2_token.c \ +@@ -1493,6 +1498,8 @@ lib/luks2/libcryptsetup_la-luks2_keyslot + lib/luks2/$(am__dirstamp) lib/luks2/$(DEPDIR)/$(am__dirstamp) + lib/luks2/libcryptsetup_la-luks2_reencrypt.lo: \ + lib/luks2/$(am__dirstamp) lib/luks2/$(DEPDIR)/$(am__dirstamp) ++lib/luks2/libcryptsetup_la-luks2_reencrypt_digest.lo: \ ++ lib/luks2/$(am__dirstamp) lib/luks2/$(DEPDIR)/$(am__dirstamp) + lib/luks2/libcryptsetup_la-luks2_segment.lo: \ + lib/luks2/$(am__dirstamp) lib/luks2/$(DEPDIR)/$(am__dirstamp) + lib/luks2/libcryptsetup_la-luks2_token_keyring.lo: \ +@@ -1670,6 +1677,7 @@ distclean-compile: + @AMDEP_TRUE@@am__include@ @am__quote@lib/luks2/$(DEPDIR)/libcryptsetup_la-luks2_keyslot_reenc.Plo@am__quote@ # am--include-marker + @AMDEP_TRUE@@am__include@ @am__quote@lib/luks2/$(DEPDIR)/libcryptsetup_la-luks2_luks1_convert.Plo@am__quote@ # am--include-marker + @AMDEP_TRUE@@am__include@ @am__quote@lib/luks2/$(DEPDIR)/libcryptsetup_la-luks2_reencrypt.Plo@am__quote@ # am--include-marker ++@AMDEP_TRUE@@am__include@ @am__quote@lib/luks2/$(DEPDIR)/libcryptsetup_la-luks2_reencrypt_digest.Plo@am__quote@ # am--include-marker + @AMDEP_TRUE@@am__include@ @am__quote@lib/luks2/$(DEPDIR)/libcryptsetup_la-luks2_segment.Plo@am__quote@ # am--include-marker + @AMDEP_TRUE@@am__include@ @am__quote@lib/luks2/$(DEPDIR)/libcryptsetup_la-luks2_token.Plo@am__quote@ # am--include-marker + @AMDEP_TRUE@@am__include@ @am__quote@lib/luks2/$(DEPDIR)/libcryptsetup_la-luks2_token_keyring.Plo@am__quote@ # am--include-marker +@@ -2138,6 +2146,13 @@ lib/luks2/libcryptsetup_la-luks2_reencry + @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ + @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcryptsetup_la_CPPFLAGS) $(CPPFLAGS) $(libcryptsetup_la_CFLAGS) $(CFLAGS) -c -o lib/luks2/libcryptsetup_la-luks2_reencrypt.lo `test -f 'lib/luks2/luks2_reencrypt.c' || echo '$(srcdir)/'`lib/luks2/luks2_reencrypt.c + ++lib/luks2/libcryptsetup_la-luks2_reencrypt_digest.lo: lib/luks2/luks2_reencrypt_digest.c ++@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcryptsetup_la_CPPFLAGS) $(CPPFLAGS) $(libcryptsetup_la_CFLAGS) $(CFLAGS) -MT lib/luks2/libcryptsetup_la-luks2_reencrypt_digest.lo -MD -MP -MF lib/luks2/$(DEPDIR)/libcryptsetup_la-luks2_reencrypt_digest.Tpo -c -o lib/luks2/libcryptsetup_la-luks2_reencrypt_digest.lo `test -f 'lib/luks2/luks2_reencrypt_digest.c' || echo '$(srcdir)/'`lib/luks2/luks2_reencrypt_digest.c ++@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) lib/luks2/$(DEPDIR)/libcryptsetup_la-luks2_reencrypt_digest.Tpo lib/luks2/$(DEPDIR)/libcryptsetup_la-luks2_reencrypt_digest.Plo ++@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='lib/luks2/luks2_reencrypt_digest.c' object='lib/luks2/libcryptsetup_la-luks2_reencrypt_digest.lo' libtool=yes @AMDEPBACKSLASH@ ++@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ ++@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcryptsetup_la_CPPFLAGS) $(CPPFLAGS) $(libcryptsetup_la_CFLAGS) $(CFLAGS) -c -o lib/luks2/libcryptsetup_la-luks2_reencrypt_digest.lo `test -f 'lib/luks2/luks2_reencrypt_digest.c' || echo '$(srcdir)/'`lib/luks2/luks2_reencrypt_digest.c ++ + lib/luks2/libcryptsetup_la-luks2_segment.lo: lib/luks2/luks2_segment.c + @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcryptsetup_la_CPPFLAGS) $(CPPFLAGS) $(libcryptsetup_la_CFLAGS) $(CFLAGS) -MT lib/luks2/libcryptsetup_la-luks2_segment.lo -MD -MP -MF lib/luks2/$(DEPDIR)/libcryptsetup_la-luks2_segment.Tpo -c -o lib/luks2/libcryptsetup_la-luks2_segment.lo `test -f 'lib/luks2/luks2_segment.c' || echo '$(srcdir)/'`lib/luks2/luks2_segment.c + @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) lib/luks2/$(DEPDIR)/libcryptsetup_la-luks2_segment.Tpo lib/luks2/$(DEPDIR)/libcryptsetup_la-luks2_segment.Plo +@@ -2738,6 +2754,7 @@ distclean: distclean-recursive + -rm -f lib/luks2/$(DEPDIR)/libcryptsetup_la-luks2_keyslot_reenc.Plo + -rm -f lib/luks2/$(DEPDIR)/libcryptsetup_la-luks2_luks1_convert.Plo + -rm -f lib/luks2/$(DEPDIR)/libcryptsetup_la-luks2_reencrypt.Plo ++ -rm -f lib/luks2/$(DEPDIR)/libcryptsetup_la-luks2_reencrypt_digest.Plo + -rm -f lib/luks2/$(DEPDIR)/libcryptsetup_la-luks2_segment.Plo + -rm -f lib/luks2/$(DEPDIR)/libcryptsetup_la-luks2_token.Plo + -rm -f lib/luks2/$(DEPDIR)/libcryptsetup_la-luks2_token_keyring.Plo +@@ -2864,6 +2881,7 @@ maintainer-clean: maintainer-clean-recur + -rm -f lib/luks2/$(DEPDIR)/libcryptsetup_la-luks2_keyslot_reenc.Plo + -rm -f lib/luks2/$(DEPDIR)/libcryptsetup_la-luks2_luks1_convert.Plo + -rm -f lib/luks2/$(DEPDIR)/libcryptsetup_la-luks2_reencrypt.Plo ++ -rm -f lib/luks2/$(DEPDIR)/libcryptsetup_la-luks2_reencrypt_digest.Plo + -rm -f lib/luks2/$(DEPDIR)/libcryptsetup_la-luks2_segment.Plo + -rm -f lib/luks2/$(DEPDIR)/libcryptsetup_la-luks2_token.Plo + -rm -f lib/luks2/$(DEPDIR)/libcryptsetup_la-luks2_token_keyring.Plo diff --git a/SOURCES/cryptsetup-tests-Makefile-in.patch b/SOURCES/cryptsetup-tests-Makefile-in.patch new file mode 100644 index 0000000..e913449 --- /dev/null +++ b/SOURCES/cryptsetup-tests-Makefile-in.patch @@ -0,0 +1,19 @@ +diff -rupN cryptsetup-2.3.3.old/tests/Makefile.in cryptsetup-2.3.3/tests/Makefile.in +--- cryptsetup-2.3.3.old/tests/Makefile.in 2022-01-14 16:25:59.283158424 +0100 ++++ cryptsetup-2.3.3/tests/Makefile.in 2022-01-14 16:27:15.094215021 +0100 +@@ -441,6 +441,7 @@ EXTRA_DIST = compatimage.img.xz compatv1 + reencryption-compat-test \ + reencryption-compat-test2 \ + luks2-reencryption-test \ ++ luks2-reencryption-mangle-test \ + tcrypt-compat-test \ + luks1-compat-test \ + luks2-validation-test generators \ +@@ -1023,6 +1024,7 @@ valgrind-check: api-test api-test-2 diff + @INFOSTRING="api-test-000" ./valg-api.sh ./api-test + @INFOSTRING="api-test-002" ./valg-api.sh ./api-test-2 + @VALG=1 ./luks2-reencryption-test ++ @VALG=1 ./luks2-reencryption-mangle-test + @VALG=1 ./compat-test + + .PHONY: valgrind-check diff --git a/SPECS/cryptsetup.spec b/SPECS/cryptsetup.spec index aedeee3..b18c126 100644 --- a/SPECS/cryptsetup.spec +++ b/SPECS/cryptsetup.spec @@ -5,7 +5,7 @@ Obsoletes: cryptsetup-python3 Summary: A utility for setting up encrypted disks Name: cryptsetup Version: 2.3.3 -Release: 4%{?dist} +Release: 4%{?dist}.1 License: GPLv2+ and LGPLv2+ Group: Applications/System URL: https://gitlab.com/cryptsetup/cryptsetup @@ -27,6 +27,24 @@ Patch2: %{name}-2.3.4-luks2-validation-32bit-fix.patch Patch3: %{name}-2.3.4-fix-crypto-backend-to-properly-handle-ECB-mode.patch Patch4: %{name}-2.3.5-fix-reencryption-cipher_null.patch +# CVE-2021-4122 fix +Patch5: %{name}-2.3.7-Fix-CVE-2021-4122-LUKS2-reencryption-crash-recovery-.patch +Patch6: %{name}-2.3.7-Reenc-keyslot-must-have-key_size-1.patch +Patch7: %{name}-2.3.7-Do-not-run-reencryption-recovery-when-not-needed.patch +Patch8: %{name}-2.3.7-Move-requirement-helpers-for-later-changes.patch +Patch9: %{name}-2.3.7-Expose-json_segment_contains_flag-to-internal-librar.patch +Patch10: %{name}-2.3.7-Split-requirements-validation-from-config-section-va.patch +Patch11: %{name}-2.3.7-Add-segments-validation-for-reencryption.patch +Patch12: %{name}-2.3.7-Rename-LUKS2_keyslot_reencrypt_create-function.patch +Patch13: %{name}-2.3.7-Make-reencryption-flag-and-keyslot-inseparable.patch +Patch14: %{name}-2.3.7-Add-reencryption-mangle-test.patch +# cryptsetup manual repair command able to upgrade/verify reencryption metadata +Patch15: %{name}-2.3.7-Add-CRYPT_REENCRYPT_REPAIR_NEEDED-flag.patch +Patch16: %{name}-2.3.7-Allow-reencryption-metadata-repair-from-cryptsetup.patch +Patch17: %{name}-2.3.7-Fix-reencrypt-mangle-test-for-older-jq.patch +Patch18: %{name}-Makefile-in.patch +Patch19: %{name}-tests-Makefile-in.patch + %description The cryptsetup package contains a utility for setting up disk encryption using dm-crypt kernel module. @@ -85,8 +103,24 @@ can be used for offline reencryption of disk in situ. %patch2 -p1 %patch3 -p1 %patch4 -p1 +%patch5 -p1 +%patch6 -p1 +%patch7 -p1 +%patch8 -p1 +%patch9 -p1 +%patch10 -p1 +%patch11 -p1 +%patch12 -p1 +%patch13 -p1 +%patch14 -p1 +%patch15 -p1 +%patch16 -p1 +%patch17 -p1 +%patch18 -p1 +%patch19 -p1 %patch0 -p1 chmod -x misc/dracut_90reencrypt/* +chmod +x tests/luks2-reencryption-mangle-test %build %configure --enable-fips --enable-pwquality --enable-internal-sse-argon2 --with-crypto_backend=openssl --with-default-luks-format=LUKS2 @@ -144,6 +178,10 @@ rm -rf %{buildroot}/%{_libdir}/*.la %clean %changelog +* Fri Jan 14 2022 Ondrej Kozina - 2.3.3-4.1 +- patch: fix CVE-2021-4122. +- Resolves: #2036906 + * Wed Feb 17 2021 Ondrej Kozina - 2.3.3-4 - patch: Fix reencryption for custom devices with data segments set to use cipher_null.