fix recovery of LUKS encrypted systems with multiple keyslots
Resolves: RHEL-106762
This commit is contained in:
parent
92d1a3ed37
commit
cef3700c9e
165
rear-support-multi-keyslot-luks-RHEL-83776.patch
Normal file
165
rear-support-multi-keyslot-luks-RHEL-83776.patch
Normal file
@ -0,0 +1,165 @@
|
||||
From e9ce93f096e505968cc728a7eb5a06e25dc8d88b Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Renaud=20M=C3=A9trich?=
|
||||
<1163635+rmetrich@users.noreply.github.com>
|
||||
Date: Fri, 27 Jun 2025 14:39:01 +0200
|
||||
Subject: [PATCH] LUKS2: try to handle multiple key slots (#3430)
|
||||
|
||||
LUKS2: try to handle multiple key slots:
|
||||
The current code doesn't deal properly with multiple key slots nor
|
||||
extracts the Hash that was used at LUKS creation properly.
|
||||
With current code, when multiple key slots are found or PBKDF algorithm
|
||||
is "pbkdf2" (instead of default "argon2id"), the disk layout file
|
||||
contains 2 lines for 'crypt' parameters, causing havoc during recovery.
|
||||
This new code tries to do better:
|
||||
It searches for the Hash in Keyslots section only
|
||||
(and falls back to Digests section if not found).
|
||||
It warns the admin if multiple keyslots are in use
|
||||
(e.g. because of multiple passphrases or Clevis binding).
|
||||
It handles the PBKDF algorithm.
|
||||
It makes sure that the 'crypt' parameters are always on one line.
|
||||
---
|
||||
doc/user-guide/06-layout-configuration.adoc | 2 +-
|
||||
.../GNU/Linux/160_include_luks_code.sh | 3 +
|
||||
.../layout/save/GNU/Linux/260_crypt_layout.sh | 69 ++++++++++++++++---
|
||||
3 files changed, 62 insertions(+), 12 deletions(-)
|
||||
|
||||
diff --git a/doc/user-guide/06-layout-configuration.adoc b/doc/user-guide/06-layout-configuration.adoc
|
||||
index d2a0a4c8b9..f1f4a47326 100644
|
||||
--- a/doc/user-guide/06-layout-configuration.adoc
|
||||
+++ b/doc/user-guide/06-layout-configuration.adoc
|
||||
@@ -666,7 +666,7 @@ lvmvol <volume_group> <name> <size(bytes)> <layout> [key:value ...]
|
||||
|
||||
=== LUKS Devices ===
|
||||
----------------------------------
|
||||
-crypt /dev/mapper/<name> <device> [type=<type>] [cipher=<cipher>] [key_size=<key size>] [hash=<hash function>] [uuid=<uuid>] [keyfile=<keyfile>] [password=<password>]
|
||||
+crypt /dev/mapper/<name> <device> [type=<type>] [cipher=<cipher>] [key_size=<key size>] [hash=<hash function>] [uuid=<uuid>] [pbkdf=<pbkdf algo> ] [keyfile=<keyfile>] [password=<password>]
|
||||
----------------------------------
|
||||
|
||||
=== DRBD ===
|
||||
diff --git a/usr/share/rear/layout/prepare/GNU/Linux/160_include_luks_code.sh b/usr/share/rear/layout/prepare/GNU/Linux/160_include_luks_code.sh
|
||||
index 0c662f6770..3b0b34cd12 100644
|
||||
--- a/usr/share/rear/layout/prepare/GNU/Linux/160_include_luks_code.sh
|
||||
+++ b/usr/share/rear/layout/prepare/GNU/Linux/160_include_luks_code.sh
|
||||
@@ -62,6 +62,9 @@ create_crypt() {
|
||||
(uuid)
|
||||
test $value && cryptsetup_options+=" --uuid $value"
|
||||
;;
|
||||
+ (pbkdf)
|
||||
+ test $value && cryptsetup_options+=" --pbkdf $value"
|
||||
+ ;;
|
||||
(keyfile)
|
||||
test $value && keyfile=$value
|
||||
;;
|
||||
diff --git a/usr/share/rear/layout/save/GNU/Linux/260_crypt_layout.sh b/usr/share/rear/layout/save/GNU/Linux/260_crypt_layout.sh
|
||||
index 7410165a5e..c3470f3244 100644
|
||||
--- a/usr/share/rear/layout/save/GNU/Linux/260_crypt_layout.sh
|
||||
+++ b/usr/share/rear/layout/save/GNU/Linux/260_crypt_layout.sh
|
||||
@@ -61,31 +61,73 @@ while read target_name junk ; do
|
||||
fi
|
||||
luks_type=luks$version
|
||||
|
||||
+ luksDump_cmd="cryptsetup luksDump $source_device"
|
||||
+
|
||||
# Gather crypt information:
|
||||
- if ! cryptsetup luksDump $source_device >$TMP_DIR/cryptsetup.luksDump ; then
|
||||
- LogPrintError "Error: Cannot get LUKS$version values for $target_name ('cryptsetup luksDump $source_device' failed)"
|
||||
+ if ! $luksDump_cmd >$TMP_DIR/cryptsetup.luksDump ; then
|
||||
+ LogPrintError "Error: Cannot get LUKS$version values for $target_name ('$luksDump_cmd' failed)"
|
||||
continue
|
||||
fi
|
||||
+
|
||||
uuid=$( grep "UUID" $TMP_DIR/cryptsetup.luksDump | sed -r 's/^.+:\s*(.+)$/\1/' )
|
||||
keyfile_option=$( [ -f /etc/crypttab ] && awk '$1 == "'"$target_name"'" && $3 != "none" && $3 != "-" && $3 != "" { print "keyfile=" $3; }' /etc/crypttab )
|
||||
+ pbkdf_option=""
|
||||
+
|
||||
if test $luks_type = "luks1" ; then
|
||||
+
|
||||
cipher_name=$( grep "Cipher name" $TMP_DIR/cryptsetup.luksDump | sed -r 's/^.+:\s*(.+)$/\1/' )
|
||||
cipher_mode=$( grep "Cipher mode" $TMP_DIR/cryptsetup.luksDump | cut -d: -f2- | awk '{printf("%s",$1)};' )
|
||||
cipher=$cipher_name-$cipher_mode
|
||||
key_size=$( grep "MK bits" $TMP_DIR/cryptsetup.luksDump | sed -r 's/^.+:\s*(.+)$/\1/' )
|
||||
hash=$( grep "Hash spec" $TMP_DIR/cryptsetup.luksDump | sed -r 's/^.+:\s*(.+)$/\1/' )
|
||||
+
|
||||
elif test $luks_type = "luks2" ; then
|
||||
- cipher=$( grep "cipher:" $TMP_DIR/cryptsetup.luksDump | sed -r 's/^.+:\s*(.+)$/\1/' )
|
||||
- # More than one keyslot may be defined - use key_size from the first slot.
|
||||
+
|
||||
+ keyslots_section=$( awk '/^Keyslots:/ {include=1;next} /^[[:upper:]]/ && include {exit} include' $TMP_DIR/cryptsetup.luksDump )
|
||||
+ if [ -z "$keyslots_section" ]; then
|
||||
+ LogPrintError "Error: No Keyslots section found in '$luksDump_cmd' output"
|
||||
+ continue
|
||||
+ fi
|
||||
+ if [ $( grep -c -P '^\s+\d+: luks2' <<< "$keyslots_section" ) -gt 1 ]; then
|
||||
+ LogPrintError "Warning: More than one luks2 keyslot found in '$luksDump_cmd' output, will only consider the first keyslot during recovery"
|
||||
+ fi
|
||||
+ luks2_section=$( awk '/^[[:blank:]]+[[:digit:]]+:/ && include {exit} /^[[:blank:]]+[[:digit:]]+: luks2/{include=1} include' <<< "$keyslots_section")
|
||||
+
|
||||
+ cipher=$( grep "Cipher:" <<< "$luks2_section" | sed -r 's/^.+:\s*(.+)$/\1/' )
|
||||
+ pbkdf=$( grep "PBKDF:" <<< "$luks2_section" | sed -r 's/^.+:\s*(.+)$/\1/' )
|
||||
+ if [ -z "$pbkdf" ]; then
|
||||
+ LogPrintError "Warning: no PBKDF found in luks2 keyslot of '$luksDump_cmd' output, will use defaults during recovery"
|
||||
+ else
|
||||
+ pbkdf_option="pbkdf=$pbkdf"
|
||||
+ fi
|
||||
+
|
||||
# Depending on the version the "cryptsetup luksDump" command outputs the key_size value
|
||||
# as a line like
|
||||
# Key: 512 bits
|
||||
# and/or as a line like
|
||||
# Cipher key: 512 bits
|
||||
# cf. https://github.com/rear/rear/pull/2504#issuecomment-718729198 and subsequent comments
|
||||
- # so we grep for both lines but use only the first match from the first slot:
|
||||
- key_size=$( grep -E -m 1 "Key:|Cipher key:" $TMP_DIR/cryptsetup.luksDump | sed -r 's/^.+:\s*(.+) bits$/\1/' )
|
||||
- hash=$( grep "Hash" $TMP_DIR/cryptsetup.luksDump | sed -r 's/^.+:\s*(.+)$/\1/' )
|
||||
+ key_size=$( grep -E "Key:|Cipher key:" <<< "$luks2_section" | sed -r 's/^.+:\s*(.+) bits$/\1/' | sort -u )
|
||||
+ if [ -z "$key_size" ]; then
|
||||
+ LogPrintError "Error: No key size found in luks2 keyslot of '$luksDump_cmd' output"
|
||||
+ elif [ $( wc -w <<< "$key_size" ) -gt 1 ]; then
|
||||
+ LogPrintError "Error: Too many key sizes found in luks2 keyslot of '$luksDump_cmd' output"
|
||||
+ key_size=""
|
||||
+ fi
|
||||
+
|
||||
+ hash=$( grep "AF hash:" <<< "$luks2_section" | sed -r 's/^.+:\s*(.+)$/\1/' )
|
||||
+ if [ -z "$hash" ]; then
|
||||
+ # Fallback to using Hash field found in Digests section
|
||||
+ digests_section=$( awk '/^Digests:/ {include=1;next} /^[[:upper:]]/ && include {exit} include' $TMP_DIR/cryptsetup.luksDump )
|
||||
+ hash=$( grep "Hash:" <<< "$digests_section" | sed -r 's/^.+:\s*(.+)$/\1/' | sort -u )
|
||||
+ if [ -z "$hash" ]; then
|
||||
+ LogPrintError "Warning: No Hash found in Digests section of '$luksDump_cmd' output, will use default type during recovery"
|
||||
+ elif [ $( wc -w <<< "$hash" ) -gt 1 ]; then
|
||||
+ hash=$( head -1 <<< "$hash" )
|
||||
+ LogPrintError "Warning: Too many Hash found in Digests section of '$luksDump_cmd' output, will use '$hash' during recovery"
|
||||
+ fi
|
||||
+ fi
|
||||
+
|
||||
fi
|
||||
|
||||
# Basic checks that the cipher key_size hash uuid values exist
|
||||
@@ -95,9 +137,9 @@ while read target_name junk ; do
|
||||
# and it seems cryptsetup fails when options with empty values are specified
|
||||
# cf. https://github.com/rear/rear/pull/2504#issuecomment-719479724
|
||||
# For example a LUKS1 crypt entry in disklayout.conf looks like
|
||||
- # crypt /dev/mapper/luks1test /dev/sda7 type=luks1 cipher=aes-xts-plain64 key_size=256 hash=sha256 uuid=1b4198c9-d9b0-4c57-b9a3-3433e391e706
|
||||
- # and a LUKS1 crypt entry in disklayout.conf looks like
|
||||
- # crypt /dev/mapper/luks2test /dev/sda8 type=luks2 cipher=aes-xts-plain64 key_size=256 hash=sha256 uuid=3e874a28-7415-4f8c-9757-b3f28a96c4d2
|
||||
+ # crypt /dev/mapper/luks1test /dev/sda7 type=luks1 cipher=aes-xts-plain64 key_size=256 hash=sha256 uuid=1b4198c9-d9b0-4c57-b9a3-3433e391e706
|
||||
+ # and a LUKS2 crypt entry in disklayout.conf looks like
|
||||
+ # crypt /dev/mapper/luks2test /dev/sda8 type=luks2 cipher=aes-xts-plain64 key_size=256 hash=sha256 uuid=3e874a28-7415-4f8c-9757-b3f28a96c4d2 pbkdf=argon2id
|
||||
# Only the keyfile_option value is optional and the luks_type value is already tested above.
|
||||
# Using plain test to ensure a value is a single non empty and non blank word
|
||||
# without quoting because test " " would return zero exit code
|
||||
@@ -127,7 +169,12 @@ while read target_name junk ; do
|
||||
LogPrintError "Error: No 'uuid' value for LUKS$version volume $target_name in $source_device (mounting it or booting the recreated system may fail)"
|
||||
fi
|
||||
|
||||
- echo "crypt /dev/mapper/$target_name $source_device type=$luks_type cipher=$cipher key_size=$key_size hash=$hash uuid=$uuid $keyfile_option" >> $DISKLAYOUT_FILE
|
||||
+ {
|
||||
+ echo -n "crypt /dev/mapper/$target_name $source_device type=$luks_type cipher=$cipher key_size=$key_size hash=$hash uuid=$uuid"
|
||||
+ [ -n "$keyfile_option" ] && echo -n " $keyfile_option"
|
||||
+ [ -n "$pbkdf_option" ] && echo -n " $pbkdf_option"
|
||||
+ echo
|
||||
+ } >> $DISKLAYOUT_FILE
|
||||
|
||||
done < <( dmsetup ls --target crypt )
|
||||
|
||||
|
||||
@ -34,6 +34,10 @@ Patch122: rear-skip-longhorn-iscsi-RHEL-83551.patch
|
||||
# https://github.com/rear/rear/commit/1ca518c2a0e675ace956ef71bc79d67e4990562b
|
||||
Patch123: rear-detect-prep-boot-on-gpt-RHEL-82098.patch
|
||||
|
||||
# fix recovery of LUKS encrypted systems with multiple keyslots
|
||||
# https://github.com/rear/rear/commit/e9ce93f096e505968cc728a7eb5a06e25dc8d88b
|
||||
Patch124: rear-support-multi-keyslot-luks-RHEL-83776.patch
|
||||
|
||||
######################
|
||||
# downstream patches #
|
||||
######################
|
||||
|
||||
Loading…
Reference in New Issue
Block a user