mirror of
https://github.com/linuxboot/heads.git
synced 2025-02-18 00:10:24 +00:00
Merge branch 'flammit-usb-boot' pull request #200
This commit is contained in:
commit
f0913e9670
config
initrd
@ -19,6 +19,8 @@ CONFIG_LINUX_USB=y
|
|||||||
|
|
||||||
CONFIG_BOOTSCRIPT=/bin/qubes-init
|
CONFIG_BOOTSCRIPT=/bin/qubes-init
|
||||||
|
|
||||||
|
CONFIG_USB_BOOT_DEV="/dev/sdb1"
|
||||||
|
|
||||||
# Disks encrypted by the TPM LUKS key
|
# Disks encrypted by the TPM LUKS key
|
||||||
CONFIG_QUBES_BOOT_DEV="/dev/sda1"
|
CONFIG_QUBES_BOOT_DEV="/dev/sda1"
|
||||||
CONFIG_QUBES_VG="qubes_dom0"
|
CONFIG_QUBES_VG="qubes_dom0"
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
# Configuration for a x230 running Qubes OS
|
# Configuration for a x230 running non-Qubes
|
||||||
BOARD=x230
|
BOARD=x230
|
||||||
|
|
||||||
CONFIG_CRYPTSETUP=y
|
CONFIG_CRYPTSETUP=y
|
||||||
@ -18,8 +18,9 @@ CONFIG_DROPBEAR=y
|
|||||||
CONFIG_LINUX_USB=y
|
CONFIG_LINUX_USB=y
|
||||||
CONFIG_LINUX_E1000E=y
|
CONFIG_LINUX_E1000E=y
|
||||||
|
|
||||||
CONFIG_BOOTSCRIPT=/bin/qubes-init
|
CONFIG_BOOTSCRIPT=/bin/generic-init
|
||||||
|
|
||||||
# Disks encrypted by the TPM LUKS key
|
CONFIG_BOOT_REQ_HASH=n
|
||||||
CONFIG_QUBES_BOOT_DEV="/dev/sda1"
|
CONFIG_BOOT_REQ_ROLLBACK=n
|
||||||
CONFIG_QUBES_VG="qubes_dom0"
|
CONFIG_BOOT_DEV="/dev/sda1"
|
||||||
|
CONFIG_USB_BOOT_DEV="/dev/sdb1"
|
@ -1,11 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
# Generate a crypttab file for all the devices that are
|
|
||||||
# present on the system. This is a total hack since the
|
|
||||||
# rd.luks.key=/secret.key should be sufficient.
|
|
||||||
|
|
||||||
keyfile=/secret.key
|
|
||||||
|
|
||||||
for dev in /dev/sd*; do
|
|
||||||
uuid=`cryptsetup luksUUID "$dev" 2>/dev/null` || continue
|
|
||||||
echo "luks-$uuid /dev/disk/by-uuid/$uuid $keyfile luks"
|
|
||||||
done
|
|
25
initrd/bin/generic-init
Executable file
25
initrd/bin/generic-init
Executable file
@ -0,0 +1,25 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# Boot from a local disk installation
|
||||||
|
|
||||||
|
. /etc/functions
|
||||||
|
. /etc/config
|
||||||
|
|
||||||
|
# Confirm we have a good TOTP unseal
|
||||||
|
if ! confirm_totp ; then
|
||||||
|
recovery 'Failed to unseal TOTP'
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! "$totp_confirm" = "y" ]; then
|
||||||
|
recovery "Failed to confirm validity of TOTP"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Mount local disk
|
||||||
|
if ! grep -q /boot /proc/mounts ; then
|
||||||
|
mount -o ro "$CONFIG_BOOT_DEV" /boot \
|
||||||
|
|| recovery "$CONFIG_BOOT_DEV: Unable to mount /boot"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Attempt to pull verified config from device
|
||||||
|
kexec-select-boot -b /boot -c "grub.cfg"
|
||||||
|
|
||||||
|
recovery "Something failed during boot"
|
137
initrd/bin/kexec-boot
Executable file
137
initrd/bin/kexec-boot
Executable file
@ -0,0 +1,137 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# Launches kexec from saved configuration entries
|
||||||
|
set -e -o pipefail
|
||||||
|
. /etc/functions
|
||||||
|
|
||||||
|
dryrun="n"
|
||||||
|
printfiles="n"
|
||||||
|
printinitrd="n"
|
||||||
|
while getopts "b:e:r:a:o:fi" arg; do
|
||||||
|
case $arg in
|
||||||
|
b) bootdir="$OPTARG" ;;
|
||||||
|
e) entry="$OPTARG" ;;
|
||||||
|
r) cmdremove="$OPTARG" ;;
|
||||||
|
a) cmdadd="$OPTARG" ;;
|
||||||
|
o) override_initrd="$OPTARG" ;;
|
||||||
|
f) dryrun="y"; printfiles="y" ;;
|
||||||
|
i) dryrun="y"; printinitrd="y" ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ -z "$bootdir" -o -z "$entry" ]; then
|
||||||
|
die "Usage: $0 -b /boot -e 'kexec params|...|...'"
|
||||||
|
fi
|
||||||
|
|
||||||
|
bootdir=${bootdir%%"/"}
|
||||||
|
|
||||||
|
kexectype=`echo $entry | cut -d\| -f2`
|
||||||
|
kexecparams=`echo $entry | cut -d\| -f3- | tr '|' '\n'`
|
||||||
|
kexeccmd="kexec"
|
||||||
|
|
||||||
|
# TODO: make this configurable
|
||||||
|
cmdadd="intel_iommu=on $cmdadd"
|
||||||
|
cmdremove="quiet $cmdremove"
|
||||||
|
|
||||||
|
fix_file_path() {
|
||||||
|
if [ "$printfiles" = "y" ]; then
|
||||||
|
# output file relative to local boot directory
|
||||||
|
echo ".$firstval"
|
||||||
|
fi
|
||||||
|
|
||||||
|
filepath="$bootdir$firstval"
|
||||||
|
|
||||||
|
if ! [ -r $filepath ]; then
|
||||||
|
die "Failed to find file $firstval"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
adjusted_cmd_line="n"
|
||||||
|
adjust_cmd_line() {
|
||||||
|
if [ -n "$cmdremove" ]; then
|
||||||
|
for i in $cmdremove; do
|
||||||
|
cmdline="${cmdline//$i/}"
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -n "$cmdadd" ]; then
|
||||||
|
cmdline="$cmdline $cmdadd"
|
||||||
|
fi
|
||||||
|
adjusted_cmd_line="y"
|
||||||
|
}
|
||||||
|
|
||||||
|
module_number="1"
|
||||||
|
while read line
|
||||||
|
do
|
||||||
|
key=`echo $line | cut -d\ -f1`
|
||||||
|
firstval=`echo $line | cut -d\ -f2`
|
||||||
|
restval=`echo $line | cut -d\ -f3-`
|
||||||
|
if [ "$key" = "kernel" ]; then
|
||||||
|
if [ "$kexectype" = "xen" ]; then
|
||||||
|
# always overload xen and with custom arguments
|
||||||
|
kexeccmd="$kexeccmd -l /bin/xen.gz"
|
||||||
|
kexeccmd="$kexeccmd --command-line \"no-real-mode reboot=no\""
|
||||||
|
elif [ "$kexectype" = "multiboot" ]; then
|
||||||
|
fix_file_path
|
||||||
|
kexeccmd="$kexeccmd -l $filepath"
|
||||||
|
kexeccmd="$kexeccmd --command-line \"$restval\""
|
||||||
|
else
|
||||||
|
fix_file_path
|
||||||
|
kexeccmd="$kexeccmd -l $filepath"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
if [ "$key" = "module" ]; then
|
||||||
|
fix_file_path
|
||||||
|
cmdline="$restval"
|
||||||
|
if [ "$kexectype" = "xen" ]; then
|
||||||
|
if [ "$module_number" -eq 1 ]; then
|
||||||
|
adjust_cmd_line
|
||||||
|
elif [ "$module_number" -eq 2 ]; then
|
||||||
|
if [ "$printinitrd" = "y" ]; then
|
||||||
|
# output the current path to initrd
|
||||||
|
echo $filepath
|
||||||
|
fi
|
||||||
|
if [ -n "$override_initrd" ]; then
|
||||||
|
filepath="$override_initrd"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
module_number=`expr $module_number + 1`
|
||||||
|
kexeccmd="$kexeccmd --module \"$filepath $cmdline\""
|
||||||
|
fi
|
||||||
|
if [ "$key" = "initrd" ]; then
|
||||||
|
fix_file_path
|
||||||
|
if [ "$printinitrd" = "y" ]; then
|
||||||
|
# output the current path to initrd
|
||||||
|
echo $filepath
|
||||||
|
fi
|
||||||
|
if [ -n "$override_initrd" ]; then
|
||||||
|
filepath="$override_initrd"
|
||||||
|
fi
|
||||||
|
kexeccmd="$kexeccmd --initrd=$filepath"
|
||||||
|
fi
|
||||||
|
if [ "$key" = "append" ]; then
|
||||||
|
cmdline="$firstval $restval"
|
||||||
|
adjust_cmd_line
|
||||||
|
kexeccmd="$kexeccmd --append=\"$cmdline\""
|
||||||
|
fi
|
||||||
|
done << EOF
|
||||||
|
$kexecparams
|
||||||
|
EOF
|
||||||
|
|
||||||
|
if [ "$adjusted_cmd_line" = "n" ]; then
|
||||||
|
if [ "$kexectype" = "elf" ]; then
|
||||||
|
kexeccmd="$kexeccmd --append=\"$cmdadd\""
|
||||||
|
else
|
||||||
|
die "Failed to add required kernel commands: $cmdadd"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$dryrun" = "y" ]; then exit 0; fi
|
||||||
|
|
||||||
|
echo "Loading the new kernel:"
|
||||||
|
echo "$kexeccmd"
|
||||||
|
eval "$kexeccmd" \
|
||||||
|
|| die "Failed to load the new kernel"
|
||||||
|
|
||||||
|
echo "Starting the new kernel"
|
||||||
|
exec kexec -e
|
61
initrd/bin/kexec-insert-key
Executable file
61
initrd/bin/kexec-insert-key
Executable file
@ -0,0 +1,61 @@
|
|||||||
|
#!/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 /etc/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
|
||||||
|
mkdir -p "$INITRD_DIR/etc"
|
||||||
|
|
||||||
|
# Attempt to unseal the disk key from the TPM
|
||||||
|
# should we give this some number of tries?
|
||||||
|
if ! kexec-unseal-key "$INITRD_DIR/secret.key" ; then
|
||||||
|
die 'Unseal disk key failed'
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Override PCR 4 so that user can't read the key
|
||||||
|
tpm extend -ix 4 -ic generic \
|
||||||
|
|| die 'Unable to scramble PCR'
|
||||||
|
|
||||||
|
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"
|
||||||
|
|
||||||
|
# overwrite /etc/crypttab to mirror the behavior for in seal-key
|
||||||
|
for uuid in `cat "$TMP_KEY_DEVICES" | cut -d\ -f2`; do
|
||||||
|
echo "luks-$uuid UUID=$uuid /secret.key" >> "$INITRD_DIR/etc/crypttab"
|
||||||
|
done
|
||||||
|
( cd "$INITRD_DIR" ; find . -type f | cpio -H newc -o ) >> "$SECRET_CPIO"
|
49
initrd/bin/kexec-iso-init
Executable file
49
initrd/bin/kexec-iso-init
Executable file
@ -0,0 +1,49 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# Boot from signed ISO
|
||||||
|
set -e -o pipefail
|
||||||
|
. /etc/functions
|
||||||
|
. /etc/config
|
||||||
|
|
||||||
|
MOUNTED_ISO_PATH="$1"
|
||||||
|
ISO_PATH="$2"
|
||||||
|
DEV="$3"
|
||||||
|
|
||||||
|
echo '+++ Verifying ISO'
|
||||||
|
# Verify the signature on the hashes
|
||||||
|
ISOSIG="$MOUNTED_ISO_PATH.sig"
|
||||||
|
if ! [ -r "$ISOSIG" ]; then
|
||||||
|
ISOSIG="$MOUNTED_ISO_PATH.asc"
|
||||||
|
fi
|
||||||
|
|
||||||
|
gpgv "$ISOSIG" "$MOUNTED_ISO_PATH" \
|
||||||
|
|| die 'ISO signature failed'
|
||||||
|
|
||||||
|
echo '+++ Mounting ISO and booting'
|
||||||
|
mount -t iso9660 -o loop $MOUNTED_ISO_PATH /boot \
|
||||||
|
|| die '$MOUNTED_ISO_PATH: Unable to mount /boot'
|
||||||
|
|
||||||
|
DEV_UUID=`blkid $DEV | tail -1 | tr " " "\n" | grep UUID | cut -d\" -f2`
|
||||||
|
ADD="fromiso=/dev/disk/by-uuid/$DEV_UUID/$ISO_PATH"
|
||||||
|
REMOVE=""
|
||||||
|
|
||||||
|
paramsdir="/media/kexec_iso/$ISO_PATH/"
|
||||||
|
check_config $paramsdir
|
||||||
|
|
||||||
|
ADD_FILE=/tmp/kexec/kexec_iso_add.txt
|
||||||
|
if [ -r $ADD_FILE ]; then
|
||||||
|
NEW_ADD=`cat $ADD_FILE`
|
||||||
|
ADD=$(eval "echo \"$NEW_ADD\"")
|
||||||
|
echo "+++ Overriding standard ISO kernel add arguments: $ADD"
|
||||||
|
fi
|
||||||
|
REMOVE_FILE=/tmp/kexec/kexec_iso_remove.txt
|
||||||
|
if [ -r $REMOVE_FILE ]; then
|
||||||
|
NEW_REMOVE=`cat $REMOVE_FILE`
|
||||||
|
REMOVE=$(eval "echo \"$NEW_REMOVE\"")
|
||||||
|
echo "+++ Overriding standard ISO kernel remove arguments: $REMOVE"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Call kexec and indicate that hashes have been verified
|
||||||
|
kexec-select-boot -b /boot -d /media/ -p "$paramsdir" \
|
||||||
|
-a "$ADD" -r "$REMOVE" -c "*.cfg" -u -i
|
||||||
|
|
||||||
|
die "Something failed in selecting boot"
|
208
initrd/bin/kexec-parse-boot
Executable file
208
initrd/bin/kexec-parse-boot
Executable file
@ -0,0 +1,208 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
set -e -o pipefail
|
||||||
|
bootdir="$1"
|
||||||
|
file="$2"
|
||||||
|
|
||||||
|
if [ -z "$bootdir" -o -z "$file" ]; then
|
||||||
|
die "Usage: $0 /boot /boot/grub/grub.cfg"
|
||||||
|
fi
|
||||||
|
|
||||||
|
reset_entry() {
|
||||||
|
name=""
|
||||||
|
kexectype="elf"
|
||||||
|
kernel=""
|
||||||
|
initrd=""
|
||||||
|
modules=""
|
||||||
|
append=""
|
||||||
|
}
|
||||||
|
|
||||||
|
filedir=`dirname $file`
|
||||||
|
bootdir=${bootdir%%"/"}
|
||||||
|
bootlen=${#bootdir}
|
||||||
|
appenddir=${filedir:$bootlen}
|
||||||
|
|
||||||
|
fix_path() {
|
||||||
|
path="$@"
|
||||||
|
if [ "${path:0:1}" != "/" ]; then
|
||||||
|
path="$appenddir/$path"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
echo_entry() {
|
||||||
|
if [ "$kexectype" = "elf" ]; then
|
||||||
|
if [ -z "$kernel" ]; then return; fi
|
||||||
|
|
||||||
|
fix_path $kernel
|
||||||
|
entry="$name|$kexectype|kernel $path"
|
||||||
|
if [ -n "$initrd" ]; then
|
||||||
|
fix_path $initrd
|
||||||
|
entry="$entry|initrd $path"
|
||||||
|
fi
|
||||||
|
if [ -n "$append" ]; then
|
||||||
|
entry="$entry|append $append"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo $(eval "echo \"$entry\"")
|
||||||
|
fi
|
||||||
|
if [ "$kexectype" = "multiboot" -o "$kexectype" = "xen" ]; then
|
||||||
|
if [ -z "$kernel" ]; then return; fi
|
||||||
|
|
||||||
|
fix_path $kernel
|
||||||
|
echo $(eval "echo \"$name|$kexectype|kernel $path$modules\"")
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
search_entry() {
|
||||||
|
case $line in
|
||||||
|
menuentry* | MENUENTRY* )
|
||||||
|
state="grub"
|
||||||
|
reset_entry
|
||||||
|
name=`echo $line | tr "'" "\"" | cut -d\" -f 2`
|
||||||
|
;;
|
||||||
|
|
||||||
|
label* | LABEL* )
|
||||||
|
state="syslinux"
|
||||||
|
reset_entry
|
||||||
|
name=`echo $line | cut -c6- `
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
grub_entry() {
|
||||||
|
if [ "$line" = "}" ]; then
|
||||||
|
echo_entry
|
||||||
|
state="search"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
# add info to menuentry
|
||||||
|
trimcmd=`echo $line | tr '\t ' ' ' | tr -s ' '`
|
||||||
|
cmd=`echo $trimcmd | cut -d\ -f1`
|
||||||
|
val=`echo $trimcmd | cut -d\ -f2-`
|
||||||
|
case $cmd in
|
||||||
|
multiboot*)
|
||||||
|
# TODO: differentiate between Xen and other multiboot kernels
|
||||||
|
kexectype="xen"
|
||||||
|
kernel="$val"
|
||||||
|
;;
|
||||||
|
module*)
|
||||||
|
case $val in
|
||||||
|
--nounzip*) val=`echo $val | cut -d\ -f2-` ;;
|
||||||
|
esac
|
||||||
|
fix_path $val
|
||||||
|
modules="$modules|module $path"
|
||||||
|
;;
|
||||||
|
linux*)
|
||||||
|
kernel=`echo $trimcmd | cut -d\ -f2`
|
||||||
|
append=`echo $trimcmd | cut -d\ -f3-`
|
||||||
|
;;
|
||||||
|
initrd*)
|
||||||
|
initrd="$val"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
syslinux_end() {
|
||||||
|
# finish menuentry
|
||||||
|
|
||||||
|
# attempt to parse out of append if missing initrd
|
||||||
|
if [ -z "$initrd" ]; then
|
||||||
|
newappend=""
|
||||||
|
for param in $append; do
|
||||||
|
case $param in
|
||||||
|
initrd=*)
|
||||||
|
initrd=`echo $param | cut -d\= -f2`
|
||||||
|
;;
|
||||||
|
*) newappend="$newappend $param" ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
append="${newappend##' '}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo_entry
|
||||||
|
state="search"
|
||||||
|
}
|
||||||
|
|
||||||
|
syslinux_multiboot_append() {
|
||||||
|
splitval=`echo "${val// --- /|}" | tr '|' '\n'`
|
||||||
|
while read line
|
||||||
|
do
|
||||||
|
if [ -z "$kernel" ]; then
|
||||||
|
kernel="$line"
|
||||||
|
else
|
||||||
|
fix_path $line
|
||||||
|
modules="$modules|module $path"
|
||||||
|
fi
|
||||||
|
done << EOF
|
||||||
|
$splitval
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
syslinux_entry() {
|
||||||
|
case $line in
|
||||||
|
"")
|
||||||
|
syslinux_end
|
||||||
|
return
|
||||||
|
;;
|
||||||
|
label* | LABEL* )
|
||||||
|
syslinux_end
|
||||||
|
search_entry
|
||||||
|
return
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# add info to menuentry
|
||||||
|
trimcmd=`echo $line | tr '\t ' ' ' | tr -s ' '`
|
||||||
|
cmd=`echo $trimcmd | cut -d\ -f1`
|
||||||
|
val=`echo $trimcmd | cut -d\ -f2-`
|
||||||
|
case $trimcmd in
|
||||||
|
menu* | MENU* )
|
||||||
|
cmd2=`echo $trimcmd | cut -d \ -f2`
|
||||||
|
if [ "$cmd2" = "label" -o "$cmd2" = "LABEL" ]; then
|
||||||
|
name=`echo $trimcmd | cut -c11- | tr -d '^'`
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
linux* | LINUX* | kernel* | KERNEL* )
|
||||||
|
case $val in
|
||||||
|
# TODO: differentiate between Xen and other multiboot kernels
|
||||||
|
*mboot.c32) kexectype="xen" ;;
|
||||||
|
*.c32)
|
||||||
|
# skip this entry
|
||||||
|
state="search"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
kernel="$val"
|
||||||
|
esac
|
||||||
|
;;
|
||||||
|
initrd* | INITRD* )
|
||||||
|
initrd="$val"
|
||||||
|
;;
|
||||||
|
append* | APPEND* )
|
||||||
|
if [ "$kexectype" = "multiboot" -o "$kexectype" = "xen" ]; then
|
||||||
|
syslinux_multiboot_append
|
||||||
|
else
|
||||||
|
append="$val"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
state="search"
|
||||||
|
while read line
|
||||||
|
do
|
||||||
|
case $state in
|
||||||
|
search)
|
||||||
|
search_entry
|
||||||
|
;;
|
||||||
|
grub)
|
||||||
|
grub_entry
|
||||||
|
;;
|
||||||
|
syslinux)
|
||||||
|
syslinux_entry
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done < "$file"
|
||||||
|
|
||||||
|
# handle EOF case
|
||||||
|
if [ "$state" = "syslinux" ]; then
|
||||||
|
syslinux_end
|
||||||
|
fi
|
61
initrd/bin/kexec-save-default
Executable file
61
initrd/bin/kexec-save-default
Executable file
@ -0,0 +1,61 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# Save these options to be the persistent default
|
||||||
|
set -e -o pipefail
|
||||||
|
. /etc/functions
|
||||||
|
|
||||||
|
while getopts "b:d:p:e:i:" arg; do
|
||||||
|
case $arg in
|
||||||
|
b) bootdir="$OPTARG" ;;
|
||||||
|
d) paramsdev="$OPTARG" ;;
|
||||||
|
p) paramsdir="$OPTARG" ;;
|
||||||
|
i) index="$OPTARG" ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ -z "$bootdir" -o -z "$index" ]; then
|
||||||
|
die "Usage: $0 -b /boot -i menu_option "
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$paramsdev" ]; then
|
||||||
|
paramsdev="$bootdir"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$paramsdir" ]; then
|
||||||
|
paramsdir="$bootdir"
|
||||||
|
fi
|
||||||
|
|
||||||
|
TMP_MENU_FILE="/tmp/kexec/kexec_menu.txt"
|
||||||
|
ENTRY_FILE="$paramsdir/kexec_default.$index.txt"
|
||||||
|
HASH_FILE="$paramsdir/kexec_default_hashes.txt"
|
||||||
|
|
||||||
|
if [ ! -r "$TMP_MENU_FILE" ]; then
|
||||||
|
die "No menu options available, please run kexec-select-boot"
|
||||||
|
fi
|
||||||
|
|
||||||
|
entry=`head -n $index $TMP_MENU_FILE | tail -1`
|
||||||
|
if [ -z "$entry" ]; then
|
||||||
|
die "Invalid menu index $index"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# try to switch to rw mode
|
||||||
|
mount -o rw,remount $paramsdev
|
||||||
|
|
||||||
|
if [ ! -d $paramsdir ]; then
|
||||||
|
mkdir -p $paramsdir \
|
||||||
|
|| die "Failed to create params directory"
|
||||||
|
fi
|
||||||
|
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 \
|
||||||
|
|| die "Failed to create hashes of boot files"
|
||||||
|
if [ ! -r $ENTRY_FILE -o ! -r $HASH_FILE ]; then
|
||||||
|
die "Failed to write default config"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# sign and auto-roll config counter
|
||||||
|
kexec-sign-config -p $paramsdir -u \
|
||||||
|
|| die "Failed to sign default config"
|
||||||
|
|
||||||
|
# switch back to ro mode
|
||||||
|
mount -o ro,remount $paramsdev
|
63
initrd/bin/kexec-save-key
Executable file
63
initrd/bin/kexec-save-key
Executable file
@ -0,0 +1,63 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# Generate a TPM key used to unlock LUKS disks
|
||||||
|
set -e -o pipefail
|
||||||
|
. /etc/functions
|
||||||
|
|
||||||
|
lvm_volume_group=""
|
||||||
|
while getopts "p:d:l:" arg; do
|
||||||
|
case $arg in
|
||||||
|
p) paramsdir="$OPTARG" ;;
|
||||||
|
d) paramsdev="$OPTARG" ;;
|
||||||
|
l) lvm_volume_group="$OPTARG" ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
shift `expr $OPTIND - 1`
|
||||||
|
key_devices="$@"
|
||||||
|
|
||||||
|
if [ -z "$paramsdir" ]; then
|
||||||
|
die "Usage: $0 -p /boot [-l qubes_dom0] [/dev/sda2 /dev/sda5 ...] "
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$paramsdev" ]; then
|
||||||
|
paramsdev="$paramsdir"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -n "$lvm_volume_group" ]; then
|
||||||
|
lvm vgchange -a y $lvm_volume_group \
|
||||||
|
|| die "Failed to activate the LVM group"
|
||||||
|
|
||||||
|
for dev in /dev/$lvm_volume_group/*; do
|
||||||
|
key_devices="$key_devices $dev"
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$key_devices" ]; then
|
||||||
|
die "No devices specified for TPM key insertion"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# try to switch to rw mode
|
||||||
|
mount -o rw,remount $paramsdev
|
||||||
|
|
||||||
|
rm -f $paramsdir/kexec_key_lvm.txt || true
|
||||||
|
if [ -n "$lvm_volume_group" ]; then
|
||||||
|
echo "$lvm_volume_group" > $paramsdir/kexec_key_lvm.txt \
|
||||||
|
|| die "Failed to write lvm group to key config "
|
||||||
|
fi
|
||||||
|
|
||||||
|
rm -f $paramsdir/kexec_key_devices.txt || true
|
||||||
|
for dev in $key_devices; do
|
||||||
|
uuid=`cryptsetup luksUUID "$dev" 2>/dev/null` \
|
||||||
|
|| die "Failed to get UUID for device $dev"
|
||||||
|
echo "$dev $uuid" >> $paramsdir/kexec_key_devices.txt \
|
||||||
|
|| die "Failed to add $dev:$uuid to key devices config"
|
||||||
|
done
|
||||||
|
|
||||||
|
kexec-seal-key $paramsdir \
|
||||||
|
|| die "Failed to save and generate key in TPM"
|
||||||
|
|
||||||
|
# sign and auto-roll config counter
|
||||||
|
kexec-sign-config -p $paramsdir -u \
|
||||||
|
|| die "Failed to sign updated config"
|
||||||
|
|
||||||
|
# switch back to ro mode
|
||||||
|
mount -o ro,remount $paramsdev
|
@ -1,7 +1,8 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
# This will generate a disk encryption key and seal / ecncrypt
|
# This will generate a disk encryption key and seal / ecncrypt
|
||||||
# with the current PCRs and then store it in the TPM NVRAM.
|
# with the current PCRs and then store it in the TPM NVRAM.
|
||||||
# It will then need to be bundled into initrd that is booted with Qubes.
|
# It will then need to be bundled into initrd that is booted.
|
||||||
|
set -e -o pipefail
|
||||||
|
|
||||||
TPM_INDEX=3
|
TPM_INDEX=3
|
||||||
TPM_SIZE=312
|
TPM_SIZE=312
|
||||||
@ -12,10 +13,27 @@ RECOVERY_KEY="/tmp/secret/recovery.key"
|
|||||||
. /etc/functions
|
. /etc/functions
|
||||||
. /etc/config
|
. /etc/config
|
||||||
|
|
||||||
# Activate the LVM volume group
|
paramsdir=$1
|
||||||
VOLUME_GROUP=qubes_dom0
|
if [ -z "$paramsdir" ]; then
|
||||||
lvm vgchange -a y $VOLUME_GROUP \
|
die "Usage $0 /boot"
|
||||||
|| die "$VOLUME_GROUP: unable to activate volume group"
|
fi
|
||||||
|
|
||||||
|
KEY_DEVICES="$paramsdir/kexec_key_devices.txt"
|
||||||
|
KEY_LVM="$paramsdir/kexec_key_lvm.txt"
|
||||||
|
|
||||||
|
if [ ! -r "$KEY_DEVICES" ]; then
|
||||||
|
die "No devices defined for disk encryption"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -r "$KEY_LVM" ]; then
|
||||||
|
# Activate the LVM volume group
|
||||||
|
VOLUME_GROUP=`cat $KEY_LVM`
|
||||||
|
if [ -z "$VOLUME_GROUP" ]; 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
|
||||||
|
|
||||||
# Key slot 0 is the manual recovery pass phrase
|
# Key slot 0 is the manual recovery pass phrase
|
||||||
# that they user entered when they installed Qubes,
|
# that they user entered when they installed Qubes,
|
||||||
@ -24,15 +42,6 @@ read -s -p "Enter disk recovery key: " disk_password
|
|||||||
echo -n "$disk_password" > "$RECOVERY_KEY"
|
echo -n "$disk_password" > "$RECOVERY_KEY"
|
||||||
echo
|
echo
|
||||||
|
|
||||||
# Remove all the old keys from slot 1
|
|
||||||
for dev in /dev/$VOLUME_GROUP/*; do
|
|
||||||
echo "++++++ $dev: Removing old key slot"
|
|
||||||
cryptsetup luksKillSlot \
|
|
||||||
--key-file "$RECOVERY_KEY" \
|
|
||||||
$dev 1 \
|
|
||||||
|| warn "$dev: ignoring problem"
|
|
||||||
done
|
|
||||||
|
|
||||||
read -s -p "New disk unlock password for booting: " key_password
|
read -s -p "New disk unlock password for booting: " key_password
|
||||||
echo
|
echo
|
||||||
read -s -p "Repeat unlock code: " key_password2
|
read -s -p "Repeat unlock code: " key_password2
|
||||||
@ -42,6 +51,7 @@ if [ "$key_password" != "$key_password2" ]; then
|
|||||||
die "Key passwords do not match"
|
die "Key passwords do not match"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Generate key file
|
||||||
dd \
|
dd \
|
||||||
if=/dev/urandom \
|
if=/dev/urandom \
|
||||||
of="$KEY_FILE" \
|
of="$KEY_FILE" \
|
||||||
@ -50,8 +60,15 @@ dd \
|
|||||||
2>/dev/null \
|
2>/dev/null \
|
||||||
|| die "Unable to generate 128 random bytes"
|
|| die "Unable to generate 128 random bytes"
|
||||||
|
|
||||||
for dev in /dev/$VOLUME_GROUP/*; do
|
# Remove all the old keys from slot 1
|
||||||
echo "+++++ $dev: Adding key"
|
for dev in `cat "$KEY_DEVICES" | cut -d\ -f1`; do
|
||||||
|
echo "++++++ $dev: Removing old key slot"
|
||||||
|
cryptsetup luksKillSlot \
|
||||||
|
--key-file "$RECOVERY_KEY" \
|
||||||
|
$dev 1 \
|
||||||
|
|| warn "$dev: ignoring problem"
|
||||||
|
|
||||||
|
echo "++++++ $dev: Adding key"
|
||||||
cryptsetup luksAddKey \
|
cryptsetup luksAddKey \
|
||||||
--key-file "$RECOVERY_KEY" \
|
--key-file "$RECOVERY_KEY" \
|
||||||
--key-slot 1 \
|
--key-slot 1 \
|
||||||
@ -63,7 +80,7 @@ done
|
|||||||
# We don't care what ends up in PCR 6; we just want
|
# We don't care what ends up in PCR 6; we just want
|
||||||
# to get the /tmp/luksDump.txt file. We use PCR16
|
# to get the /tmp/luksDump.txt file. We use PCR16
|
||||||
# since it should still be zero
|
# since it should still be zero
|
||||||
/bin/qubes-measure-luks /dev/$VOLUME_GROUP/* \
|
cat "$KEY_DEVICES" | cut -d\ -f1 | xargs /bin/qubes-measure-luks \
|
||||||
|| die "Unable to measure the LUKS headers"
|
|| die "Unable to measure the LUKS headers"
|
||||||
luks_pcr=`tpm calcfuturepcr -ix 16 -if /tmp/luksDump.txt`
|
luks_pcr=`tpm calcfuturepcr -ix 16 -if /tmp/luksDump.txt`
|
||||||
|
|
||||||
@ -91,7 +108,8 @@ tpm sealfile2 \
|
|||||||
-ix 6 $luks_pcr \
|
-ix 6 $luks_pcr \
|
||||||
|| die "Unable to seal secret"
|
|| die "Unable to seal secret"
|
||||||
|
|
||||||
rm -f "$KEY_FILE"
|
rm -f "$KEY_FILE" \
|
||||||
|
|| die "Failed to delete key file"
|
||||||
|
|
||||||
# try it without the owner password first
|
# try it without the owner password first
|
||||||
if ! tpm nv_writevalue \
|
if ! tpm nv_writevalue \
|
||||||
@ -124,3 +142,4 @@ if ! tpm nv_writevalue \
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
rm "$TPM_SEALED" \
|
rm "$TPM_SEALED" \
|
||||||
|
|| warn "Failed to delete the sealed secret - continuing"
|
294
initrd/bin/kexec-select-boot
Executable file
294
initrd/bin/kexec-select-boot
Executable file
@ -0,0 +1,294 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# Generic configurable boot script via kexec
|
||||||
|
set -e -o pipefail
|
||||||
|
. /etc/config
|
||||||
|
. /etc/functions
|
||||||
|
|
||||||
|
add=""
|
||||||
|
remove=""
|
||||||
|
config="*.cfg"
|
||||||
|
unique="n"
|
||||||
|
valid_hash="n"
|
||||||
|
valid_global_hash="n"
|
||||||
|
valid_rollback="n"
|
||||||
|
while getopts "b:d:p:a:r:c:ui" arg; do
|
||||||
|
case $arg in
|
||||||
|
b) bootdir="$OPTARG" ;;
|
||||||
|
d) paramsdev="$OPTARG" ;;
|
||||||
|
p) paramsdir="$OPTARG" ;;
|
||||||
|
a) add="$OPTARG" ;;
|
||||||
|
r) remove="$OPTARG" ;;
|
||||||
|
c) config="$OPTARG" ;;
|
||||||
|
u) unique="y" ;;
|
||||||
|
i) valid_hash="y"; valid_rollback="y" ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ -z "$bootdir" ]; then
|
||||||
|
die "Usage: $0 -b /boot"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$paramsdev" ]; then
|
||||||
|
paramsdev="$bootdir"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$paramsdir" ]; then
|
||||||
|
paramsdir="$bootdir"
|
||||||
|
fi
|
||||||
|
|
||||||
|
verify_global_hashes()
|
||||||
|
{
|
||||||
|
echo "+++ Checking verified boot hash file "
|
||||||
|
# Check the hashes of all the files
|
||||||
|
if cd $bootdir && sha256sum -c "$TMP_HASH_FILE" ; then
|
||||||
|
echo "+++ Verified boot hashes "
|
||||||
|
valid_hash='y'
|
||||||
|
valid_global_hash='y'
|
||||||
|
else
|
||||||
|
die "$TMP_HASH_FILE: boot hash mismatch"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
verify_rollback_counter()
|
||||||
|
{
|
||||||
|
TPM_COUNTER=`grep counter $TMP_ROLLBACK_FILE | cut -d- -f2`
|
||||||
|
if [ -z "$TPM_COUNTER" ]; then
|
||||||
|
die "$TMP_ROLLBACK_FILE: TPM counter not found?"
|
||||||
|
fi
|
||||||
|
|
||||||
|
read_tpm_counter $TPM_COUNTER \
|
||||||
|
|| die "Failed to read TPM counter"
|
||||||
|
|
||||||
|
sha256sum -c $TMP_ROLLBACK_FILE \
|
||||||
|
|| die "Invalid TPM counter state"
|
||||||
|
|
||||||
|
valid_rollback="y"
|
||||||
|
}
|
||||||
|
|
||||||
|
first_menu="y"
|
||||||
|
get_menu_option() {
|
||||||
|
num_options=`cat $TMP_MENU_FILE | wc -l`
|
||||||
|
if [ $num_options -eq 0 ]; then
|
||||||
|
die "No boot options"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ $num_options -eq 1 -a $first_menu = "y" ]; then
|
||||||
|
option_index=1
|
||||||
|
else
|
||||||
|
echo "+++ Select your boot option:"
|
||||||
|
n=0
|
||||||
|
while read option
|
||||||
|
do
|
||||||
|
parse_option
|
||||||
|
n=`expr $n + 1`
|
||||||
|
echo "$n. $name [$kernel]"
|
||||||
|
done < $TMP_MENU_FILE
|
||||||
|
|
||||||
|
read \
|
||||||
|
-p "Choose the boot option [1-$n, a to abort]: " \
|
||||||
|
option_index
|
||||||
|
|
||||||
|
if [ "$option_index" = "a" ]; then
|
||||||
|
die "Aborting boot attempt"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
first_menu="n"
|
||||||
|
|
||||||
|
option=`head -n $option_index $TMP_MENU_FILE | tail -1`
|
||||||
|
parse_option
|
||||||
|
}
|
||||||
|
|
||||||
|
confirm_menu_option() {
|
||||||
|
echo "+++ Please confirm the boot details for $name:"
|
||||||
|
echo $option
|
||||||
|
|
||||||
|
read \
|
||||||
|
-n 1 \
|
||||||
|
-p "Confirm selection by pressing 'y', make default with 'd': " \
|
||||||
|
option_confirm
|
||||||
|
echo
|
||||||
|
}
|
||||||
|
|
||||||
|
parse_option() {
|
||||||
|
name=`echo $option | cut -d\| -f1`
|
||||||
|
kernel=`echo $option | cut -d\| -f3`
|
||||||
|
}
|
||||||
|
|
||||||
|
scan_options() {
|
||||||
|
echo "+++ Scanning for unsigned boot options"
|
||||||
|
option_file="/tmp/kexec_options.txt"
|
||||||
|
if [ -r $option_file ]; then rm $option_file; fi
|
||||||
|
for i in `find $bootdir -name "$config"`; do
|
||||||
|
kexec-parse-boot "$bootdir" "$i" >> $option_file
|
||||||
|
done
|
||||||
|
if [ ! -r $option_file ]; then
|
||||||
|
die "Failed to parse any boot options"
|
||||||
|
fi
|
||||||
|
if [ "$unique" = 'y' ]; then
|
||||||
|
sort $option_file | uniq > $TMP_MENU_FILE
|
||||||
|
else
|
||||||
|
cp $option_file $TMP_MENU_FILE
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
save_default_option() {
|
||||||
|
read \
|
||||||
|
-n 1 \
|
||||||
|
-p "Saving a default will modify the disk. Proceed? (y/n): " \
|
||||||
|
default_confirm
|
||||||
|
echo
|
||||||
|
|
||||||
|
if [ "$default_confirm" = "y" ]; then
|
||||||
|
if kexec-save-default \
|
||||||
|
-b "$bootdir" \
|
||||||
|
-d "$paramsdev" \
|
||||||
|
-p "$paramsdir" \
|
||||||
|
-i "$option_index" \
|
||||||
|
; then
|
||||||
|
echo "+++ Saved defaults to device"
|
||||||
|
sleep 2
|
||||||
|
default_failed="n"
|
||||||
|
return
|
||||||
|
else
|
||||||
|
echo "Failed to save defaults"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
option_confirm="n"
|
||||||
|
}
|
||||||
|
|
||||||
|
default_select() {
|
||||||
|
# Attempt boot with expected parameters
|
||||||
|
|
||||||
|
# Check that entry matches that which is expected from menu
|
||||||
|
default_index=`basename "$TMP_DEFAULT_FILE" | cut -d. -f 2`
|
||||||
|
|
||||||
|
# Check to see if entries have changed - useful for detecting grub update
|
||||||
|
expectedoption=`cat $TMP_DEFAULT_FILE`
|
||||||
|
option=`head -n $default_index $TMP_MENU_FILE | tail -1`
|
||||||
|
if [ "$option" != "$expectedoption" ]; then
|
||||||
|
warn "!!! Boot entry has changed - please set a new default"
|
||||||
|
sleep 5
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
parse_option
|
||||||
|
|
||||||
|
# Enforce that default option hashes are valid
|
||||||
|
echo "+++ Checking verified default boot hash file "
|
||||||
|
# Check the hashes of all the files
|
||||||
|
if cd $bootdir && sha256sum -c "$TMP_DEFAULT_HASH_FILE" ; then
|
||||||
|
echo "+++ Verified default boot hashes "
|
||||||
|
valid_hash='y'
|
||||||
|
else
|
||||||
|
die "$TMP_DEFAULT_HASH_FILE: default boot hash mismatch"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "+++ Executing default boot for $name:"
|
||||||
|
do_boot
|
||||||
|
warn "Failed to boot default option"
|
||||||
|
}
|
||||||
|
|
||||||
|
user_select() {
|
||||||
|
# No default expected boot parameters, ask user
|
||||||
|
|
||||||
|
option_confirm=""
|
||||||
|
while [ "$option_confirm" != "y" -a "$option_confirm" != "d" ]
|
||||||
|
do
|
||||||
|
get_menu_option
|
||||||
|
confirm_menu_option
|
||||||
|
|
||||||
|
if [ "$option_confirm" = 'd' ]; then
|
||||||
|
save_default_option
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ "$option_confirm" = "d" ]; then
|
||||||
|
# reload settings to reflect new default
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
do_boot
|
||||||
|
}
|
||||||
|
|
||||||
|
do_boot()
|
||||||
|
{
|
||||||
|
if [ "$CONFIG_BOOT_REQ_ROLLBACK" = "y" -a "$valid_rollback" = "n" ]; then
|
||||||
|
warn "!!! Missing required rollback counter state"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$CONFIG_BOOT_REQ_HASH" = "y" -a "$valid_hash" = "n" ]; then
|
||||||
|
warn "!!! Missing required boot hashes"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -r "$TMP_KEY_DEVICES" ]; then
|
||||||
|
INITRD=`kexec-boot -b "$bootdir" -e "$option" -i` \
|
||||||
|
|| die "!!! Failed to extract the initrd from boot option"
|
||||||
|
if [ -z "$INITRD" ]; then
|
||||||
|
die "!!! No initrd file found in boot option"
|
||||||
|
fi
|
||||||
|
|
||||||
|
kexec-insert-key $INITRD \
|
||||||
|
|| die "!!! Failed to insert disk key into a new initrd"
|
||||||
|
|
||||||
|
kexec-boot -b "$bootdir" -e "$option" \
|
||||||
|
-a "$add" -r "$remove" -o "/tmp/secret/initrd.cpio" \
|
||||||
|
|| die "!!! Failed to boot w/ options: $option"
|
||||||
|
else
|
||||||
|
kexec-boot -b "$bootdir" -e "$option" -a "$add" -r "$remove" \
|
||||||
|
|| die "!!! Failed to boot w/ options: $option"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
while true; do
|
||||||
|
check_config $paramsdir
|
||||||
|
TMP_DEFAULT_FILE=`find /tmp/kexec/kexec_default.*.txt 2>/dev/null | head -1` || true
|
||||||
|
TMP_MENU_FILE="/tmp/kexec/kexec_menu.txt"
|
||||||
|
TMP_HASH_FILE="/tmp/kexec/kexec_hashes.txt"
|
||||||
|
TMP_DEFAULT_HASH_FILE="/tmp/kexec/kexec_default_hashes.txt"
|
||||||
|
TMP_ROLLBACK_FILE="/tmp/kexec/kexec_rollback.txt"
|
||||||
|
TMP_KEY_DEVICES="/tmp/kexec/kexec_key_devices.txt"
|
||||||
|
TMP_KEY_LVM="/tmp/kexec/kexec_key_lvm.txt"
|
||||||
|
|
||||||
|
if [ ! -r "$TMP_KEY_DEVICES" ]; then
|
||||||
|
# Extend PCR4 as soon as possible
|
||||||
|
tpm extend -ix 4 -ic generic \
|
||||||
|
|| die "Failed to extend PCR 4"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# if no saved options, scan the boot directory and generate
|
||||||
|
if [ ! -r "$TMP_MENU_FILE" ]; then
|
||||||
|
scan_options
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Optionally enforce device file hashes
|
||||||
|
if [ -r "$TMP_HASH_FILE" ]; then
|
||||||
|
valid_global_hash="n"
|
||||||
|
|
||||||
|
verify_global_hashes
|
||||||
|
|
||||||
|
if [ "$valid_global_hash" = "n" ]; then
|
||||||
|
die "Failed to verify global hashes"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -r "$TMP_ROLLBACK_FILE" ]; then
|
||||||
|
# in the case of iso boot with a rollback file, do not assume valid
|
||||||
|
valid_rollback="n"
|
||||||
|
|
||||||
|
verify_rollback_counter
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$default_failed" != "y" \
|
||||||
|
-a -r "$TMP_DEFAULT_FILE" \
|
||||||
|
-a -r "$TMP_DEFAULT_HASH_FILE" ] \
|
||||||
|
; then
|
||||||
|
default_select
|
||||||
|
default_failed="y"
|
||||||
|
else
|
||||||
|
user_select
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
die "!!! Shouldn't get here""
|
59
initrd/bin/kexec-sign-config
Executable file
59
initrd/bin/kexec-sign-config
Executable file
@ -0,0 +1,59 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# Sign a valid directory of kexec params
|
||||||
|
set -e -o pipefail
|
||||||
|
. /etc/functions
|
||||||
|
|
||||||
|
rollback="n"
|
||||||
|
update_counter="n"
|
||||||
|
while getopts "p:c:u" arg; do
|
||||||
|
case $arg in
|
||||||
|
p) paramsdir="$OPTARG" ;;
|
||||||
|
c) counter="$OPTARG"; rollback="y" ;;
|
||||||
|
u) update_counter="y"; rollback="y" ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ -z "$paramsdir" ]; then
|
||||||
|
die "Usage: $0 -p /boot [ -u | -c counter ]"
|
||||||
|
fi
|
||||||
|
|
||||||
|
confirm_gpg_card
|
||||||
|
|
||||||
|
if [ "$rollback" = "y" ]; then
|
||||||
|
rollback_file="$paramsdir/kexec_rollback.txt"
|
||||||
|
|
||||||
|
if [ -n "$counter" ]; then
|
||||||
|
# use existing counter
|
||||||
|
read_tpm_counter $counter \
|
||||||
|
|| die "$paramsdir: Unable to read tpm counter '$counter'"
|
||||||
|
else
|
||||||
|
# increment counter
|
||||||
|
check_tpm_counter $rollback_file \
|
||||||
|
|| die "$paramsdir: Unable to find/create tpm counter"
|
||||||
|
counter="$TPM_COUNTER"
|
||||||
|
|
||||||
|
increment_tpm_counter $counter \
|
||||||
|
|| die "$paramsdir: Unable to increment tpm counter"
|
||||||
|
fi
|
||||||
|
|
||||||
|
sha256sum /tmp/counter-$counter > $rollback_file \
|
||||||
|
|| die "$paramsdir: Unable to create rollback file"
|
||||||
|
fi
|
||||||
|
|
||||||
|
param_files=`find $paramsdir/kexec*.txt`
|
||||||
|
if [ -z "$param_files" ]; then
|
||||||
|
die "$paramsdir: No kexec parameter files to sign"
|
||||||
|
fi
|
||||||
|
|
||||||
|
for tries in 1 2 3; do
|
||||||
|
if sha256sum $param_files | gpg \
|
||||||
|
--digest-algo SHA256 \
|
||||||
|
--detach-sign \
|
||||||
|
-a \
|
||||||
|
> $paramsdir/kexec.sig \
|
||||||
|
; then
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
die "$paramsdir: Unable to sign kexec hashes"
|
45
initrd/bin/kexec-unseal-key
Executable file
45
initrd/bin/kexec-unseal-key
Executable file
@ -0,0 +1,45 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# This will unseal and unecncrypt the drive encryption key from the TPM
|
||||||
|
# The TOTP secret will be shown to the user on each encryption attempt.
|
||||||
|
# It will then need to be bundled into initrd that is booted with Qubes.
|
||||||
|
set -e -o pipefail
|
||||||
|
|
||||||
|
TPM_INDEX=3
|
||||||
|
TPM_SIZE=312
|
||||||
|
|
||||||
|
. /etc/functions
|
||||||
|
mkdir -p /tmp/secret
|
||||||
|
|
||||||
|
sealed_file="/tmp/secret/sealed.key"
|
||||||
|
key_file="$1"
|
||||||
|
|
||||||
|
if [ -z "$key_file" ]; then
|
||||||
|
key_file="/tmp/secret/secret.key"
|
||||||
|
fi
|
||||||
|
|
||||||
|
tpm nv_readvalue \
|
||||||
|
-in "$TPM_INDEX" \
|
||||||
|
-sz "$TPM_SIZE" \
|
||||||
|
-of "$sealed_file" \
|
||||||
|
|| die "Unable to read key from TPM NVRAM"
|
||||||
|
|
||||||
|
for tries in 1 2 3; do
|
||||||
|
read -s -p "Enter unlock password: " tpm_password
|
||||||
|
echo
|
||||||
|
|
||||||
|
if tpm unsealfile \
|
||||||
|
-if "$sealed_file" \
|
||||||
|
-of "$key_file" \
|
||||||
|
-pwdd "$tpm_password" \
|
||||||
|
-hk 40000000 \
|
||||||
|
; then
|
||||||
|
# should be okay if this fails
|
||||||
|
rm -f /tmp/secret/sealed || true
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
pcrs
|
||||||
|
warn "Unable to unseal disk encryption key"
|
||||||
|
done
|
||||||
|
|
||||||
|
die "Retry count exceeded..."
|
@ -28,4 +28,8 @@ if [ ! -d /media ]; then
|
|||||||
mkdir /media
|
mkdir /media
|
||||||
fi
|
fi
|
||||||
|
|
||||||
mount -o ro $1 /media
|
if [ -z "$1" ]; then
|
||||||
|
mount -o ro /media
|
||||||
|
else
|
||||||
|
mount -o ro $1 /media
|
||||||
|
fi
|
||||||
|
@ -1,38 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
# Final stage to start qubes given a Xen, dom0 kernel and initrd
|
|
||||||
# get the UUID of the root file system
|
|
||||||
# busybox blkid doesn't have a "just the UUID" option
|
|
||||||
. /etc/functions
|
|
||||||
. /etc/config
|
|
||||||
|
|
||||||
XEN="$1"
|
|
||||||
KERNEL="$2"
|
|
||||||
INITRD="$3"
|
|
||||||
|
|
||||||
if [ -z "$XEN" -o -z "$KERNEL" -o -z "$INITRD" ]; then
|
|
||||||
die "Usage: $0 /boot/xen... /boot/vmlinuz... /boot/initramfs..."
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Activate the dom0 group, if it isn't already active
|
|
||||||
lvm vgchange -a y "$CONFIG_QUBES_VG" \
|
|
||||||
|| die "$CONFIG_QUBES_VG: LVM volume group activate failed"
|
|
||||||
|
|
||||||
ROOT_UUID=`blkid /dev/$CONFIG_QUBES_VG/00 | cut -d\" -f2`
|
|
||||||
if [ -z "$ROOT_UUID" ]; then
|
|
||||||
die "$CONFIG_QUBES_VG/00: No UUID for /"
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "$CONFIG_QUBES_VG/00: UUID=$ROOT_UUID"
|
|
||||||
|
|
||||||
# command line arguments are include in the signature on this script,
|
|
||||||
echo '+++ Loading kernel and initrd'
|
|
||||||
kexec \
|
|
||||||
-l \
|
|
||||||
--module "$KERNEL root=/dev/mapper/luks-$ROOT_UUID ro rd.qubes.hide_all_usb" \
|
|
||||||
--module "$INITRD" \
|
|
||||||
--command-line "no-real-mode reboot=no" \
|
|
||||||
"${XEN}" \
|
|
||||||
|| die "kexec load failed"
|
|
||||||
|
|
||||||
echo "+++ Starting Qubes..."
|
|
||||||
exec kexec -e
|
|
@ -1,83 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
# Boot a Qubes installation that has already been setup.
|
|
||||||
# This depends on the PCR 4 being "normal-boot":
|
|
||||||
# f8fa3b6e32e7c6fe04c366e74636e505b28f3b0d
|
|
||||||
# which is only set if the top level /init script has started
|
|
||||||
# without user intervention or dropping into a recovery shell.
|
|
||||||
|
|
||||||
. /etc/functions
|
|
||||||
. /etc/config
|
|
||||||
|
|
||||||
if [ "$1" = "recovery" ]; then
|
|
||||||
warn "Recovery mode boot; ignoring key failures"
|
|
||||||
RECOVERY=1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# TODO: Allow /boot to be encrypted?
|
|
||||||
# This would require a different TPM key, a user passphrase to decrypt it,
|
|
||||||
# or loading the USB modules to talk to a Yubikey to get the thing.
|
|
||||||
if ! grep -q /boot /proc/mounts ; then
|
|
||||||
mount -o ro "$CONFIG_QUBES_BOOT_DEV" /boot \
|
|
||||||
|| recovery '$CONFIG_BOOT_DEV: Unable to mount /boot'
|
|
||||||
fi
|
|
||||||
|
|
||||||
BOOT_HASHES=/boot/boot.hashes
|
|
||||||
if [ ! -r "$BOOT_HASHES" ]; then
|
|
||||||
recovery "$BOOT_HASHES does not exist; re-run qubes-update"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Verify the signature on the hashes
|
|
||||||
gpgv "$BOOT_HASHES.asc" "$BOOT_HASHES" \
|
|
||||||
|| recovery 'boot hashes signature failed'
|
|
||||||
|
|
||||||
# Retrieve the TPM counter ID and generate its current value
|
|
||||||
TPM_COUNTER=`grep counter $BOOT_HASHES | cut -d- -f2`
|
|
||||||
if [ -z "$TPM_COUNTER" ]; then
|
|
||||||
recovery "$BOOT_HASHES: TPM counter not found?"
|
|
||||||
fi
|
|
||||||
|
|
||||||
tpm counter_read -ix "$TPM_COUNTER" | tee "/tmp/counter-$TPM_COUNTER"
|
|
||||||
|
|
||||||
# Check the hashes of all the files
|
|
||||||
sha256sum -c "$BOOT_HASHES" \
|
|
||||||
|| recovery "$BOOT_HASHES: hash mismatch"
|
|
||||||
|
|
||||||
XEN=`grep /boot/xen $BOOT_HASHES | cut -d\ -f3 | tail -1`
|
|
||||||
KERNEL=`grep /boot/vmlin $BOOT_HASHES | cut -d\ -f3 | tail -1`
|
|
||||||
INITRD=`grep /boot/initram $BOOT_HASHES | cut -d\ -f3 | tail -1`
|
|
||||||
|
|
||||||
# Activate the dom0 group
|
|
||||||
lvm vgchange -a y "$CONFIG_QUBES_VG" \
|
|
||||||
|| recovery "$CONFIG_QUBES_VG: LVM volume group activate failed"
|
|
||||||
|
|
||||||
# Measure the LUKS headers before we unseal the disk key
|
|
||||||
qubes-measure-luks /dev/$CONFIG_QUBES_VG/* \
|
|
||||||
|| recovery "LUKS measure failed"
|
|
||||||
|
|
||||||
# Unpack the initrd and fixup the /etc/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
|
|
||||||
mkdir -p "$INITRD_DIR/etc"
|
|
||||||
|
|
||||||
# Attempt to unseal the disk key from the TPM
|
|
||||||
# should we give this some number of tries?
|
|
||||||
if ! unseal-key "$INITRD_DIR/secret.key" ; then
|
|
||||||
warn 'Unseal disk key failed'
|
|
||||||
if [ -z "$RECOVERY" ]; then
|
|
||||||
recovery 'Starting recovery shell'
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Override PCR 4 so that user can't read the key
|
|
||||||
tpm extend -ix 4 -ic qubes \
|
|
||||||
|| recovery 'Unable to scramble PCR'
|
|
||||||
|
|
||||||
echo '+++ Building initrd'
|
|
||||||
( cd "$INITRD_DIR" ; find . | cpio -H newc -o ) > "$SECRET_CPIO"
|
|
||||||
cat "$INITRD" >> "$SECRET_CPIO"
|
|
||||||
|
|
||||||
/bin/qubes-boot "$XEN" "$KERNEL" "$SECRET_CPIO"
|
|
||||||
|
|
||||||
recovery "Something failed..."
|
|
@ -1,29 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
# Attempt to install qubes using the recovery shell and the pre-built
|
|
||||||
# version of Xen
|
|
||||||
|
|
||||||
. /etc/functions
|
|
||||||
|
|
||||||
DEV="$1"
|
|
||||||
if [ -z "$DEV" ]; then
|
|
||||||
DEV="/dev/sdb2"
|
|
||||||
fi
|
|
||||||
|
|
||||||
mount-usb "$DEV" \
|
|
||||||
|| die "$DEV: Unable to mount?"
|
|
||||||
|
|
||||||
cd /media/efi/boot \
|
|
||||||
|| die "$DEV: cd to /media/efi/boot failed?"
|
|
||||||
|
|
||||||
kexec -l \
|
|
||||||
--module "./vmlinuz inst.stage2=hd:LABEL=Qubes-R3.2-x86_64" \
|
|
||||||
--module "./initrd.img" \
|
|
||||||
--command-line "no-real-mode reboot=no" \
|
|
||||||
/bin/xen.gz \
|
|
||||||
|| die "$DEV: kexec -l failed?"
|
|
||||||
|
|
||||||
warn "Starting installer..."
|
|
||||||
sleep 1
|
|
||||||
kexec -e
|
|
||||||
|
|
||||||
die "$DEV: kexec -e failed?"
|
|
@ -1,86 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
# Update the /boot partition signatures
|
|
||||||
set -o pipefail
|
|
||||||
. /etc/functions
|
|
||||||
|
|
||||||
XEN="$1"
|
|
||||||
KERNEL="$2"
|
|
||||||
INITRD="$3"
|
|
||||||
BOOT_HASHES="/boot/boot.hashes"
|
|
||||||
|
|
||||||
if [ -z "$XEN" -o -z "$KERNEL" -o -z "$INITRD" ]; then
|
|
||||||
die "Usage: $0 /boot/xen... /boot/vmlinuz... /boot/initramfs..."
|
|
||||||
fi
|
|
||||||
|
|
||||||
# setup the USB so we can reach the GPG card
|
|
||||||
if ! lsmod | grep -q ehci_hcd; then
|
|
||||||
insmod /lib/modules/ehci-hcd.ko \
|
|
||||||
|| die "ehci_hcd: module load failed"
|
|
||||||
fi
|
|
||||||
if ! lsmod | grep -q ehci_pci; then
|
|
||||||
insmod /lib/modules/ehci-pci.ko \
|
|
||||||
|| die "ehci_pci: module load failed"
|
|
||||||
fi
|
|
||||||
if ! lsmod | grep -q xhci_hcd; then
|
|
||||||
insmod /lib/modules/xhci-hcd.ko \
|
|
||||||
|| die "ehci_hcd: module load failed"
|
|
||||||
fi
|
|
||||||
if ! lsmod | grep -q xhci_pci; then
|
|
||||||
insmod /lib/modules/xhci-pci.ko \
|
|
||||||
|| die "ehci_pci: module load failed"
|
|
||||||
sleep 2
|
|
||||||
fi
|
|
||||||
|
|
||||||
gpg --card-status \
|
|
||||||
|| die "gpg card read failed"
|
|
||||||
|
|
||||||
# if the /boot.hashes file already exists, read the TPM counter ID
|
|
||||||
# from it.
|
|
||||||
if [ -r "$BOOT_HASHES" ]; then
|
|
||||||
TPM_COUNTER=`grep counter- "$BOOT_HASHES" | cut -d- -f2`
|
|
||||||
else
|
|
||||||
warn "$BOOT_HASHES does not exist; creating new TPM counter"
|
|
||||||
read -s -p "TPM Owner password: " tpm_password
|
|
||||||
echo
|
|
||||||
tpm counter_create \
|
|
||||||
-pwdo "$tpm_password" \
|
|
||||||
-pwdc '' \
|
|
||||||
-la 3135106223 \
|
|
||||||
| tee /tmp/counter \
|
|
||||||
|| die "Unable to create TPM counter"
|
|
||||||
TPM_COUNTER=`cut -d: -f1 < /tmp/counter`
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -z "$TPM_COUNTER" ]; then
|
|
||||||
die "$BOOT_HASHES: TPM Counter not found?"
|
|
||||||
fi
|
|
||||||
|
|
||||||
mount -o rw,remount /boot \
|
|
||||||
|| die "Could not remount /boot"
|
|
||||||
|
|
||||||
tpm counter_increment -ix "$TPM_COUNTER" -pwdc '' \
|
|
||||||
| tee /tmp/counter-$TPM_COUNTER \
|
|
||||||
|| die "Counter increment failed"
|
|
||||||
|
|
||||||
sha256sum \
|
|
||||||
"$XEN" \
|
|
||||||
"$KERNEL" \
|
|
||||||
"$INITRD" \
|
|
||||||
"/tmp/counter-$TPM_COUNTER" \
|
|
||||||
| tee "$BOOT_HASHES"
|
|
||||||
|
|
||||||
for tries in 1 2 3; do
|
|
||||||
if gpg \
|
|
||||||
--digest-algo SHA256 \
|
|
||||||
--detach-sign \
|
|
||||||
-a \
|
|
||||||
"$BOOT_HASHES" \
|
|
||||||
; then
|
|
||||||
mount -o ro,remount /boot
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
warn "$BOOT_HASHES: Unable to sign boot hashes"
|
|
||||||
mount -o ro,remount /boot
|
|
||||||
exit 1
|
|
@ -1,30 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
mount -o ro -t ext4 /dev/sda1 /boot
|
|
||||||
|
|
||||||
die() { echo >&2 "$*"; exit 1; }
|
|
||||||
|
|
||||||
XEN=/boot/xen-4.6.3.gz
|
|
||||||
INITRD=/boot/initramfs-4.4.14-11.pvops.qubes.x86_64.img
|
|
||||||
KERNEL=/boot/vmlinuz-4.4.14-11.pvops.qubes.x86_64
|
|
||||||
|
|
||||||
echo "+++ Checking $XEN"
|
|
||||||
gpgv "${XEN}.asc" "${XEN}" || die "Xen signature failed"
|
|
||||||
|
|
||||||
echo "+++ Checking $INITRD"
|
|
||||||
gpgv "${INITRD}.asc" "${INITRD}" || die "Initrd signature failed"
|
|
||||||
|
|
||||||
echo "+++ Checking $KERNEL"
|
|
||||||
gpgv "${KERNEL}.asc" "${KERNEL}" || die "Kernel signature failed"
|
|
||||||
|
|
||||||
# should also check xen command line arguments!
|
|
||||||
# should also check kernel command line arguments!
|
|
||||||
|
|
||||||
kexec \
|
|
||||||
-l \
|
|
||||||
--module "${KERNEL} root=LABEL=root rhgb" \
|
|
||||||
--module "${INITRD}" \
|
|
||||||
--command-line "no-real-mode reboot=no console=vga dom0_mem=min:1024M dom0_mem=max:4096M" \
|
|
||||||
"${XEN}"
|
|
||||||
|
|
||||||
|
|
||||||
echo "Ready to start Xen: run 'kexec -e' to execute it"
|
|
@ -1,92 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
# This will unseal and unecncrypt the drive encryption key from the TPM
|
|
||||||
# The TOTP secret will be shown to the user on each encryption attempt.
|
|
||||||
# It will then need to be bundled into initrd that is booted with Qubes.
|
|
||||||
|
|
||||||
TPM_INDEX=3
|
|
||||||
TPM_SIZE=312
|
|
||||||
|
|
||||||
. /etc/functions
|
|
||||||
mkdir -p /tmp/secret
|
|
||||||
|
|
||||||
sealed_file="/tmp/secret/sealed.key"
|
|
||||||
key_file="$1"
|
|
||||||
|
|
||||||
if [ -z "$key_file" ]; then
|
|
||||||
key_file="/tmp/secret/secret.key"
|
|
||||||
fi
|
|
||||||
|
|
||||||
tpm nv_readvalue \
|
|
||||||
-in "$TPM_INDEX" \
|
|
||||||
-sz "$TPM_SIZE" \
|
|
||||||
-of "$sealed_file" \
|
|
||||||
|| die "Unable to read key from TPM NVRAM"
|
|
||||||
|
|
||||||
|
|
||||||
get_password()
|
|
||||||
{
|
|
||||||
last_half=X
|
|
||||||
|
|
||||||
while true; do
|
|
||||||
|
|
||||||
# update the TOTP code every thirty seconds
|
|
||||||
date=`date "+%Y-%m-%d %H:%M:%S"`
|
|
||||||
seconds=`date "+%s"`
|
|
||||||
half=`expr \( $seconds % 60 \) / 30`
|
|
||||||
if [ "$half" != "$last_half" ]; then
|
|
||||||
last_half=$half;
|
|
||||||
TOTP=`unseal-totp` \
|
|
||||||
|| die "TOTP code generation failed"
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo -n "$date $TOTP: "
|
|
||||||
|
|
||||||
# read the first character, non-blocking
|
|
||||||
read \
|
|
||||||
-t 1 \
|
|
||||||
-n 1 \
|
|
||||||
-s \
|
|
||||||
-p "Enter unlock password: " \
|
|
||||||
tpm_password_1 \
|
|
||||||
&& break
|
|
||||||
|
|
||||||
# nothing typed, redraw the line
|
|
||||||
echo -ne '\r'
|
|
||||||
done
|
|
||||||
|
|
||||||
# they have started typing, read the rest, blocking
|
|
||||||
if [ -z "$tpm_password_1" ]; then
|
|
||||||
# they hit enter; we should exit gracefully
|
|
||||||
tpm_password=""
|
|
||||||
else
|
|
||||||
# they hit something else, read the rest of the line
|
|
||||||
read \
|
|
||||||
-s \
|
|
||||||
-p '' \
|
|
||||||
tpm_password_2
|
|
||||||
tpm_password="$tpm_password_1$tpm_password_2"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# clean up with a newline
|
|
||||||
echo
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
for tries in 1 2 3; do
|
|
||||||
get_password
|
|
||||||
|
|
||||||
if tpm unsealfile \
|
|
||||||
-if "$sealed_file" \
|
|
||||||
-of "$key_file" \
|
|
||||||
-pwdd "$tpm_password" \
|
|
||||||
-hk 40000000 \
|
|
||||||
; then
|
|
||||||
rm -f /tmp/secret/sealed
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
pcrs
|
|
||||||
warn "Unable to unseal disk encryption key"
|
|
||||||
done
|
|
||||||
|
|
||||||
die "Retry count exceeded..."
|
|
20
initrd/bin/usb-init
Executable file
20
initrd/bin/usb-init
Executable file
@ -0,0 +1,20 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# Boot a USB installation
|
||||||
|
|
||||||
|
. /etc/functions
|
||||||
|
. /etc/config
|
||||||
|
|
||||||
|
# Confirm we have a good TOTP unseal
|
||||||
|
if ! confirm_totp ; then
|
||||||
|
recovery 'Failed to unseal TOTP'
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Extend PCR4 as soon as possible
|
||||||
|
tpm extend -ix 4 -ic usb
|
||||||
|
|
||||||
|
if [ ! "$totp_confirm" = "y" ]; then
|
||||||
|
recovery "Failed to confirm validity of TOTP"
|
||||||
|
fi
|
||||||
|
|
||||||
|
usb-scan
|
||||||
|
recovery "Something failed during USB boot"
|
67
initrd/bin/usb-scan
Executable file
67
initrd/bin/usb-scan
Executable file
@ -0,0 +1,67 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# Scan for USB installation options
|
||||||
|
set -e -o pipefail
|
||||||
|
. /etc/functions
|
||||||
|
. /etc/config
|
||||||
|
|
||||||
|
# Unmount any previous boot device
|
||||||
|
if grep -q /boot /proc/mounts ; then
|
||||||
|
umount /boot \
|
||||||
|
|| die '$CONFIG_USB_BOOT_DEV: Unable to unmount /boot'
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Mount the USB boot device
|
||||||
|
if ! grep -q /media /proc/mounts ; then
|
||||||
|
mount-usb "$CONFIG_USB_BOOT_DEV" \
|
||||||
|
|| die '$CONFIG_USB_BOOT_DEV: Unable to mount /media'
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check for ISO first
|
||||||
|
get_menu_option() {
|
||||||
|
echo "+++ Select your ISO boot option:"
|
||||||
|
n=0
|
||||||
|
while read option
|
||||||
|
do
|
||||||
|
n=`expr $n + 1`
|
||||||
|
echo "$n. $option"
|
||||||
|
done < /tmp/iso_menu.txt
|
||||||
|
|
||||||
|
read \
|
||||||
|
-p "Choose the ISO boot option [1-$n, s for standard boot, a to abort]: " \
|
||||||
|
option_index
|
||||||
|
|
||||||
|
if [ "$option_index" = "a" ]; then
|
||||||
|
die "Aborting boot attempt"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$option_index" = "s" ]; then
|
||||||
|
option=""
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
option=`head -n $option_index /tmp/iso_menu.txt | tail -1`
|
||||||
|
}
|
||||||
|
|
||||||
|
# create ISO menu options
|
||||||
|
ls -1r /media/*.iso 2>/dev/null > /tmp/iso_menu.txt || true
|
||||||
|
if [ `cat /tmp/iso_menu.txt | wc -l` -gt 0 ]; then
|
||||||
|
option_confirm=""
|
||||||
|
while [ -z "$option" -a "$option_index" != "s" ]
|
||||||
|
do
|
||||||
|
get_menu_option
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ -n "$option" ]; then
|
||||||
|
MOUNTED_ISO=$option
|
||||||
|
ISO=${option:7} # remove /media/ to get device relative path
|
||||||
|
kexec-iso-init $MOUNTED_ISO $ISO $CONFIG_USB_BOOT_DEV
|
||||||
|
|
||||||
|
die "Something failed in iso init"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "!!! Could not find any ISO, trying bootable USB"
|
||||||
|
# Attempt to pull verified config from device
|
||||||
|
kexec-select-boot -b /media/ -c "*.cfg" -u
|
||||||
|
|
||||||
|
die "Something failed in selecting boot"
|
@ -1,21 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
# Add additional files to the initrd cpio so that we can pass
|
|
||||||
# new keys to the Qubes startup routines.
|
|
||||||
# Usage:
|
|
||||||
# wrap-cpio /boot/initrd.blah /tmp/root/ > /tmp/new.cpio
|
|
||||||
|
|
||||||
die() { echo >&2 "$@"; exit 1; }
|
|
||||||
warn() { echo >&2 "$@"; }
|
|
||||||
|
|
||||||
cpio_file="$1"
|
|
||||||
if [ -z "$cpio_file" ]; then
|
|
||||||
die "Initial cpio must be specified"
|
|
||||||
fi
|
|
||||||
|
|
||||||
new_dir="$2"
|
|
||||||
if [ -z "$new_dir" ]; then
|
|
||||||
die "Additional directory must be specified"
|
|
||||||
fi
|
|
||||||
|
|
||||||
( cd "$new_dir" ; find . | cpio -H newc -ov )
|
|
||||||
cat "$cpio_file"
|
|
@ -28,3 +28,127 @@ recovery() {
|
|||||||
pcrs() {
|
pcrs() {
|
||||||
head -7 /sys/class/tpm/tpm0/pcrs
|
head -7 /sys/class/tpm/tpm0/pcrs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
confirm_totp()
|
||||||
|
{
|
||||||
|
last_half=X
|
||||||
|
|
||||||
|
while true; do
|
||||||
|
|
||||||
|
# update the TOTP code every thirty seconds
|
||||||
|
date=`date "+%Y-%m-%d %H:%M:%S"`
|
||||||
|
seconds=`date "+%s"`
|
||||||
|
half=`expr \( $seconds % 60 \) / 30`
|
||||||
|
if [ "$half" != "$last_half" ]; then
|
||||||
|
last_half=$half;
|
||||||
|
TOTP=`unseal-totp` \
|
||||||
|
|| recovery "TOTP code generation failed"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo -n "$date $TOTP: "
|
||||||
|
|
||||||
|
# read the first character, non-blocking
|
||||||
|
read \
|
||||||
|
-t 1 \
|
||||||
|
-n 1 \
|
||||||
|
-s \
|
||||||
|
-p "Confirm TOTP with a 'y': " \
|
||||||
|
totp_confirm \
|
||||||
|
&& break
|
||||||
|
|
||||||
|
# nothing typed, redraw the line
|
||||||
|
echo -ne '\r'
|
||||||
|
done
|
||||||
|
|
||||||
|
# clean up with a newline
|
||||||
|
echo
|
||||||
|
}
|
||||||
|
|
||||||
|
confirm_gpg_card()
|
||||||
|
{
|
||||||
|
# setup the USB so we can reach the GPG card
|
||||||
|
if ! lsmod | grep -q ehci_hcd; then
|
||||||
|
insmod /lib/modules/ehci-hcd.ko \
|
||||||
|
|| die "ehci_hcd: module load failed"
|
||||||
|
fi
|
||||||
|
if ! lsmod | grep -q ehci_pci; then
|
||||||
|
insmod /lib/modules/ehci-pci.ko \
|
||||||
|
|| die "ehci_pci: module load failed"
|
||||||
|
fi
|
||||||
|
if ! lsmod | grep -q xhci_hcd; then
|
||||||
|
insmod /lib/modules/xhci-hcd.ko \
|
||||||
|
|| die "ehci_hcd: module load failed"
|
||||||
|
fi
|
||||||
|
if ! lsmod | grep -q xhci_pci; then
|
||||||
|
insmod /lib/modules/xhci-pci.ko \
|
||||||
|
|| die "ehci_pci: module load failed"
|
||||||
|
sleep 2
|
||||||
|
fi
|
||||||
|
|
||||||
|
gpg --card-status \
|
||||||
|
|| die "gpg card read failed"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
check_tpm_counter()
|
||||||
|
{
|
||||||
|
# if the /boot.hashes file already exists, read the TPM counter ID
|
||||||
|
# from it.
|
||||||
|
if [ -r "$1" ]; then
|
||||||
|
TPM_COUNTER=`grep counter- "$1" | cut -d- -f2`
|
||||||
|
else
|
||||||
|
warn "$BOOT_HASHES does not exist; creating new TPM counter"
|
||||||
|
read -s -p "TPM Owner password: " tpm_password
|
||||||
|
echo
|
||||||
|
tpm counter_create \
|
||||||
|
-pwdo "$tpm_password" \
|
||||||
|
-pwdc '' \
|
||||||
|
-la 3135106223 \
|
||||||
|
| tee /tmp/counter \
|
||||||
|
|| die "Unable to create TPM counter"
|
||||||
|
TPM_COUNTER=`cut -d: -f1 < /tmp/counter`
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$TPM_COUNTER" ]; then
|
||||||
|
die "$1: TPM Counter not found?"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
read_tpm_counter()
|
||||||
|
{
|
||||||
|
tpm counter_read -ix "$1" | tee "/tmp/counter-$1" \
|
||||||
|
|| die "Counter read failed"
|
||||||
|
}
|
||||||
|
|
||||||
|
increment_tpm_counter()
|
||||||
|
{
|
||||||
|
tpm counter_increment -ix "$1" -pwdc '' \
|
||||||
|
| tee /tmp/counter-$1 \
|
||||||
|
|| die "Counter increment failed"
|
||||||
|
}
|
||||||
|
|
||||||
|
check_config() {
|
||||||
|
if [ ! -d /tmp/kexec ]; then
|
||||||
|
mkdir /tmp/kexec \
|
||||||
|
|| die 'Failed to make kexec tmp dir'
|
||||||
|
else
|
||||||
|
rm -rf /tmp/kexec/* \
|
||||||
|
|| die 'Failed to empty kexec tmp dir'
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -r $1/kexec.sig ]; then
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ `find $1/kexec*.txt | wc -l` -eq 0 ]; then
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! sha256sum `find $1/kexec*.txt` | gpgv $1/kexec.sig - ; then
|
||||||
|
die 'Invalid signature on kexec boot params'
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "+++ Found verified kexec boot params"
|
||||||
|
cp $1/kexec*.txt /tmp/kexec \
|
||||||
|
|| die "Failed to copy kexec boot params to tmp"
|
||||||
|
}
|
||||||
|
19
initrd/init
19
initrd/init
@ -29,6 +29,15 @@ hwclock -l -s
|
|||||||
. /etc/functions
|
. /etc/functions
|
||||||
. /etc/config
|
. /etc/config
|
||||||
|
|
||||||
|
# Add our boot devices into the /etc/fstab, if they are defined
|
||||||
|
# in the configuration file.
|
||||||
|
if [ ! -z "$CONFIG_BOOT_DEV" ]; then
|
||||||
|
echo >> /etc/fstab "$CONFIG_BOOT_DEV /boot auto defaults,ro 0 0"
|
||||||
|
fi
|
||||||
|
if [ ! -z "$CONFIG_USB_BOOT_DEV" ]; then
|
||||||
|
echo >> /etc/fstab "$CONFIG_USB_BOOT_DEV /media auto defaults,ro 0 0"
|
||||||
|
fi
|
||||||
|
|
||||||
if [ ! -x "$CONFIG_BOOTSCRIPT" ]; then
|
if [ ! -x "$CONFIG_BOOTSCRIPT" ]; then
|
||||||
recovery 'Boot script missing? Entering recovery shell'
|
recovery 'Boot script missing? Entering recovery shell'
|
||||||
# just in case...
|
# just in case...
|
||||||
@ -39,7 +48,7 @@ fi
|
|||||||
# Give the user a second to enter a recovery shell
|
# Give the user a second to enter a recovery shell
|
||||||
read \
|
read \
|
||||||
-t "1" \
|
-t "1" \
|
||||||
-p "Press 'r' for recovery shell: " \
|
-p "Press 'r' for recovery shell or 'u' for usb: " \
|
||||||
-n 1 \
|
-n 1 \
|
||||||
boot_option
|
boot_option
|
||||||
echo
|
echo
|
||||||
@ -52,6 +61,14 @@ if [ "$boot_option" = "r" ]; then
|
|||||||
exec /bin/ash
|
exec /bin/ash
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if [ "$boot_option" = "u" ]; then
|
||||||
|
echo '***** USB boot'
|
||||||
|
exec /bin/usb-init
|
||||||
|
# just in case...
|
||||||
|
tpm extend -ix 4 -ic recovery
|
||||||
|
exec /bin/ash
|
||||||
|
fi
|
||||||
|
|
||||||
echo '***** Normal boot'
|
echo '***** Normal boot'
|
||||||
exec "$CONFIG_BOOTSCRIPT"
|
exec "$CONFIG_BOOTSCRIPT"
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user