Skip to content

Commit

Permalink
Introduce io386 to heads and use it to finalize chipset at runtime
Browse files Browse the repository at this point in the history
On some newer platforms of intel (confirmed on nehalem, sandy/ivy
bridge), coreboot after commit [2ac149d294af795710eb4bb20f093e9920604abd](https://review.coreboot.org/cgit/coreboot.git/commit/?id=2ac149d294af795710eb4bb20f093e9920604abd)
registers an SMI to lockdown some registers on the chipset, as well
as access to the SPI flash, optionally. The SMI will always be triggered
by coreboot during S3 resume, but can be triggered by either coreboot
or the payload during normal boot path.

Enabling lockdown access to SPI flash will effectly write-protect it,
but there is no runtime option for coreboot to control it, so letting
coreboot to trigger such SMI will leave the owner of the machine lost
any possibility to program the SPI flash with its own OS, and becomes
a nightmare if the machine is uneasy to disassemble, so a scheme could
be implement, in which the SMI to lockdown chipset and SPI flash is left
for a payload to trigger, and temporarily disabling such triggering in
order to program the SPI flash needs authentication.

I have implemented a passcode-protected runtime-disableable lockdown
with grub, described [here](https://github.com/hardenedlinux/Debian-GNU-Linux-Profiles/blob/master/docs/hardened_boot/grub-for-coreboot.md#update-for-coreboot-after-commit-2ac149d294af795710eb4bb20f093e9920604abd). In order to implement a similar scheme for
Heads, I wrote [io386](https://github.com/hardenedlinux/io386).

With this commit, io386 will be called before entering boot routine
and recovery shell to trigger the SMI to finalize the chipset and
write protect the SPI flash at the same time. If the owner of the
machine want to program the SPI flash, they can enter the "flash mode"
in which the SMI is never triggered, thus SPI flash is writable.
To enter such mode, they should authencate themselves by connecting
their OpenPGP card to the machine, in order to prove they hold the very
same secret key used to sign the boot file list used by Heads.
  • Loading branch information
persmule committed Mar 1, 2018
1 parent 149635e commit 512dfdf
Show file tree
Hide file tree
Showing 5 changed files with 104 additions and 2 deletions.
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,7 @@ bin_modules-$(CONFIG_LVM2) += lvm2
bin_modules-$(CONFIG_DROPBEAR) += dropbear
bin_modules-$(CONFIG_FLASHTOOLS) += flashtools
bin_modules-$(CONFIG_NEWT) += newt
bin_modules-$(CONFIG_IO386) += io386

$(foreach m, $(bin_modules-y), \
$(call map,initrd_bin_add,$(call bins,$m)) \
Expand Down
46 changes: 46 additions & 0 deletions initrd/bin/flashmode
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#!/bin/sh
. /etc/config
. /etc/functions


echo >&2 "!!!!! Please authenticate with OpenPGP card to prove you own this box..."

confirm_gpg_card

# Perform a signing-based challenge-response,
# to authencate that the card plugged in holding
# the key to sign the list of boot files.
CR_NONCE="/tmp/secret/cr_nonce"
CR_SIG="/tmp/secret/cr_nonce.sig"

dd \
if=/dev/urandom \
of="$CR_NONCE" \
count=1 \
bs=20 \
2>/dev/null \
|| die "Unable to generate 20 random bytes"

for tries in 1 2 3; do
if gpg --digest-algo SHA256 \
--detach-sign \
-o "$CR_SIG" \
"$CR_NONCE" \
&& gpgv "$CR_SIG" "$CR_NONCE" \
; then
# Remove any temporary secret files that might be hanging around
# but recreate the directory so that new tools can use it.
rm -rf /tmp/secret
mkdir -p /tmp/secret
if [ "$CONFIG_TPM" = y ]; then
tpm extend -ix 4 -ic flashing
fi
echo >&2 "!!!!! Starting shell for ROM flashing"
sleep 1
exec /bin/ash
else
rm "$CR_SIG"
fi
done

die "Authentication failed! You are not allowed to program the flash."
17 changes: 17 additions & 0 deletions initrd/bin/generic-init
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ while true; do
echo "r) Recovery boot"
echo "u) USB boot"
echo "m) Boot menu"
echo "f) ROM flashing"

if ! confirm_totp "Boot mode"; then
recovery 'Failed to unseal TOTP'
Expand All @@ -40,24 +41,40 @@ while true; do
fi

if [ "$totp_confirm" = "u" ]; then
if [ "$CONFIG_IO386" = y ]; then
lock_chip
fi
exec /bin/usb-init
continue
fi

if [ "$totp_confirm" = "f" ]; then
flashmode \
|| recovery "Failed to enter flash mode"
fi

if [ "$totp_confirm" = "m" ]; then
# Try to select a kernel from the menu
if [ "$CONFIG_IO386" = y ]; then
lock_chip
fi
mount_boot
kexec-select-boot -m -b /boot -c "grub.cfg"
continue
fi

if [ "$totp_confirm" = "y" -o -n "$totp_confirm" ]; then
# Try to boot the default
if [ "$CONFIG_IO386" = y ]; then
lock_chip
fi
mount_boot
kexec-select-boot -b /boot -c "grub.cfg" \
|| recovery "Failed default boot"
fi



done

recovery "Something failed during boot"
14 changes: 12 additions & 2 deletions initrd/etc/functions
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,13 @@ warn() {
echo >&2 "$*";
}

lock_chip() {
APM_CNT=0xb2
FIN_CODE=0xcb
echo "Finalizing chipset"
io386 -o b -b x $APM_CNT $FIN_CODE
}

recovery() {
echo >&2 "!!!!! $*"

Expand All @@ -20,12 +27,16 @@ recovery() {
if [ "$CONFIG_TPM" = y ]; then
tpm extend -ix 4 -ic recovery
fi

if [ "$CONFIG_IO386" = y ]; then
lock_chip
fi

echo >&2 "!!!!! Starting recovery shell"
sleep 1
exec /bin/ash
}


pcrs() {
head -7 /sys/class/tpm/tpm0/pcrs
}
Expand Down Expand Up @@ -126,7 +137,6 @@ confirm_gpg_card()
|| die "gpg card read failed"
}


check_tpm_counter()
{
# if the /boot.hashes file already exists, read the TPM counter ID
Expand Down
28 changes: 28 additions & 0 deletions modules/io386
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
modules-$(CONFIG_IO386) += io386

io386_depends := $(musl_dep)

io386_version := git
io386_repo := https://github.com/hardenedlinux/io386
io386_dir := io386-$(io386_version)

io386_target := \
$(MAKE_JOBS) \
$(CROSS_TOOLS) \
SHARED=yes \
PREFIX="/" \
&& \
$(MAKE) \
-C $(build)/$(io386_dir) \
$(CROSS_TOOLS) \
SHARED=yes \
PREFIX="/" \
DESTDIR="$(INSTALL)" \
install \

io386_output := \
io386

io386_libraries :=

io386_configure :=

0 comments on commit 512dfdf

Please sign in to comment.