From 121991d7592d36c4167347a8b818dc2138eaaccf Mon Sep 17 00:00:00 2001 From: Thierry Laurion Date: Wed, 17 Jan 2024 13:29:45 -0500 Subject: [PATCH 01/10] WiP: Suggest all lvms/luks partitions in staing<->array conversion Signed-off-by: Thierry Laurion --- initrd/bin/kexec-save-default | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/initrd/bin/kexec-save-default b/initrd/bin/kexec-save-default index e21dd13ea..ba8b15dbd 100755 --- a/initrd/bin/kexec-save-default +++ b/initrd/bin/kexec-save-default @@ -50,9 +50,12 @@ lvm_suggest=$(echo $lvm_suggest | tr '\n' ' ') DEBUG "LVM num_lvm: $num_lvm, lvm_suggest: $lvm_suggest" # get all LUKS container devices -devices_suggest=$(blkid | cut -d ':' -f 1 | while read device; do +# Here: devices suggest has many devices. /dev/sda is BRTFS QubesOS install and /dev/sdb is internal backup +# BRTFS: /dev/sda2 /dev/sda3 /dev/sdc2 +# read -r: doesn't escape on backslash +devices_suggest=$(blkid | cut -d ':' -f 1 | while read -r device; do if cryptsetup isLuks "$device"; then echo "$device"; fi -done | sort) +done | tr '\n' ' ' | sort) num_devices=$(echo "$devices_suggest" | wc -l) if [ "$num_devices" -eq 1 ] && [ -s "$devices_suggest" ]; then @@ -61,7 +64,7 @@ elif [ -z "$devices_suggest" ]; then num_devices=0 fi # $devices_suggest is a multiline string, we need to convert it to a space separated string -devices_suggest=$(echo $devices_suggest | tr '\n' ' ') +#devices_suggest=$(echo $devices_suggest | tr '\n' ' ') DEBUG "LUKS num_devices: $num_devices, devices_suggest: $devices_suggest" if [ "$num_lvm" -eq 0 ] && [ "$num_devices" -eq 0 ]; then @@ -78,7 +81,7 @@ prompt_for_existing_encrypted_lvms_or_disks() { declare -A lvms_array # Loop through the suggested LVMs and add them to the array for lvm in $lvm_suggest; do - lvms_array[$lvm]=$lvm + lvms_array["$lvm"]=$lvm done # Get the number of suggested LVMs @@ -116,6 +119,9 @@ prompt_for_existing_encrypted_lvms_or_disks() { fi } done + # Update lvm_suggest with the selected LVMs + lvm_suggest="${key_lvms_array[@]}" + elif [ "$num_lvms" -eq 1 ]; then echo "Single Encrypted LVM found at $lvm_suggest." key_lvms=$lvm_suggest @@ -127,11 +133,12 @@ prompt_for_existing_encrypted_lvms_or_disks() { declare -A devices_array # Loop through the suggested devices and add them to the array for device in $devices_suggest; do - devices_array[$device]=$device + devices_array["$device"]=$device done - # Get the number of suggested devices + DEBUG "LUKS num_devices before array: $num_devices, devices_array: ${devices_array[@]}" num_devices=${#devices_array[@]} + DEBUG "LUKS num_devices after array: $num_devices, devices_array: ${devices_array[@]}" if [ "$num_devices" -gt 1 ]; then DEBUG "Multiple LUKS devices found: $devices_suggest" @@ -165,15 +172,16 @@ prompt_for_existing_encrypted_lvms_or_disks() { fi } done + # Update devices_suggest with the selected devices + devices_suggest="${key_devices_array[@]}" + DEBUG "devices_suggest: $devices_suggest, key_devices: $key_devices, key_devices_array: ${key_devices_array[@]}" + DEBUG "Multiple LUKS devices selected: $key_devices" elif [ "$num_devices" -eq 1 ]; then echo "Single Encrypted Disk found at $devices_suggest." key_devices=$devices_suggest else echo "No encrypted devices found." fi - - DEBUG "Multiple LUKS devices selected: $key_devices" - } if [ ! -r "$TMP_MENU_FILE" ]; then From 4759e73fae8ac0d04a4da80e42d7d568a02b7e9d Mon Sep 17 00:00:00 2001 From: Thierry Laurion Date: Wed, 17 Jan 2024 13:37:38 -0500 Subject: [PATCH 02/10] WiP: Suggest all lvms/luks partitions in staing<->array conversion Signed-off-by: Thierry Laurion --- initrd/bin/kexec-save-default | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/initrd/bin/kexec-save-default b/initrd/bin/kexec-save-default index ba8b15dbd..a331fe236 100755 --- a/initrd/bin/kexec-save-default +++ b/initrd/bin/kexec-save-default @@ -50,12 +50,9 @@ lvm_suggest=$(echo $lvm_suggest | tr '\n' ' ') DEBUG "LVM num_lvm: $num_lvm, lvm_suggest: $lvm_suggest" # get all LUKS container devices -# Here: devices suggest has many devices. /dev/sda is BRTFS QubesOS install and /dev/sdb is internal backup -# BRTFS: /dev/sda2 /dev/sda3 /dev/sdc2 -# read -r: doesn't escape on backslash -devices_suggest=$(blkid | cut -d ':' -f 1 | while read -r device; do +devices_suggest=$(blkid | cut -d ':' -f 1 | while read device; do if cryptsetup isLuks "$device"; then echo "$device"; fi -done | tr '\n' ' ' | sort) +done | sort) num_devices=$(echo "$devices_suggest" | wc -l) if [ "$num_devices" -eq 1 ] && [ -s "$devices_suggest" ]; then @@ -64,7 +61,7 @@ elif [ -z "$devices_suggest" ]; then num_devices=0 fi # $devices_suggest is a multiline string, we need to convert it to a space separated string -#devices_suggest=$(echo $devices_suggest | tr '\n' ' ') +devices_suggest=$(echo $devices_suggest | tr '\n' ' ') DEBUG "LUKS num_devices: $num_devices, devices_suggest: $devices_suggest" if [ "$num_lvm" -eq 0 ] && [ "$num_devices" -eq 0 ]; then @@ -119,9 +116,6 @@ prompt_for_existing_encrypted_lvms_or_disks() { fi } done - # Update lvm_suggest with the selected LVMs - lvm_suggest="${key_lvms_array[@]}" - elif [ "$num_lvms" -eq 1 ]; then echo "Single Encrypted LVM found at $lvm_suggest." key_lvms=$lvm_suggest @@ -172,8 +166,6 @@ prompt_for_existing_encrypted_lvms_or_disks() { fi } done - # Update devices_suggest with the selected devices - devices_suggest="${key_devices_array[@]}" DEBUG "devices_suggest: $devices_suggest, key_devices: $key_devices, key_devices_array: ${key_devices_array[@]}" DEBUG "Multiple LUKS devices selected: $key_devices" elif [ "$num_devices" -eq 1 ]; then From 0b660305b1b483b13407d4c562618ea41b940160 Mon Sep 17 00:00:00 2001 From: Thierry Laurion Date: Wed, 17 Jan 2024 14:02:29 -0500 Subject: [PATCH 03/10] WiP: Suggest all lvms/luks partitions in staing<->array conversion Move function on top of file, first pass to replace strings with array and deal with arrays only. Signed-off-by: Thierry Laurion --- initrd/bin/kexec-save-default | 167 +++++++++++++++++++--------------- prompt | 25 +++++ 2 files changed, 117 insertions(+), 75 deletions(-) create mode 100644 prompt diff --git a/initrd/bin/kexec-save-default b/initrd/bin/kexec-save-default index a331fe236..285c50f8e 100755 --- a/initrd/bin/kexec-save-default +++ b/initrd/bin/kexec-save-default @@ -1,7 +1,9 @@ #!/bin/bash # Save these options to be the persistent default set -e -o pipefail +# shellcheck disable=SC1091 . /tmp/config +# shellcheck disable=SC1091 . /etc/functions TRACE "Under /bin/kexec-save-default" @@ -12,6 +14,7 @@ while getopts "b:d:p:i:" arg; do d) paramsdev="$OPTARG" ;; p) paramsdir="$OPTARG" ;; i) index="$OPTARG" ;; + *) echo "Invalid flag: -$OPTARG" >&2 ;; esac done @@ -38,46 +41,15 @@ PRIMHASH_FILE="$paramsdir/kexec_primhdl_hash.txt" KEY_DEVICES="$paramsdir/kexec_key_devices.txt" KEY_LVM="$paramsdir/kexec_key_lvm.txt" -lvm_suggest=$(lvm vgscan | awk -F '"' {'print $1'} | tail -n +2) -num_lvm=$(echo "$lvm_suggest" | wc -l) -if [ "$num_lvm" -eq 1 ] && [ -n "$lvm_suggest" ]; then - lvm_volume_group="$lvm_suggest" -elif [ -z "$lvm_suggest" ]; then - num_lvm=0 -fi -# $lvm_suggest is a multiline string, we need to convert it to a space separated string -lvm_suggest=$(echo $lvm_suggest | tr '\n' ' ') -DEBUG "LVM num_lvm: $num_lvm, lvm_suggest: $lvm_suggest" - -# get all LUKS container devices -devices_suggest=$(blkid | cut -d ':' -f 1 | while read device; do - if cryptsetup isLuks "$device"; then echo "$device"; fi -done | sort) -num_devices=$(echo "$devices_suggest" | wc -l) - -if [ "$num_devices" -eq 1 ] && [ -s "$devices_suggest" ]; then - key_devices=$devices_suggest -elif [ -z "$devices_suggest" ]; then - num_devices=0 -fi -# $devices_suggest is a multiline string, we need to convert it to a space separated string -devices_suggest=$(echo $devices_suggest | tr '\n' ' ') -DEBUG "LUKS num_devices: $num_devices, devices_suggest: $devices_suggest" - -if [ "$num_lvm" -eq 0 ] && [ "$num_devices" -eq 0 ]; then - #No encrypted partition found. - no_encrypted_partition=1 -fi - #Reusable function when user wants to define new TPM DUK for lvms/disks prompt_for_existing_encrypted_lvms_or_disks() { TRACE "Under kexec-save-default:prompt_for_existing_encrypted_lvms_or_disks" - DEBUG "num_lvm: $num_lvm, lvm_suggest: $lvm_suggest, num_devices: $num_devices, devices_suggest: $devices_suggest" + DEBUG "num_lvm: $num_lvm, lvm_suggest: ${lvm_suggest[*]}, num_devices: $num_devices, devices_suggest: ${devices_suggest[*]}" # Create an associative array to store the suggested LVMs and their paths declare -A lvms_array # Loop through the suggested LVMs and add them to the array - for lvm in $lvm_suggest; do + for lvm in ${lvm_suggest[@]}; do lvms_array["$lvm"]=$lvm done @@ -85,7 +57,7 @@ prompt_for_existing_encrypted_lvms_or_disks() { num_lvms=${#lvms_array[@]} if [ "$num_lvms" -gt 1 ]; then - DEBUG "Multiple LVMs found: $lvm_suggest" + DEBUG "Multiple LVMs found: ${lvm_suggest[*]}" selected_lvms_not_existing=1 # Create an array to store the selected LVMs declare -a key_lvms_array @@ -94,7 +66,7 @@ prompt_for_existing_encrypted_lvms_or_disks() { { # Read the user input and store it in a variable read \ - -p "Encrypted LVMs? (choose between/all: $lvm_suggest): " \ + -p "Encrypted LVMs? (choose between/all: ${lvm_suggest[*]}): " \ key_lvms # Split the user input by spaces and add each element to the array @@ -117,8 +89,8 @@ prompt_for_existing_encrypted_lvms_or_disks() { } done elif [ "$num_lvms" -eq 1 ]; then - echo "Single Encrypted LVM found at $lvm_suggest." - key_lvms=$lvm_suggest + echo "Single Encrypted LVM found at ${lvm_suggest[*]}." + key_lvms=("${lvm_suggest[@]}") else echo "No encrypted LVMs found." fi @@ -126,16 +98,16 @@ prompt_for_existing_encrypted_lvms_or_disks() { # Create an associative array to store the suggested devices and their paths declare -A devices_array # Loop through the suggested devices and add them to the array - for device in $devices_suggest; do + for device in ${devices_suggest[@]}; do devices_array["$device"]=$device done - DEBUG "LUKS num_devices before array: $num_devices, devices_array: ${devices_array[@]}" + DEBUG "LUKS num_devices before array: $num_devices, devices_array: ${devices_array[*]}" num_devices=${#devices_array[@]} - DEBUG "LUKS num_devices after array: $num_devices, devices_array: ${devices_array[@]}" + DEBUG "LUKS num_devices after array: $num_devices, devices_array: ${devices_array[*]}" if [ "$num_devices" -gt 1 ]; then - DEBUG "Multiple LUKS devices found: $devices_suggest" + DEBUG "Multiple LUKS devices found: ${devices_suggest[*]}" selected_luksdevs_not_existing=1 # Create an array to store the selected devices declare -a key_devices_array @@ -144,7 +116,7 @@ prompt_for_existing_encrypted_lvms_or_disks() { { # Read the user input and store it in a variable read \ - -p "Encrypted devices? (choose between/all: $devices_suggest): " \ + -p "Encrypted devices? (choose between/all: ${devices_suggest[*]}): " \ key_devices # Split the user input by spaces and add each element to the array @@ -166,16 +138,54 @@ prompt_for_existing_encrypted_lvms_or_disks() { fi } done - DEBUG "devices_suggest: $devices_suggest, key_devices: $key_devices, key_devices_array: ${key_devices_array[@]}" + DEBUG "devices_suggest: ${devices_suggest[*]}, key_devices: $key_devices, key_devices_array: ${key_devices_array[*]}" DEBUG "Multiple LUKS devices selected: $key_devices" elif [ "$num_devices" -eq 1 ]; then - echo "Single Encrypted Disk found at $devices_suggest." - key_devices=$devices_suggest + echo "Single Encrypted Disk found at ${devices_suggest[*]}." + key_devices=("${devices_suggest[@]}") else echo "No encrypted devices found." fi } +# get all LVM volume groups +lvm_suggest=($(lvm vgscan | awk -F '"' '{print $1}' | tail -n +2)) +num_lvm=${#lvm_suggest[@]} +if [ "$num_lvm" -eq 1 ] && [ -n "${lvm_suggest[*]}" ]; then + lvm_volume_group=("${lvm_suggest[@]}") +elif [ -z "${lvm_suggest[*]}" ]; then + num_lvm=0 +fi +DEBUG "LVM num_lvm: $num_lvm, lvm_suggest: ${lvm_suggest[*]}" + +# get all LUKS container devices +devices_suggest=($(blkid | cut -d ':' -f 1 | while read device; do + if cryptsetup isLuks "$device"; then echo "$device"; fi +done | sort)) +num_devices=${#devices_suggest[@]} + +if [ "$num_devices" -eq 1 ] && [ -s "${devices_suggest[*]}" ]; then + key_devices=("${devices_suggest[@]}") +elif [ -z "${devices_suggest[*]}" ]; then + num_devices=0 +fi + +# Create an array to store the suggested devices and their paths +declare -A devices_array +# Loop through the suggested devices and add them to the array +for device in "${devices_suggest[@]}"; do + devices_array["$device"]=$device +done + +# $devices_suggest is a multiline string, we need to convert it to a space separated string +devices_suggest=$(echo "${devices_suggest[*]}" | tr '\n' ' ') +DEBUG "LUKS num_devices: $num_devices, devices_suggest: $devices_suggest" + +if [ "$num_lvm" -eq 0 ] && [ "$num_devices" -eq 0 ]; then + #No encrypted partition found. + no_encrypted_partition=1 +fi + if [ ! -r "$TMP_MENU_FILE" ]; then die "No menu options available, please run kexec-select-boot" fi @@ -203,18 +213,18 @@ if [ "$CONFIG_TPM" = "y" ] && [ "$CONFIG_TPM_NO_LUKS_DISK_UNLOCK" != "y" ] && [ -o "$change_key_confirm" = "Y" ]; then old_lvm_volume_group="" if [ -r "$KEY_LVM" ]; then - old_lvm_volume_group=$(cat $KEY_LVM) || true - old_key_devices=$(cat $KEY_DEVICES | + old_lvm_volume_group=$(cat "$KEY_LVM") || true + old_key_devices=$(cat "$KEY_DEVICES" | cut -d\ -f1 | grep -v "$old_lvm_volume_group" | xargs) || true else - old_key_devices=$(cat $KEY_DEVICES | + old_key_devices=$(cat "$KEY_DEVICES" | cut -d\ -f1 | xargs) || true fi - lvm_suggest="$old_lvm_volume_group" - devices_suggest="$old_key_devices" + lvm_suggest=("$old_lvm_volume_group") + devices_suggest=("$old_key_devices") save_key="y" fi else @@ -234,18 +244,18 @@ if [ "$CONFIG_TPM" = "y" ] && [ "$CONFIG_TPM_NO_LUKS_DISK_UNLOCK" != "y" ] && [ if [ "$save_key" = "y" ]; then if [ -n "$old_key_devices" ] || [ -n "$old_lvm_volume_group" ]; then - DEBUG "Previous TPM Disk Unlock Key was set up for LUKS devices $old_key_devices $old_lvm_volume_group" + DEBUG "Previous TPM Disk Unlock Key was set up for LUKS devices ${old_key_devices[*]} ${old_lvm_volume_group[*]}" read \ -n 1 \ -p "Do you want to reuse configured Encrypted LVM groups/Block devices? (Y/n):" \ reuse_past_devices echo if [ "$reuse_past_devices" = "y" ] || [ "$reuse_past_devices" = "Y" ] || [ -z "$reuse_past_devices" ]; then - if [ -z "$key_devices" ] && [ -n "$old_key_devices" ]; then - key_devices="$old_key_devices" + if [ -z "${key_devices[*]}" ] && [ -n "$old_key_devices" ]; then + key_devices=("${old_key_devices[*]}") fi - if [ -z "$lvm_volume_group" ] && [ -n "$old_lvm_volume_group" ]; then - lvm_volume_group="$old_lvm_volume_group" + if [ -z "${lvm_volume_group[*]}" ] && [ -n "$old_lvm_volume_group" ]; then + lvm_volume_group=("${old_lvm_volume_group[*]}") fi #User doesn't want to reuse past devices, so we need to prompt him from devices_suggest and lvm_suggest else @@ -256,22 +266,29 @@ if [ "$CONFIG_TPM" = "y" ] && [ "$CONFIG_TPM_NO_LUKS_DISK_UNLOCK" != "y" ] && [ prompt_for_existing_encrypted_lvms_or_disks fi - save_key_params="-s -p $paramsdev" - if [ -n "$lvm_volume_group" ]; then - save_key_params="$save_key_params -l $lvm_volume_group $key_devices" + save_key_params=("-s" "-p" "$paramsdev") + if [ -n "${lvm_volume_group[*]}" ]; then + save_key_params+=("-l" "${lvm_volume_group[*]}" "${key_devices[*]}") else - save_key_params="$save_key_params $key_devices" + save_key_params+=("${key_devices[*]}") fi - kexec-save-key $save_key_params || + + #TODO REMOVE THIS TROUBLESHOOTING HACK + DEBUG "Outputting logs to USB drive. Please wait..." + mount-usb --mode rw + dmesg >/media/dmesg.txt + DEBUG "Done. You can CTRL-Alt-Delete now to reboot, files will be synced to USB drive before rebooting" + + kexec-save-key "${save_key_params[@]}" || die "Failed to save the TPM Disk Unlock Key" fi fi # try to switch to rw mode -mount -o rw,remount $paramsdev +mount -o rw,remount "$paramsdev" -if [ ! -d $paramsdir ]; then - mkdir -p $paramsdir || +if [ ! -d "$paramsdir" ]; then + mkdir -p "$paramsdir" || die "Failed to create params directory" fi @@ -281,13 +298,13 @@ if [ "$CONFIG_TPM2_TOOLS" = "y" ]; then DEBUG "TPM2 primary key handle hash saved to $PRIMHASH_FILE" fi -rm $paramsdir/kexec_default.*.txt 2>/dev/null || true -echo "$entry" >$ENTRY_FILE +rm "$paramsdir/kexec_default."*.txt 2>/dev/null || true +echo "$entry" >"$ENTRY_FILE" ( - cd $bootdir && kexec-boot -b "$bootdir" -e "$entry" -f | - xargs sha256sum >$HASH_FILE + cd "$bootdir" && kexec-boot -b "$bootdir" -e "$entry" -f | + xargs sha256sum >"$HASH_FILE" ) || die "Failed to create hashes of boot files" -if [ ! -r $ENTRY_FILE -o ! -r $HASH_FILE ]; then +if [ ! -r "$ENTRY_FILE" -o ! -r "$HASH_FILE" ]; then die "Failed to write default config" fi @@ -304,10 +321,10 @@ if [ "$save_key" = "y" ]; then if [ ! -z "$crypttab_files" ]; then DEBUG "Found crypttab files in $current_default_initrd" - rm -f $bootdir/kexec_initrd_crypttab_overrides.txt || true + rm -f "$bootdir/kexec_initrd_crypttab_overrides.txt" || true #Parsing each crypttab file found - echo "$crypttab_files" | while read crypttab_file; do + echo "$crypttab_files" | while read -r crypttab_file; do # Change crypttab file path to be relative to initrd for string manipulation final_initrd_filepath=${crypttab_file#/tmp/initrd_extract} DEBUG "Final initramfs crypttab path:$final_initrd_filepath" @@ -317,14 +334,14 @@ if [ "$save_key" = "y" ]; then # Modify each retained crypttab line for /secret.key under intramfs to be considered as a keyfile modified_crypttab_entries=$(echo "$current_crypttab_entries" | sed 's/none/\/secret.key/g') DEBUG "Modified crypttab entries $final_initrd_filepath:$modified_crypttab_entries" - echo "$modified_crypttab_entries" | while read modified_crypttab_entry; do - echo "$final_initrd_filepath:$modified_crypttab_entry" >>$bootdir/kexec_initrd_crypttab_overrides.txt + echo "$modified_crypttab_entries" | while read -r modified_crypttab_entry; do + echo "$final_initrd_filepath:$modified_crypttab_entry" >>"$bootdir/kexec_initrd_crypttab_overrides.txt" done done #insert current default boot's initrd crypttab locations into tracking file to be overwritten into initramfs at kexec-inject-key echo "+++ The following OS crypttab file:entry were modified from default boot's initrd:" - cat $bootdir/kexec_initrd_crypttab_overrides.txt + cat "$bootdir/kexec_initrd_crypttab_overrides.txt" echo "+++ Heads added /secret.key in those entries and saved them under $bootdir/kexec_initrd_crypttab_overrides.txt" echo "+++ Those overrides will be part of detached signed digests and used to prepare cpio injected at kexec of selected default boot entry." else @@ -348,8 +365,8 @@ if [ "$CONFIG_TPM" = "y" ]; then fi fi if [ "$CONFIG_BASIC" != "y" ]; then - kexec-sign-config -p $paramsdir $extparam || + kexec-sign-config -p "$paramsdir" $extparam || die "Failed to sign default config" fi # switch back to ro mode -mount -o ro,remount $paramsdev +mount -o ro,remount "$paramsdev" diff --git a/prompt b/prompt new file mode 100644 index 000000000..d4aee3451 --- /dev/null +++ b/prompt @@ -0,0 +1,25 @@ +The present code properly detects and populates devices_suggest with /dev/sda2 /dev/sdc1 prior of entering function prompt_for_existing_encrypted_lvms_or_disks. + +As can be seen under real hardware produced DEBUG trace as follow: + +''' +[ 24.118128] TRACE: Under /bin/kexec-save-default +[ 24.458491] DEBUG: LVM num_lvm: 0, lvm_suggest: +[ 24.479242] DEBUG: LUKS num_devices: 2, devices_suggest: /dev/sda2 /dev/sdb1 +[ 24.482668] DEBUG: TPM is enabled and TPM_NO_LUKS_DISK_UNLOCK is not set +[ 24.484955] DEBUG: Checking if a a TPM Disk Unlock Key was previously set up from /boot/kexec_key_devices.txt +[ 24.487162] DEBUG: No previous TPM Disk Unlock Key was set up for LUKS devices, confirming to add a Disk Encryption Key to the TPM +[ 26.429913] DEBUG: User confirmed desire to add a Disk Encryption Key to the TPM +[ 26.432147] DEBUG: No previous TPM Disk Unlock Key was set up for LUKS devices, setting up new one +[ 26.434217] TRACE: Under kexec-save-default:prompt_for_existing_encrypted_lvms_or_disks +[ 26.436331] DEBUG: num_lvm: 0, lvm_suggest: , num_devices: 2, devices_suggest: /dev/sda2 /dev/sdb1 +[ 26.440067] DEBUG: LUKS num_devices before array: 2, devices_array: /dev/sda2 /dev/sdb1 +[ 26.442249] DEBUG: LUKS num_devices after array: 1, devices_array: /dev/sda2 /dev/sdb1 +[ 26.445824] DEBUG: Outputting logs to USB drive. Please wait... +''' + +So here: +- "DEBUG: LUKS num_devices: 2, devices_suggest: /dev/sda2 /dev/sdb1" is right. +- "DEBUG: LUKS num_devices before array: 2, devices_array: /dev/sda2 /dev/sdb1" is still right +- "DEBUG: LUKS num_devices after array: 1, devices_array: /dev/sda2 /dev/sdb1" shows there is 2 elelements in array, while num_devices is now 1, which is wrong + From eb5254d58692c79a05a56e5475f74a6fafa5a343 Mon Sep 17 00:00:00 2001 From: Thierry Laurion Date: Thu, 18 Jan 2024 12:02:15 -0500 Subject: [PATCH 04/10] initrd/bin/kexec-seal-key: Fix check for number of LUKS keyslots used for both LUKSv1 and LUKSv2 Signed-off-by: Thierry Laurion --- initrd/bin/kexec-seal-key | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/initrd/bin/kexec-seal-key b/initrd/bin/kexec-seal-key index 03b64ab86..86eb6ac11 100755 --- a/initrd/bin/kexec-seal-key +++ b/initrd/bin/kexec-seal-key @@ -74,7 +74,26 @@ dd \ for dev in $(cat "$KEY_DEVICES" | cut -d\ -f1); do DEBUG "Checking number of slots used on $dev LUKS header" #check if the device is a LUKS device with luks[1,2] - slots_used=$(cryptsetup luksDump $dev | grep -c 'luks[0-9]*' || die "Unable to get number of slots used on $dev") + # Get the number of key slots used on the LUKS header. + # LUKS1 Format is : + # Slot 0: ENABLED + # Slot 1: ENABLED + # Slot 2: DISABLED + # Slot 3: DISABLED + #... + # Slot 7: DISABLED + # Luks2 only reports on enabled slots. + # luks2 Format is : + # 0: luks2 + # 1: luks2 + # Meaning that the number of slots used is the number of lines returned by a grep on the LUKS2 above format. + # We need to count the number of ENABLED slots for both LUKS1 and LUKS2 + # create glob pattern for both LUKS1 and LUKS2 + glob="Slot [0-9]*: ENABLED" + glob+="\|" + glob+="[0-9]*: luks2" + slot_used=$(cryptsetup luksDump $dev | grep -c "$glob" || die "Unable to get number of slots used on $dev") + DEBUG "Number of slots used on $dev LUKS header: $slots_used" # If slot1 is the only one used, warn and die with proper messages if [ $slots_used -eq 1 ]; then From 25ed0c2eeaa69ea58c907dd712990c47a0943d82 Mon Sep 17 00:00:00 2001 From: Thierry Laurion Date: Thu, 18 Jan 2024 12:24:47 -0500 Subject: [PATCH 05/10] initrd/bin/kexec-seal-key: fix unary comparison Signed-off-by: Thierry Laurion --- initrd/bin/kexec-seal-key | 70 +++++++++++++++++++-------------------- 1 file changed, 35 insertions(+), 35 deletions(-) diff --git a/initrd/bin/kexec-seal-key b/initrd/bin/kexec-seal-key index 86eb6ac11..a956b5644 100755 --- a/initrd/bin/kexec-seal-key +++ b/initrd/bin/kexec-seal-key @@ -72,42 +72,42 @@ dd \ # Count the number of slots used on each device for dev in $(cat "$KEY_DEVICES" | cut -d\ -f1); do - DEBUG "Checking number of slots used on $dev LUKS header" - #check if the device is a LUKS device with luks[1,2] - # Get the number of key slots used on the LUKS header. - # LUKS1 Format is : - # Slot 0: ENABLED - # Slot 1: ENABLED - # Slot 2: DISABLED - # Slot 3: DISABLED - #... - # Slot 7: DISABLED - # Luks2 only reports on enabled slots. - # luks2 Format is : - # 0: luks2 - # 1: luks2 - # Meaning that the number of slots used is the number of lines returned by a grep on the LUKS2 above format. - # We need to count the number of ENABLED slots for both LUKS1 and LUKS2 - # create glob pattern for both LUKS1 and LUKS2 - glob="Slot [0-9]*: ENABLED" - glob+="\|" - glob+="[0-9]*: luks2" - slot_used=$(cryptsetup luksDump $dev | grep -c "$glob" || die "Unable to get number of slots used on $dev") - - DEBUG "Number of slots used on $dev LUKS header: $slots_used" - # If slot1 is the only one used, warn and die with proper messages - if [ $slots_used -eq 1 ]; then - # Check if slot 1 is the only one existing - if cryptsetup luksDump $dev | grep -q "Slot 1: ENABLED"; then - warn "Slot 1 is the only one existing on $dev LUKS header. Heads cannot use it to store TPM sealed LUKS Disk Unlock Key" - warn "Slot 1 should not be the only slot existing on $dev LUKS header. Slot 0 should be used to store Disk Recovery Key/passphrase" - die "You can safely fix this before continuing through Heads recovery shell: cryptsetup luksAddKey $dev" + DEBUG "Checking number of slots used on $dev LUKS header" + #check if the device is a LUKS device with luks[1,2] + # Get the number of key slots used on the LUKS header. + # LUKS1 Format is : + # Slot 0: ENABLED + # Slot 1: ENABLED + # Slot 2: DISABLED + # Slot 3: DISABLED + #... + # Slot 7: DISABLED + # Luks2 only reports on enabled slots. + # luks2 Format is : + # 0: luks2 + # 1: luks2 + # Meaning that the number of slots used is the number of lines returned by a grep on the LUKS2 above format. + # We need to count the number of ENABLED slots for both LUKS1 and LUKS2 + # create glob pattern for both LUKS1 and LUKS2 + glob="Slot [0-9]*: ENABLED" + glob+="\|" + glob+="[0-9]*: luks2" + slot_used=$(cryptsetup luksDump "$dev" | grep -c "$glob" || die "Unable to get number of slots used on $dev") + + DEBUG "Number of slots used on $dev LUKS header: $slot_used" + # If slot1 is the only one used, warn and die with proper messages + if [ "$slot_used" -eq 1 ]; then + # Check if slot 1 is the only one existing + if cryptsetup luksDump "$dev" | grep -q "Slot 1: ENABLED"; then + warn "Slot 1 is the only one existing on $dev LUKS header. Heads cannot use it to store TPM sealed LUKS Disk Unlock Key" + warn "Slot 1 should not be the only slot existing on $dev LUKS header. Slot 0 should be used to store Disk Recovery Key/passphrase" + die "You can safely fix this before continuing through Heads recovery shell: cryptsetup luksAddKey $dev" + fi + else + DEBUG "Slot 1 is not the only existing slot on $dev LUKS header." + DEBUG "$dev LUKS header's slot 1 will store LUKS Disk Unlock Key that TPM will seal/unseal with TPM Disk Unlock Key passphrase" fi - else - DEBUG "Slot 1 is not the only existing slot on $dev LUKS header." - DEBUG "$dev LUKS header's slot 1 will store LUKS Disk Unlock Key that TPM will seal/unseal with TPM Disk Unlock Key passphrase" - fi -done + done # Remove all the old keys from slot 1 for dev in $(cat "$KEY_DEVICES" | cut -d\ -f1); do From 4b6f37fdd5bf7d6e0bc29ac8d974166a10870a17 Mon Sep 17 00:00:00 2001 From: Thierry Laurion Date: Thu, 18 Jan 2024 12:44:07 -0500 Subject: [PATCH 06/10] initrd/bin/kexec-save-default: Precise reason to reseal a TPM DUK key+passphrase, justifying choosing N in most cases. Display key_devices for confirmation as well. Signed-off-by: Thierry Laurion --- initrd/bin/kexec-save-default | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/initrd/bin/kexec-save-default b/initrd/bin/kexec-save-default index 285c50f8e..86a7a149e 100755 --- a/initrd/bin/kexec-save-default +++ b/initrd/bin/kexec-save-default @@ -202,10 +202,17 @@ if [ "$CONFIG_TPM" = "y" ] && [ "$CONFIG_TPM_NO_LUKS_DISK_UNLOCK" != "y" ] && [ DEBUG "Checking if a a TPM Disk Unlock Key was previously set up from $KEY_DEVICES" #check if $KEY_DEVICES file exists and is not empty if [ -r "$KEY_DEVICES" ] && [ -s "$KEY_DEVICES" ]; then - DEBUG "TPM Disk Unlock Key was previously set up from $KEY_DEVICES" + DEBUG "A TPM Disk Unlock Key was previously set up from $KEY_DEVICES" + #TODO: nobody complains about encrypted lvms missing, we might want to deprecate encrypted lvm logic: not aware of anyone using that anymore + + #Extract key devices from $KEY_DEVICES file + key_devices=$(cat "$KEY_DEVICES" | + cut -d\ -f1 | xargs) || true + + warn "Reseal a TPM Disk Unlock Key only if a new key/passphrase is desired for $key_devices" read \ -n 1 \ - -p "Do you want to reseal a disk key to the TPM [y/N]: " \ + -p "Do you want to reseal a Disk Unlock Key for $key_devices to the TPM [y/N]: " \ change_key_confirm echo From 37a250d951eb4a1859f3b246fcb89d833fdb872c Mon Sep 17 00:00:00 2001 From: Thierry Laurion Date: Thu, 18 Jan 2024 13:19:52 -0500 Subject: [PATCH 07/10] initrd/bin/kexec-save-default: remove sort to store luks devices in suggested_devices. Otherwise presented order is /dev/sdb1 /dev/sda2 Signed-off-by: Thierry Laurion --- initrd/bin/kexec-save-default | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/initrd/bin/kexec-save-default b/initrd/bin/kexec-save-default index 86a7a149e..fb2bd29d9 100755 --- a/initrd/bin/kexec-save-default +++ b/initrd/bin/kexec-save-default @@ -161,7 +161,7 @@ DEBUG "LVM num_lvm: $num_lvm, lvm_suggest: ${lvm_suggest[*]}" # get all LUKS container devices devices_suggest=($(blkid | cut -d ':' -f 1 | while read device; do if cryptsetup isLuks "$device"; then echo "$device"; fi -done | sort)) +done)) num_devices=${#devices_suggest[@]} if [ "$num_devices" -eq 1 ] && [ -s "${devices_suggest[*]}" ]; then From df27306dcaa0b5ff886438b4aaf8b570d5a55572 Mon Sep 17 00:00:00 2001 From: Thierry Laurion Date: Thu, 18 Jan 2024 14:04:19 -0500 Subject: [PATCH 08/10] initrd/bin/kexec-unseal-key: make TPM Disk Unlock Key actually retry (pipefail prevented retries) + cleanup. Apply workaround stating that capslock might be on, TPM might be in locked state: poweroff/poweron to retry cleanly. Output pcrs only in debug mode, otherwise disclosing unauthenticated final PCRs values to possible attacker. Should be available from authenticated Recovery console and from Debug only. Unify LUKS/TPM Disk Unlock Key output to end user for clarity Signed-off-by: Thierry Laurion --- initrd/bin/kexec-seal-key | 8 ++++---- initrd/bin/kexec-unseal-key | 14 ++++++++------ 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/initrd/bin/kexec-seal-key b/initrd/bin/kexec-seal-key index a956b5644..36aad18e4 100755 --- a/initrd/bin/kexec-seal-key +++ b/initrd/bin/kexec-seal-key @@ -111,18 +111,18 @@ for dev in $(cat "$KEY_DEVICES" | cut -d\ -f1); do # Remove all the old keys from slot 1 for dev in $(cat "$KEY_DEVICES" | cut -d\ -f1); do - echo "++++++ $dev: Removing old key slot 1" + echo "++++++ $dev: Removing old TPM Disk Unlock Key in LUKS slot 1" cryptsetup luksKillSlot \ --key-file "$RECOVERY_KEY" \ $dev 1 || - warn "$dev: removal of key in slot 1 failed: might not exist. Continuing" + warn "$dev: removal of TPM Disk Unlock Key in LUKS slot 1 failed: might not exist. Continuing" - echo "++++++ $dev: Adding key to slot 1" + echo "++++++ $dev: Adding TPM DISK Unlock Key to LUKS slot 1" cryptsetup luksAddKey \ --key-file "$RECOVERY_KEY" \ --key-slot 1 \ $dev "$KEY_FILE" || - die "$dev: Unable to add key to slot 1" + die "$dev: Unable to add TPM Disk Unlock Key to LUKS slot 1" done # Now that we have setup the new keys, measure the PCRs diff --git a/initrd/bin/kexec-unseal-key b/initrd/bin/kexec-unseal-key index b8c94b387..1a8ad129d 100755 --- a/initrd/bin/kexec-unseal-key +++ b/initrd/bin/kexec-unseal-key @@ -25,8 +25,9 @@ DEBUG "CONFIG_TPM2_TOOLS: $CONFIG_TPM2_TOOLS" DEBUG "Show PCRs" DEBUG "$(pcrs)" +failed=0 for tries in 1 2 3; do - read -s -p "Enter LUKS Disk Unlock Key passphrase (blank to abort): " tpm_password + read -s -p "Enter LUKS TPM Disk Unlock Key passphrase (blank to abort): " tpm_password echo if [ -z "$tpm_password" ]; then die "Aborting unseal disk encryption key" @@ -34,14 +35,15 @@ for tries in 1 2 3; do DO_WITH_DEBUG --mask-position 6 \ tpmr unseal "$TPM_INDEX" "0,1,2,3,4,5,6,7" "$TPM_SIZE" \ - "$key_file" "$tpm_password" + "$key_file" "$tpm_password" || failed=1 - if [ "$?" -eq 0 ]; then + if [ "$failed" -eq 0 ]; then exit 0 fi - pcrs - warn "Unable to unseal disk encryption key" + DEBUG pcrs # Show PCRs final state only in debug mode. TCPA/TPM Event log should only be visible in debug mode/from authenticated Recovery console + warn "Unable to unseal TPM Disk Unlock Key with provided passphrase. retry count: $tries/3." + warn "Caps Lock mode on? (All letters typed might have been uppercased)" done -die "Retry count exceeded..." +die "Retry count exceeded: TPM might be in a locked state until machine is cold rebooted (Power off, wait 30 seconds, power on)" From 30e52efbf0d4bef42a13ef735cc4974f2205832e Mon Sep 17 00:00:00 2001 From: Thierry Laurion Date: Thu, 18 Jan 2024 14:33:12 -0500 Subject: [PATCH 09/10] initrd/bin/kexec-insert-key: insert newline before output on console Signed-off-by: Thierry Laurion --- initrd/bin/kexec-insert-key | 1 + 1 file changed, 1 insertion(+) diff --git a/initrd/bin/kexec-insert-key b/initrd/bin/kexec-insert-key index 1b8632c02..4d0fc930d 100755 --- a/initrd/bin/kexec-insert-key +++ b/initrd/bin/kexec-insert-key @@ -45,6 +45,7 @@ mkdir -p "$INITRD_DIR/etc" unseal_failed="n" if ! kexec-unseal-key "$INITRD_DIR/secret.key"; then unseal_failed="y" + echo echo "!!! Failed to unseal the TPM LUKS disk key" fi From e33af25dc349a0b693de146e6dc8391004b5f235 Mon Sep 17 00:00:00 2001 From: Thierry Laurion Date: Thu, 18 Jan 2024 14:34:31 -0500 Subject: [PATCH 10/10] initrd/bin/kexec-save-default: remove mount-usb --mode rw and dmesg.txt output to usb thumb drive Really handy btw. Would be nice to add that into sysrq magic to output to usb thumb drive and have ctrl-alt-delete output dmesg to external storage when in debug mode. Would work also for headless debug when porting TODO: squash allrelated commits together. Signed-off-by: Thierry Laurion --- initrd/bin/kexec-save-default | 6 ------ initrd/bin/kexec-seal-key | 2 +- prompt | 25 ------------------------- 3 files changed, 1 insertion(+), 32 deletions(-) delete mode 100644 prompt diff --git a/initrd/bin/kexec-save-default b/initrd/bin/kexec-save-default index fb2bd29d9..2527dcc86 100755 --- a/initrd/bin/kexec-save-default +++ b/initrd/bin/kexec-save-default @@ -280,12 +280,6 @@ if [ "$CONFIG_TPM" = "y" ] && [ "$CONFIG_TPM_NO_LUKS_DISK_UNLOCK" != "y" ] && [ save_key_params+=("${key_devices[*]}") fi - #TODO REMOVE THIS TROUBLESHOOTING HACK - DEBUG "Outputting logs to USB drive. Please wait..." - mount-usb --mode rw - dmesg >/media/dmesg.txt - DEBUG "Done. You can CTRL-Alt-Delete now to reboot, files will be synced to USB drive before rebooting" - kexec-save-key "${save_key_params[@]}" || die "Failed to save the TPM Disk Unlock Key" fi diff --git a/initrd/bin/kexec-seal-key b/initrd/bin/kexec-seal-key index 36aad18e4..3c6a94d89 100755 --- a/initrd/bin/kexec-seal-key +++ b/initrd/bin/kexec-seal-key @@ -117,7 +117,7 @@ for dev in $(cat "$KEY_DEVICES" | cut -d\ -f1); do $dev 1 || warn "$dev: removal of TPM Disk Unlock Key in LUKS slot 1 failed: might not exist. Continuing" - echo "++++++ $dev: Adding TPM DISK Unlock Key to LUKS slot 1" + echo "++++++ $dev: Adding TPM Disk Unlock Key to LUKS slot 1" cryptsetup luksAddKey \ --key-file "$RECOVERY_KEY" \ --key-slot 1 \ diff --git a/prompt b/prompt deleted file mode 100644 index d4aee3451..000000000 --- a/prompt +++ /dev/null @@ -1,25 +0,0 @@ -The present code properly detects and populates devices_suggest with /dev/sda2 /dev/sdc1 prior of entering function prompt_for_existing_encrypted_lvms_or_disks. - -As can be seen under real hardware produced DEBUG trace as follow: - -''' -[ 24.118128] TRACE: Under /bin/kexec-save-default -[ 24.458491] DEBUG: LVM num_lvm: 0, lvm_suggest: -[ 24.479242] DEBUG: LUKS num_devices: 2, devices_suggest: /dev/sda2 /dev/sdb1 -[ 24.482668] DEBUG: TPM is enabled and TPM_NO_LUKS_DISK_UNLOCK is not set -[ 24.484955] DEBUG: Checking if a a TPM Disk Unlock Key was previously set up from /boot/kexec_key_devices.txt -[ 24.487162] DEBUG: No previous TPM Disk Unlock Key was set up for LUKS devices, confirming to add a Disk Encryption Key to the TPM -[ 26.429913] DEBUG: User confirmed desire to add a Disk Encryption Key to the TPM -[ 26.432147] DEBUG: No previous TPM Disk Unlock Key was set up for LUKS devices, setting up new one -[ 26.434217] TRACE: Under kexec-save-default:prompt_for_existing_encrypted_lvms_or_disks -[ 26.436331] DEBUG: num_lvm: 0, lvm_suggest: , num_devices: 2, devices_suggest: /dev/sda2 /dev/sdb1 -[ 26.440067] DEBUG: LUKS num_devices before array: 2, devices_array: /dev/sda2 /dev/sdb1 -[ 26.442249] DEBUG: LUKS num_devices after array: 1, devices_array: /dev/sda2 /dev/sdb1 -[ 26.445824] DEBUG: Outputting logs to USB drive. Please wait... -''' - -So here: -- "DEBUG: LUKS num_devices: 2, devices_suggest: /dev/sda2 /dev/sdb1" is right. -- "DEBUG: LUKS num_devices before array: 2, devices_array: /dev/sda2 /dev/sdb1" is still right -- "DEBUG: LUKS num_devices after array: 1, devices_array: /dev/sda2 /dev/sdb1" shows there is 2 elelements in array, while num_devices is now 1, which is wrong -