mirror of
https://github.com/linuxboot/heads.git
synced 2025-01-31 16:35:25 +00:00
adds a USB boot option with basic parsing to kexec
Supports booting from USB media using either the root device or a signed ISO as the boot device. Boot options are parsed with quick/dirty shell scripts to infer kexec params. Closes #195 and begins to address #196
This commit is contained in:
parent
7f600072ad
commit
efd662c63a
@ -19,6 +19,8 @@ CONFIG_LINUX_USB=y
|
||||
|
||||
CONFIG_BOOTSCRIPT=/bin/qubes-init
|
||||
|
||||
CONFIG_USB_BOOT_DEV="/dev/sdb1"
|
||||
|
||||
# Disks encrypted by the TPM LUKS key
|
||||
CONFIG_QUBES_BOOT_DEV="/dev/sda1"
|
||||
CONFIG_QUBES_VG="qubes_dom0"
|
||||
|
@ -20,6 +20,8 @@ CONFIG_LINUX_E1000E=y
|
||||
|
||||
CONFIG_BOOTSCRIPT=/bin/qubes-init
|
||||
|
||||
CONFIG_USB_BOOT_DEV="/dev/sdb1"
|
||||
|
||||
# Disks encrypted by the TPM LUKS key
|
||||
CONFIG_QUBES_BOOT_DEV="/dev/sda1"
|
||||
CONFIG_QUBES_VG="qubes_dom0"
|
||||
|
73
initrd/bin/usb-boot
Executable file
73
initrd/bin/usb-boot
Executable file
@ -0,0 +1,73 @@
|
||||
#!/bin/sh
|
||||
. /etc/functions
|
||||
|
||||
while getopts "b:e:r:a:" arg; do
|
||||
case $arg in
|
||||
b) bootdir="$OPTARG" ;;
|
||||
e) entry="$OPTARG" ;;
|
||||
r) cmdremove="$OPTARG" ;;
|
||||
a) cmdadd="$OPTARG" ;;
|
||||
esac
|
||||
done
|
||||
|
||||
kexectype=`echo $entry | cut -d\| -f2`
|
||||
kexecparams=`echo $entry | cut -d\| -f3- | tr '|' '\n'`
|
||||
kexeccmd="kexec"
|
||||
|
||||
fix_file_path() {
|
||||
filepath=`find $bootdir -path "*$firstval" | tail -1`
|
||||
if ! [ -r $filepath ]; then
|
||||
die "failed to find file $firstval"
|
||||
fi
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
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
|
||||
fix_file_path
|
||||
kexeccmd="$kexeccmd -l $filepath"
|
||||
if [ "$kexectype" = "multiboot" ]; then
|
||||
cmdline="$restval"
|
||||
adjust_cmd_line
|
||||
kexeccmd="$kexeccmd --command-line \"$cmdline\""
|
||||
fi
|
||||
fi
|
||||
if [ "$key" = "module" ]; then
|
||||
fix_file_path
|
||||
kexeccmd="$kexeccmd --module \"$filepath $restval\""
|
||||
fi
|
||||
if [ "$key" = "initrd" ]; then
|
||||
fix_file_path
|
||||
kexeccmd="$kexeccmd --initrd=$filepath"
|
||||
fi
|
||||
if [ "$key" = "append" ]; then
|
||||
cmdline="$firstval $restval"
|
||||
adjust_cmd_line
|
||||
kexeccmd="$kexeccmd --append=\"$cmdline\""
|
||||
fi
|
||||
done << EOF
|
||||
$kexecparams
|
||||
EOF
|
||||
|
||||
echo "Loading the new kernel:"
|
||||
echo "$kexeccmd"
|
||||
eval "$kexeccmd" \
|
||||
|| die "Failed to load the new kernel"
|
||||
|
||||
echo "Starting the new kernel"
|
||||
exec kexec -e
|
65
initrd/bin/usb-init
Executable file
65
initrd/bin/usb-init
Executable file
@ -0,0 +1,65 @@
|
||||
#!/bin/sh
|
||||
# Boot a Tails 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
|
||||
|
||||
# TODO: Do a scan of USB devices to detect the Tails USB
|
||||
mount-usb "$CONFIG_USB_BOOT_DEV"
|
||||
|
||||
# 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
|
||||
recovery "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
|
||||
if [ `wc -l /tmp/iso_menu.txt | cut -d\ -f1` -gt 0 ]; then
|
||||
option_confirm=""
|
||||
while [ -z "$option" -a "$option_index" != "s" ]
|
||||
do
|
||||
get_menu_option
|
||||
done
|
||||
|
||||
if [ -n "$option" ]; then
|
||||
exec usb-iso-init $option
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "!!! Could not find any ISO, trying bootable USB"
|
||||
exec usb-select-boot /media
|
||||
|
||||
recovery "Something failed..."
|
27
initrd/bin/usb-iso-init
Executable file
27
initrd/bin/usb-iso-init
Executable file
@ -0,0 +1,27 @@
|
||||
#!/bin/sh
|
||||
# Boot from signed ISO
|
||||
|
||||
. /etc/functions
|
||||
. /etc/config
|
||||
|
||||
ISO="$1"
|
||||
|
||||
echo '+++ Verifying ISO'
|
||||
# Verify the signature on the hashes
|
||||
ISOSIG="$ISO.sig"
|
||||
if ! [ -r "$ISOSIG" ]; then
|
||||
ISOSIG="$ISO.asc"
|
||||
fi
|
||||
|
||||
gpgv "$ISOSIG" "$ISO" \
|
||||
|| recovery 'ISO signature failed'
|
||||
|
||||
echo '+++ Mounting ISO and booting'
|
||||
mount -t iso9660 -o loop $ISO /boot
|
||||
|
||||
ISO_FILE=${ISO:7}
|
||||
DEV=$CONFIG_USB_BOOT_DEV
|
||||
DEV_UUID=`blkid $DEV | tail -1 | tr " " "\n" | grep UUID | cut -d\" -f2`
|
||||
ADD="fromiso=/dev/disk/by-uuid/$DEV_UUID/$ISO_FILE"
|
||||
|
||||
/bin/usb-select-boot /boot "$ADD"
|
171
initrd/bin/usb-parse-boot
Executable file
171
initrd/bin/usb-parse-boot
Executable file
@ -0,0 +1,171 @@
|
||||
#!/bin/sh
|
||||
file=$1
|
||||
basefile=$(basename $file)
|
||||
|
||||
reset_entry() {
|
||||
name=""
|
||||
kexectype="elf"
|
||||
kernel=""
|
||||
initrd=""
|
||||
modules=""
|
||||
append=""
|
||||
}
|
||||
|
||||
echo_entry() {
|
||||
if [ "$kexectype" = "elf" ]; then
|
||||
if [ -z "$kernel" -o -z "$initrd" ]; then return; fi
|
||||
|
||||
entry="$name|$kexectype|kernel $kernel|initrd $initrd"
|
||||
if [ -n "$append" ]; then entry="$entry|append $append"; fi
|
||||
echo "$entry"
|
||||
fi
|
||||
if [ "$kexectype" = "multiboot" ]; then
|
||||
if [ -z "$kernel" ]; then return; fi
|
||||
|
||||
echo "$name|$kexectype|kernel $kernel$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
|
||||
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*)
|
||||
kexectype="multiboot"
|
||||
kernel="$val"
|
||||
;;
|
||||
module*)
|
||||
modules="$modules|module $val"
|
||||
;;
|
||||
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
|
||||
modules="$modules|module $line"
|
||||
fi
|
||||
done << EOF
|
||||
$splitval
|
||||
EOF
|
||||
}
|
||||
|
||||
syslinux_entry() {
|
||||
label_line=${line:0:5}
|
||||
if [ -z "$line" ]; then
|
||||
syslinux_end
|
||||
fi
|
||||
if [ "$label_line" = "label" -o "$label_line" = "LABEL" ]; then
|
||||
search_entry
|
||||
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 $trimcmd in
|
||||
menu* | MENU* )
|
||||
cmd2=`echo $trimcmd | cut -d \ -f2`
|
||||
if [ "$cmd2" = "label" -o "$cmd2" = "LABEL" ]; then
|
||||
name=`echo ${trimcmd:11} | tr -d '^'`
|
||||
fi
|
||||
;;
|
||||
linux* | LINUX* | kernel* | KERNEL* )
|
||||
case $val in
|
||||
*mboot.c32) kexectype="multiboot" ;;
|
||||
*.c32)
|
||||
# skip this entry
|
||||
state="search"
|
||||
;;
|
||||
*)
|
||||
kernel="$val"
|
||||
esac
|
||||
;;
|
||||
initrd* | INITRD* )
|
||||
initrd="$val"
|
||||
;;
|
||||
append* | APPEND* )
|
||||
if [ "$kexectype" = "multiboot" ]; 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
|
59
initrd/bin/usb-select-boot
Executable file
59
initrd/bin/usb-select-boot
Executable file
@ -0,0 +1,59 @@
|
||||
#!/bin/sh
|
||||
. /etc/functions
|
||||
|
||||
bootdir=$1
|
||||
add=$2
|
||||
|
||||
get_menu_option() {
|
||||
echo "+++ Select your boot option:"
|
||||
n=0
|
||||
while read option
|
||||
do
|
||||
parse_option
|
||||
n=`expr $n + 1`
|
||||
echo "$n. $name [$kernel]"
|
||||
done < /tmp/usb_menu.txt
|
||||
|
||||
read \
|
||||
-p "Choose the boot option [1-$n, a to abort]: " \
|
||||
option_index
|
||||
|
||||
if [ "$option_index" = "a" ]; then
|
||||
recovery "Aborting boot attempt"
|
||||
fi
|
||||
|
||||
option=`head -n $option_index /tmp/usb_menu.txt | 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': " \
|
||||
option_confirm
|
||||
echo
|
||||
}
|
||||
|
||||
parse_option() {
|
||||
name=`echo $option | cut -d\| -f1`
|
||||
kernel=`echo $option | cut -d\| -f3`
|
||||
}
|
||||
|
||||
echo "+++ Scanning USB media boot options"
|
||||
for i in `find $bootdir -name "*.cfg"`; do usb-parse-boot $i >> /tmp/usb_options.txt; done
|
||||
if [ ! -r /tmp/usb_options.txt ]; then
|
||||
recovery "Failed to parse any boot options"
|
||||
fi
|
||||
sort /tmp/usb_options.txt | uniq > /tmp/usb_menu.txt
|
||||
|
||||
option_confirm=""
|
||||
while [ "$option_confirm" != "y" ]
|
||||
do
|
||||
get_menu_option
|
||||
confirm_menu_option
|
||||
done
|
||||
|
||||
usb-boot -b $bootdir -e "$option" -a "intel_iommu=on $add" -r "quiet"
|
@ -28,3 +28,38 @@ recovery() {
|
||||
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
|
||||
}
|
||||
|
10
initrd/init
10
initrd/init
@ -39,7 +39,7 @@ fi
|
||||
# Give the user a second to enter a recovery shell
|
||||
read \
|
||||
-t "1" \
|
||||
-p "Press 'r' for recovery shell: " \
|
||||
-p "Press 'r' for recovery shell or 'u' for usb: " \
|
||||
-n 1 \
|
||||
boot_option
|
||||
echo
|
||||
@ -52,6 +52,14 @@ if [ "$boot_option" = "r" ]; then
|
||||
exec /bin/ash
|
||||
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'
|
||||
exec "$CONFIG_BOOTSCRIPT"
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user