mirror of
https://github.com/linuxboot/heads.git
synced 2025-03-27 22:28:42 +00:00
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 . 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.
102 lines
3.2 KiB
Bash
Executable File
102 lines
3.2 KiB
Bash
Executable File
#!/bin/sh
|
|
# Unseal a disk key from TPM and add to a new initramfs
|
|
set -e -o pipefail
|
|
. /etc/functions
|
|
|
|
TMP_KEY_DEVICES="/tmp/kexec/kexec_key_devices.txt"
|
|
TMP_KEY_LVM="/tmp/kexec/kexec_key_lvm.txt"
|
|
|
|
INITRD="$1"
|
|
|
|
if [ -z "$INITRD" ]; then
|
|
die "Usage: $0 /boot/initramfs... "
|
|
fi
|
|
|
|
if [ ! -r "$TMP_KEY_DEVICES" ]; then
|
|
die "No devices defined for disk encryption"
|
|
fi
|
|
|
|
if [ -r "$TMP_KEY_LVM" ]; then
|
|
# Activate the LVM volume group
|
|
VOLUME_GROUP=`cat $TMP_KEY_LVM`
|
|
if [ -z "$TMP_KEY_LVM" ]; then
|
|
die "No LVM volume group defined for activation"
|
|
fi
|
|
lvm vgchange -a y $VOLUME_GROUP \
|
|
|| die "$VOLUME_GROUP: unable to activate volume group"
|
|
fi
|
|
|
|
# Measure the LUKS headers before we unseal the disk key
|
|
cat "$TMP_KEY_DEVICES" | cut -d\ -f1 | xargs /bin/qubes-measure-luks \
|
|
|| die "LUKS measure failed"
|
|
|
|
# Unpack the initrd and fixup the crypttab
|
|
# this is a hack to split it into two parts since
|
|
# 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)"
|
|
|
|
# Attempt to unseal the disk key from the TPM
|
|
# should we give this some number of tries?
|
|
unseal_failed="n"
|
|
if ! kexec-unseal-key "$INITRD_DIR/secret.key" ; then
|
|
unseal_failed="y"
|
|
echo "!!! Failed to unseal the TPM LUKS disk key"
|
|
fi
|
|
|
|
# Override PCR 4 so that user can't read the key
|
|
tpm extend -ix 4 -ic generic \
|
|
|| die 'Unable to scramble PCR'
|
|
|
|
# Check to continue
|
|
if [ "$unseal_failed" = "y" ]; then
|
|
confirm_boot="n"
|
|
read \
|
|
-n 1 \
|
|
-p "Do you wish to boot and use the disk recovery key? [Y/n] " \
|
|
confirm_boot
|
|
|
|
if [ "$confirm_boot" != 'y' \
|
|
-a "$confirm_boot" != 'Y' \
|
|
-a -n "$confirm_boot" ] \
|
|
; then
|
|
die "!!! Aborting boot due to failure to unseal TPM disk key"
|
|
fi
|
|
fi
|
|
|
|
echo '+++ Building initrd'
|
|
# pad the initramfs (dracut doesn't pad the last gz blob)
|
|
# without this the kernel init/initramfs.c fails to read
|
|
# the subsequent uncompressed/compressed cpio
|
|
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
|
|
( cd "$INITRD_DIR" ; find . -type f | cpio -H newc -o ) >> "$SECRET_CPIO"
|
|
fi
|