TPM disk unlock key setup: Automatically override selected default boot option's initrd's crypttab file(s) to point to LUKS decryption key in injected cpio

- kexec-save-default extracts initrd crypttab files and creates /boot/kexec_initrd_crypttab_overrides.txt entries pointing to /secret.key
- kexec-insert-key applies /boot/kexec_initrd_crypttab_overrides.txt to replace initrd's crypttabs files pointing to inserted /secret.key through cpio
- Both scripts inform the user of applied magic on screen
This commit is contained in:
Thierry Laurion 2023-01-16 15:15:21 -05:00
parent 8a60930c6b
commit 150b95a034
No known key found for this signature in database
GPG Key ID: E7B4A71658E36A93
2 changed files with 71 additions and 24 deletions

View File

@ -35,19 +35,8 @@ cat "$TMP_KEY_DEVICES" | cut -d\ -f1 | xargs /bin/qubes-measure-luks \
# we know that the first 0x3400 bytes are the microcode
INITRD_DIR=/tmp/secret/initrd
SECRET_CPIO=/tmp/secret/initrd.cpio
# Not all distro put crypttab under /etc/ within initramfs, but finding it at
# runtime needs unpacking, which may be hard to do, so it is made overridable
# with a file at /boot/kexec_initrd_crypttab_path.txt, whose content could be
# obtained with $ cpio -t < ${uncompressed_initrd} | grep crypttab .
bootdir=$(dirname "$INITRD")
if [ -r $bootdir/kexec_initrd_crypttab_path.txt ]; then
crypttab_path=$(cat $bootdir/kexec_initrd_crypttab_path.txt)
else
crypttab_path=etc/crypttab
fi
mkdir -p "$INITRD_DIR/$(dirname $crypttab_path)"
mkdir -p "$INITRD_DIR/etc"
# Attempt to unseal the disk key from the TPM
# should we give this some number of tries?
@ -84,18 +73,30 @@ echo '+++ Building initrd'
dd if="$INITRD" of="$SECRET_CPIO" bs=512 conv=sync \
|| die "Failed to copy initrd to /tmp"
# The "target" field of the record within the crypttab stored in the root
# file system for the luks container which is going to be unlocked via
# kexec-insert-key should be modified into the same "luks-$uuid" format,
# otherwise the boot sequence will get stuck when OS is trying to unlock them
# again, in order to map them according to "target" fields written in the
# crypttab stored in the root fs.
if [ "$unseal_failed" = "n" ]; then
# overwrite crypttab to mirror the behavior for in seal-key
for uuid in `cat "$TMP_KEY_DEVICES" | cut -d\ -f2`; do
# In Debian, the "luks" option at last should not be omitted
echo "luks-$uuid UUID=$uuid /secret.key luks" >> "$INITRD_DIR/$crypttab_path"
done
# kexec-save-default might have created crypttab overrides to be injected in initramfs through additional cpio
if [ -r "$bootdir/kexec_initrd_crypttab_overrides.txt" ]; then
echo "$bootdir/kexec_initrd_crypttab_overrides.txt found..."
echo "Preparing initramfs crypttab overrides as defined under $bootdir/kexec_initrd_crypttab_overrides.txt to be injected through cpio at next kexec call..."
# kexec-save-default has found crypttab files under initrd and saved them
cat "$bootdir/kexec_initrd_crypttab_overrides.txt" | while read line; do
crypttab_file=$(echo "$line" | awk -F ':' {'print $1'})
crypttab_entry=$(echo "$line" | awk -F ':' {'print $NF'})
# Replace each initrd crypttab file with modified entry containing /secret.key path
mkdir -p "$INITRD_DIR/$(dirname $crypttab_file)"
echo "$crypttab_entry" | tee -a "$INITRD_DIR/$crypttab_file" > /dev/null
echo "initramfs's $crypttab_file will be overriden with $crypttab_entry"
done
else
# No crypttab files were found under selected default boot option's initrd file
crypttab_file="etc/crypttab"
mkdir -p "$INITRD_DIR/$(dirname $crypttab_file)"
# overwrite crypttab to mirror behavior of seal-key
echo "The following /etc/crypttab lines will be passed through cpio into kexec call for default boot option:"
for uuid in `cat "$TMP_KEY_DEVICES" | cut -d\ -f2`; do
# NOTE: discard operation (TRIM) is activated by default if no crypptab found in initrd
echo "luks-$uuid UUID=$uuid /secret.key luks,discard" | tee -a "$INITRD_DIR/$crypttab_file"
done
fi
( cd "$INITRD_DIR" ; find . -type f | cpio -H newc -o ) >> "$SECRET_CPIO"
fi

View File

@ -129,6 +129,52 @@ if [ ! -r $ENTRY_FILE -o ! -r $HASH_FILE ]; then
die "Failed to write default config"
fi
if [ "$save_key" = "y" ]; then
# logic to parse OS initrd to extract crypttab, its filepaths and its OS defined options
mkdir -p /tmp/initrd_extract
cd /tmp/initrd_extract
# Get initrd filename selected to be default initrd that OS could be using to configure LUKS on boot by deploying crypttab files
current_default_initrd=$(cat /boot/kexec_default_hashes.txt | grep initr | awk -F " " {'print $NF'} | sed 's/\.\//\/boot\//g')
# Get crypttab files paths from initrd
echo "Checking current selected default boot's $current_default_initrd for existing crypttab files..."
# First either decompress or use the original if it's not compressed
initrd_decompressed="/tmp/initrd_extract/initrd_decompressed.cpio"
zcat < "$current_default_initrd" > "$initrd_decompressed" 2> /dev/null || initrd_decompressed="$current_default_initrd"
crypttab_files=$(cpio --list --quiet < "$initrd_decompressed" | grep crypttab 2> /dev/null) || true
if [ ! -z "$crypttab_files" ]; then
echo "Extracting current selected default boot's $current_default_initrd for found crypttab files analysis..."
cpio -id --quiet < $initrd_decompressed $crypttab_files 2> /dev/null
rm -f $bootdir/kexec_initrd_crypttab_overrides.txt || true
#Parsing each crypttab file found
echo "$crypttab_files" | while read filepath; do
# Keep only non-commented lines
current_filepath_entries=$(cat "$filepath" | grep -v "^#")
# Modify each retained crypttab line to contain to be injected /secret.key at next default boots
modified_filepath_entries=$(echo "$current_filepath_entries" | sed 's/none/\/secret.key/g')
echo "$modified_filepath_entries" | while read single_modified_filepath_entry; do
# Append each found filepath:entry into additional kexec_ file that will be part of detached signed digest
echo "$filepath:$single_modified_filepath_entry" >> $bootdir/kexec_initrd_crypttab_overrides.txt
done
done
cd - > /dev/null
#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
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
echo "No crypttab file found in extracted initrd. Removing $bootdir/kexec_initrd_crypttab_overrides.txt"
rm -f "$bootdir/kexec_initrd_crypttab_overrides.txt" || true
fi
# Cleanup
rm -rf /tmp/initrd_extract || true
fi
# sign and auto-roll config counter
extparam=
if [ "$CONFIG_TPM" = "y" ]; then