220 lines
7.1 KiB
Diff
220 lines
7.1 KiB
Diff
|
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 <<EOF
|
||
|
+proc abort {} { send_error "Timeout. "; exit 42 }
|
||
|
+set timeout $EXPECT_TIMEOUT
|
||
|
+eval spawn $CRYPTSETUP_RAW reencrypt $IMG $CS_PWPARAMS --disable-locks
|
||
|
+expect timeout abort "Are you sure? (Type 'yes' in capital letters):"
|
||
|
+send "YES\n"
|
||
|
+expect timeout abort eof
|
||
|
+catch wait result
|
||
|
+exit [lindex \$result 3]
|
||
|
+EOF
|
||
|
+local ret=$?
|
||
|
+[ $ret -eq 0 ] && fail "Reencryption passed (should have failed)."
|
||
|
+[ $ret -eq 42 ] && fail "Expect script failed."
|
||
|
+img_hash_unchanged
|
||
|
+}
|
||
|
+
|
||
|
+function img_check_fail_repair_ok()
|
||
|
+{
|
||
|
+ if [ $(id -u) == 0 ]; then
|
||
|
+ $CRYPTSETUP open $CS_PWPARAMS $IMG $DEV_NAME 2>/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)'
|