mirror of
https://github.com/linuxboot/heads.git
synced 2024-12-18 20:47:55 +00:00
Add PureBoot Basic Mode
PureBoot Basic mode provides the full Linux userspace in firmware from Heads without requiring verified boot or a Librem Key. Basic and verified boot can be switched freely without changing firmware, such as if a Librem Key is lost. PureBoot Basic can apply firmware updates from a USB flash drive, and having a complete Linux userspace enables more sophisticated recovery options. Basic mode boots to the first boot option by default, setting a default is not required. This can be configured in the config GUI. Signed-off-by: Jonathon Hall <jonathon.hall@puri.sm>
This commit is contained in:
parent
a5238b5823
commit
4bc6159ab6
11
initrd/bin/basic-autoboot.sh
Executable file
11
initrd/bin/basic-autoboot.sh
Executable file
@ -0,0 +1,11 @@
|
||||
#!/bin/bash
|
||||
set -o pipefail
|
||||
|
||||
. /etc/functions
|
||||
|
||||
BOOT_MENU_OPTIONS=/tmp/basic-autoboot-options
|
||||
|
||||
scan_boot_options /boot "grub.cfg" "$BOOT_MENU_OPTIONS"
|
||||
if [ -s "$BOOT_MENU_OPTIONS" ]; then
|
||||
kexec-boot -b /boot -e "$(head -1 "$BOOT_MENU_OPTIONS")"
|
||||
fi
|
@ -27,14 +27,32 @@ while true; do
|
||||
menu_choice=${param::1}
|
||||
unset param
|
||||
else
|
||||
# check current PureBoot Mode
|
||||
BASIC_MODE="$(load_config_value CONFIG_PUREBOOT_BASIC)"
|
||||
BASIC_NO_AUTOMATIC_DEFAULT="$(load_config_value CONFIG_BASIC_NO_AUTOMATIC_DEFAULT)"
|
||||
|
||||
dynamic_config_options=()
|
||||
|
||||
if [ "$BASIC_MODE" = "y" ]; then
|
||||
dynamic_config_options+=( \
|
||||
'P' " $(get_config_display_action "$BASIC_MODE") PureBoot Basic Mode" \
|
||||
'A' " $(get_inverted_config_display_action "$BASIC_NO_AUTOMATIC_DEFAULT") automatic default boot" \
|
||||
)
|
||||
else
|
||||
dynamic_config_options+=( \
|
||||
'r' ' Clear GPG key(s) and reset all user settings' \
|
||||
'R' ' Change the root device for hashing' \
|
||||
'D' ' Change the root directories to hash' \
|
||||
'B' ' Check root hashes at boot' \
|
||||
'P' " $(get_config_display_action "$BASIC_MODE") PureBoot Basic Mode" \
|
||||
)
|
||||
fi
|
||||
|
||||
unset menu_choice
|
||||
whiptail $BG_COLOR_MAIN_MENU --title "Config Management Menu" \
|
||||
--menu "This menu lets you change settings for the current BIOS session.\n\nAll changes will revert after a reboot,\n\nunless you also save them to the running BIOS." 0 80 10 \
|
||||
'b' ' Change the /boot device' \
|
||||
'r' ' Clear GPG key(s) and reset all user settings' \
|
||||
'R' ' Change the root device for hashing' \
|
||||
'D' ' Change the root directories to hash' \
|
||||
'B' ' Check root hashes at boot' \
|
||||
"${dynamic_config_options[@]}" \
|
||||
's' ' Save the current configuration to the running BIOS' \
|
||||
'x' ' Return to Main Menu' \
|
||||
2>/tmp/whiptail || recovery "GUI menu failed"
|
||||
@ -228,6 +246,61 @@ while true; do
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
"P" )
|
||||
if [ "$BASIC_MODE" = "n" ]; then
|
||||
if (whiptail --title 'Enable PureBoot Basic Mode?' \
|
||||
--yesno "This will remove all signature checking on the firmware
|
||||
\nand boot files, and disable use of the Librem Key.
|
||||
\n\nDo you want to proceed?" 0 80) then
|
||||
|
||||
set_config /etc/config.user "CONFIG_PUREBOOT_BASIC" "y"
|
||||
combine_configs
|
||||
|
||||
whiptail --title 'Config change successful' \
|
||||
--msgbox "PureBoot Basic mode enabled;\nsave the config change and reboot for it to go into effect." 0 80
|
||||
|
||||
fi
|
||||
else
|
||||
if (whiptail --title 'Disable PureBoot Basic Mode?' \
|
||||
--yesno "This will enable all signature checking on the firmware
|
||||
\nand boot files, and enable use of the Librem Key.
|
||||
\n\nDo you want to proceed?" 0 80) then
|
||||
|
||||
set_config /etc/config.user "CONFIG_PUREBOOT_BASIC" "n"
|
||||
combine_configs
|
||||
|
||||
whiptail --title 'Config change successful' \
|
||||
--msgbox "PureBoot Basic mode has been disabled;\nsave the config change and reboot for it to go into effect." 0 80
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
"A" )
|
||||
if [ "$BASIC_NO_AUTOMATIC_DEFAULT" = "n" ]; then
|
||||
if (whiptail --title 'Disable automatic default boot?' \
|
||||
--yesno "You will need to select a default boot option.
|
||||
\nIf the boot options are changed, such as for an OS update,
|
||||
\nyou will be prompted to select a new default.
|
||||
\n\nDo you want to proceed?" 0 80) then
|
||||
|
||||
set_config /etc/config.user "CONFIG_BASIC_NO_AUTOMATIC_DEFAULT" "y"
|
||||
combine_configs
|
||||
|
||||
whiptail --title 'Config change successful' \
|
||||
--msgbox "Automatic default boot disabled;\nsave the config change and reboot for it to go into effect." 0 80
|
||||
fi
|
||||
else
|
||||
if (whiptail --title 'Enable automatic default boot?' \
|
||||
--yesno "The first boot option will be used automatically.
|
||||
\n\nDo you want to proceed?" 0 80) then
|
||||
|
||||
set_config /etc/config.user "CONFIG_BASIC_NO_AUTOMATIC_DEFAULT" "n"
|
||||
combine_configs
|
||||
|
||||
whiptail --title 'Config change successful' \
|
||||
--msgbox "Automatic default boot enabled;\nsave the config change and reboot for it to go into effect." 0 80
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
done
|
||||
|
213
initrd/bin/gui-init-basic
Executable file
213
initrd/bin/gui-init-basic
Executable file
@ -0,0 +1,213 @@
|
||||
#!/bin/bash
|
||||
# Boot from a local disk installation
|
||||
|
||||
BOARD_NAME=${CONFIG_BOARD_NAME:-${CONFIG_BOARD}}
|
||||
MAIN_MENU_TITLE="${BOARD_NAME} | PureBoot Basic Boot Menu"
|
||||
export BG_COLOR_MAIN_MENU=""
|
||||
|
||||
. /etc/functions
|
||||
. /etc/gui_functions
|
||||
. /tmp/config
|
||||
|
||||
# skip_to_menu is set if the user selects "continue to the main menu" from any
|
||||
# error, so we will indeed go to the main menu even if other errors occur. It's
|
||||
# reset when we reach the main menu so the user can retry from the main menu and
|
||||
# # see errors again.
|
||||
skip_to_menu="false"
|
||||
|
||||
mount_boot()
|
||||
{
|
||||
TRACE "Under /bin/gui-init:mount_boot"
|
||||
# Mount local disk if it is not already mounted
|
||||
while ! grep -q /boot /proc/mounts ; do
|
||||
# try to mount if CONFIG_BOOT_DEV exists
|
||||
if [ -e "$CONFIG_BOOT_DEV" ]; then
|
||||
mount -o ro $CONFIG_BOOT_DEV /boot
|
||||
[[ $? -eq 0 ]] && continue
|
||||
fi
|
||||
|
||||
# CONFIG_BOOT_DEV doesn't exist or couldn't be mounted, so give user options
|
||||
BG_COLOR_MAIN_MENU=$BG_COLOR_ERROR
|
||||
whiptail $BG_COLOR_ERROR --title "ERROR: No Bootable OS Found!" \
|
||||
--menu " No bootable OS was found on the default boot device $CONFIG_BOOT_DEV.
|
||||
How would you like to proceed?" 0 80 4 \
|
||||
'b' ' Select a new boot device' \
|
||||
'u' ' Boot from USB' \
|
||||
'm' ' Continue to the main menu' \
|
||||
'x' ' Exit to recovery shell' \
|
||||
2>/tmp/whiptail || recovery "GUI menu failed"
|
||||
|
||||
option=$(cat /tmp/whiptail)
|
||||
case "$option" in
|
||||
b )
|
||||
config-gui.sh boot_device_select
|
||||
if [ $? -eq 0 ]; then
|
||||
# update CONFIG_BOOT_DEV
|
||||
. /tmp/config
|
||||
BG_COLOR_MAIN_MENU=""
|
||||
fi
|
||||
;;
|
||||
u )
|
||||
exec /bin/usb-init
|
||||
;;
|
||||
m )
|
||||
skip_to_menu="true"
|
||||
break
|
||||
;;
|
||||
* )
|
||||
recovery "User requested recovery shell"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
prompt_auto_default_boot()
|
||||
{
|
||||
TRACE "Under /bin/gui-init:prompt_auto_default_boot"
|
||||
|
||||
# save IFS before changing, restore after read
|
||||
IFS_DEF=$IFS
|
||||
IFS=''
|
||||
first_pass=false
|
||||
|
||||
echo -e "\n\n"
|
||||
read -t $CONFIG_AUTO_BOOT_TIMEOUT -s -n 1 -p "Automatic boot in $CONFIG_AUTO_BOOT_TIMEOUT seconds unless interrupted by keypress... "
|
||||
if [[ $? -ne 0 ]]; then
|
||||
IFS=$IFS_DEF
|
||||
echo -e "\n\nAttempting default boot...\n\n"
|
||||
attempt_default_boot
|
||||
fi
|
||||
IFS=$IFS_DEF
|
||||
}
|
||||
|
||||
show_main_menu()
|
||||
{
|
||||
TRACE "Under /bin/gui-init:show_main_menu"
|
||||
date=`date "+%Y-%m-%d %H:%M:%S %Z"`
|
||||
whiptail $BG_COLOR_MAIN_MENU --title "$MAIN_MENU_TITLE" \
|
||||
--menu "$date" 0 80 10 \
|
||||
'd' ' Default boot' \
|
||||
'o' ' Options -->' \
|
||||
's' ' System Info' \
|
||||
'p' ' Power Off' \
|
||||
2>/tmp/whiptail || recovery "GUI menu failed"
|
||||
|
||||
option=$(cat /tmp/whiptail)
|
||||
case "$option" in
|
||||
d )
|
||||
attempt_default_boot
|
||||
;;
|
||||
o )
|
||||
show_options_menu
|
||||
;;
|
||||
s )
|
||||
show_system_info
|
||||
;;
|
||||
p )
|
||||
poweroff
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
show_options_menu()
|
||||
{
|
||||
TRACE "Under /bin/gui-init:show_options_menu"
|
||||
whiptail $BG_COLOR_MAIN_MENU --title "PureBoot Basic Options" \
|
||||
--menu "" 0 80 10 \
|
||||
'b' ' Boot Options -->' \
|
||||
'c' ' Change configuration settings -->' \
|
||||
'f' ' Flash/Update the BIOS -->' \
|
||||
'x' ' Exit to recovery shell' \
|
||||
'r' ' <-- Return to main menu' \
|
||||
2>/tmp/whiptail || recovery "GUI menu failed"
|
||||
|
||||
option=$(cat /tmp/whiptail)
|
||||
case "$option" in
|
||||
b )
|
||||
show_boot_options_menu
|
||||
;;
|
||||
c )
|
||||
config-gui.sh
|
||||
;;
|
||||
f )
|
||||
flash-gui.sh
|
||||
;;
|
||||
x )
|
||||
recovery "User requested recovery shell"
|
||||
;;
|
||||
r )
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
show_boot_options_menu()
|
||||
{
|
||||
TRACE "Under /bin/gui-init:show_boot_options_menu"
|
||||
whiptail $BG_COLOR_MAIN_MENU --title "Boot Options" \
|
||||
--menu "Select A Boot Option" 0 80 10 \
|
||||
'm' ' Show OS boot menu' \
|
||||
'u' ' USB boot' \
|
||||
'r' ' <-- Return to main menu' \
|
||||
2>/tmp/whiptail || recovery "GUI menu failed"
|
||||
|
||||
option=$(cat /tmp/whiptail)
|
||||
case "$option" in
|
||||
m )
|
||||
# select a kernel from the menu
|
||||
select_os_boot_option
|
||||
;;
|
||||
u )
|
||||
exec /bin/usb-init
|
||||
;;
|
||||
r )
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
select_os_boot_option()
|
||||
{
|
||||
TRACE "Under /bin/gui-init:select_os_boot_option"
|
||||
mount_boot
|
||||
kexec-select-boot -m -b /boot -c "grub.cfg" -g -i
|
||||
}
|
||||
|
||||
attempt_default_boot()
|
||||
{
|
||||
TRACE "Under /bin/gui-init:attempt_default_boot"
|
||||
mount_boot
|
||||
|
||||
DEFAULT_FILE=`find /boot/kexec_default.*.txt 2>/dev/null | head -1`
|
||||
# Basic by default boots automatically to the first menu option. This allows
|
||||
# kernel updates to work in Basic by default without prompting to select a
|
||||
# new default boot option.
|
||||
if [ "$CONFIG_BASIC_NO_AUTOMATIC_DEFAULT" != "y" ]; then
|
||||
basic-autoboot.sh
|
||||
elif [ -r "$DEFAULT_FILE" ]; then
|
||||
kexec-select-boot -b /boot -c "grub.cfg" -g -i -s \
|
||||
|| recovery "Failed default boot"
|
||||
elif (whiptail $BG_COLOR_WARNING --title 'No Default Boot Option Configured' \
|
||||
--yesno "There is no default boot option configured yet.\nWould you like to load a menu of boot options?\nOtherwise you will return to the main menu." 0 80) then
|
||||
kexec-select-boot -m -b /boot -c "grub.cfg" -g -i
|
||||
fi
|
||||
}
|
||||
|
||||
# gui-init-basic start
|
||||
TRACE "Under /bin/gui-init, start"
|
||||
|
||||
if ! detect_boot_device ; then
|
||||
# can't determine /boot device or no OS installed,
|
||||
# so fall back to interactive selection
|
||||
mount_boot
|
||||
fi
|
||||
|
||||
if [ "$skip_to_menu" != "true" -a -n "$CONFIG_AUTO_BOOT_TIMEOUT" ]; then
|
||||
prompt_auto_default_boot
|
||||
fi
|
||||
|
||||
while true; do
|
||||
TRACE "Under gui-init:while true loop"
|
||||
skip_to_menu="false"
|
||||
show_main_menu
|
||||
done
|
||||
|
||||
recovery "Something failed during boot"
|
@ -194,8 +194,9 @@ if [ "$CONFIG_TPM" = "y" ];then
|
||||
extparam=-r
|
||||
fi
|
||||
fi
|
||||
kexec-sign-config -p $paramsdir $extparam \
|
||||
|| die "Failed to sign default config"
|
||||
|
||||
if [ "$CONFIG_PUREBOOT_BASIC" != "y" ]; then
|
||||
kexec-sign-config -p $paramsdir $extparam \
|
||||
|| die "Failed to sign default config"
|
||||
fi
|
||||
# switch back to ro mode
|
||||
mount -o ro,remount $paramsdev
|
||||
|
@ -257,19 +257,20 @@ default_select() {
|
||||
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" > /tmp/hash_output ); then
|
||||
echo "+++ Verified default boot hashes "
|
||||
valid_hash='y'
|
||||
else
|
||||
if [ "$gui_menu" = "y" ]; then
|
||||
CHANGED_FILES=$(grep -v 'OK$' /tmp/hash_output | cut -f1 -d ':')
|
||||
whiptail $BG_COLOR_ERROR --title 'ERROR: Default Boot Hash Mismatch' \
|
||||
--msgbox "The following files failed the verification process:\n${CHANGED_FILES}\nExiting to a recovery shell" 0 80
|
||||
if [ "$CONFIG_PUREBOOT_BASIC" != "y" ]; then
|
||||
# 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" > /tmp/hash_output ); then
|
||||
echo "+++ Verified default boot hashes "
|
||||
valid_hash='y'
|
||||
else
|
||||
if [ "$gui_menu" = "y" ]; then
|
||||
CHANGED_FILES=$(grep -v 'OK$' /tmp/hash_output | cut -f1 -d ':')
|
||||
whiptail $BG_COLOR_ERROR --title 'ERROR: Default Boot Hash Mismatch' \
|
||||
--msgbox "The following files failed the verification process:\n${CHANGED_FILES}\nExiting to a recovery shell" 0 80
|
||||
fi
|
||||
fi
|
||||
die "!!! $TMP_DEFAULT_HASH_FILE: default boot hash mismatch"
|
||||
fi
|
||||
|
||||
echo "+++ Executing default boot for $name:"
|
||||
@ -320,6 +321,11 @@ user_select() {
|
||||
|
||||
do_boot()
|
||||
{
|
||||
if [ "$CONFIG_PUREBOOT_BASIC" != "y" ]; then
|
||||
kexec-boot -b "$bootdir" -e "$option" -a "$add" -r "$remove" \
|
||||
|| die "!!! Failed to boot w/ options: $option"
|
||||
fi
|
||||
|
||||
if [ "$CONFIG_BOOT_REQ_ROLLBACK" = "y" -a "$valid_rollback" = "n" ]; then
|
||||
die "!!! Missing required rollback counter state"
|
||||
fi
|
||||
@ -348,7 +354,7 @@ do_boot()
|
||||
}
|
||||
|
||||
while true; do
|
||||
if [ "$force_boot" = "y" ]; then
|
||||
if [ "$force_boot" = "y" -o "$CONFIG_PUREBOOT_BASIC" = "y" ]; then
|
||||
check_config $paramsdir force
|
||||
else
|
||||
check_config $paramsdir
|
||||
@ -366,9 +372,11 @@ while true; do
|
||||
# even if hashes don't match
|
||||
if [ "$force_boot" = "y" ]; then
|
||||
scan_options
|
||||
# Remove boot splash and make background red in the event of a forced boot
|
||||
add="$add vt.default_red=0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff"
|
||||
remove="$remove splash quiet"
|
||||
if [ "$CONFIG_PUREBOOT_BASIC" != "y" ]; then
|
||||
# Remove boot splash and make background red in the event of a forced boot
|
||||
add="$add vt.default_red=0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff"
|
||||
remove="$remove splash quiet"
|
||||
fi
|
||||
user_select
|
||||
fi
|
||||
|
||||
@ -385,7 +393,7 @@ while true; do
|
||||
scan_options
|
||||
fi
|
||||
|
||||
if [ "$CONFIG_TPM" = "y" ]; then
|
||||
if [ "$CONFIG_TPM" = "y" -a "$CONFIG_PUREBOOT_BASIC" != "y" ]; then
|
||||
# Optionally enforce device file hashes
|
||||
if [ -r "$TMP_HASH_FILE" ]; then
|
||||
valid_global_hash="n"
|
||||
|
@ -266,7 +266,7 @@ check_config() {
|
||||
|| die 'Failed to empty kexec tmp dir'
|
||||
fi
|
||||
|
||||
if [ ! -r $1/kexec.sig ]; then
|
||||
if [ ! -r $1/kexec.sig -a "$CONFIG_PUREBOOT_BASIC" != "y" ]; then
|
||||
return
|
||||
fi
|
||||
|
||||
|
@ -119,3 +119,16 @@ get_config_display_action()
|
||||
{
|
||||
[ "$1" = "y" ] && echo "Disable" || echo "Enable"
|
||||
}
|
||||
|
||||
# Invert a config value
|
||||
invert_config()
|
||||
{
|
||||
[ "$1" = "y" ] && echo "n" || echo "y"
|
||||
}
|
||||
|
||||
# Get "Enable" or "Disable" for a config that internally is inverted (because it
|
||||
# disables a behavior that is on by default).
|
||||
get_inverted_config_display_action()
|
||||
{
|
||||
get_config_display_action "$(invert_config "$1")"
|
||||
}
|
||||
|
@ -131,6 +131,10 @@ echo "export CONFIG_TPM2_TOOLS=\"$CONFIG_TPM2_TOOLS\"" >> /etc/config.user
|
||||
combine_configs
|
||||
. /tmp/config
|
||||
|
||||
if [ "$CONFIG_PUREBOOT_BASIC" = "y" ]; then
|
||||
echo -e "***** BASIC mode: tamper detection disabled\n" > /dev/tty0
|
||||
fi
|
||||
|
||||
# export firmware version
|
||||
export FW_VER=$(dmesg | grep 'DMI' | grep -o 'BIOS.*' | cut -f2- -d ' ')
|
||||
# chop off date, since will always be epoch w/timeless builds
|
||||
@ -142,6 +146,11 @@ if [ ! -z "$CONFIG_BOOT_DEV" ]; then
|
||||
echo >> /etc/fstab "$CONFIG_BOOT_DEV /boot auto defaults,ro 0 0"
|
||||
fi
|
||||
|
||||
if [ "$CONFIG_PUREBOOT_BASIC" = "y" ]; then
|
||||
CONFIG_BOOTSCRIPT=/bin/gui-init-basic
|
||||
export CONFIG_HOTPKEY=n
|
||||
fi
|
||||
|
||||
if [ ! -x "$CONFIG_BOOTSCRIPT" -a ! -x "$CONFIG_BOOTSCRIPT_NETWORK" ]; then
|
||||
recovery 'Boot script missing? Entering recovery shell'
|
||||
else
|
||||
|
Loading…
Reference in New Issue
Block a user