diff --git a/.circleci/config.yml b/.circleci/config.yml index cd6487f7..ae77cce8 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -15,7 +15,7 @@ commands: command: | ln -fs /usr/share/zoneinfo/America/New_York /etc/localtime apt update - apt install -y build-essential zlib1g-dev uuid-dev libdigest-sha-perl libelf-dev bc bzip2 bison flex git gnupg gawk iasl m4 nasm patch python python2 python3 wget gnat cpio ccache pkg-config cmake libusb-1.0-0-dev autoconf texinfo ncurses-dev doxygen graphviz udev libudev1 libudev-dev automake libtool rsync innoextract sudo libssl-dev device-tree-compiler u-boot-tools sharutils e2fsprogs parted curl unzip imagemagick libncurses5-dev + apt install -y build-essential zlib1g-dev uuid-dev libdigest-sha-perl libelf-dev bc bzip2 bison flex git gnupg gawk iasl m4 nasm patch python python2 python3 wget gnat cpio ccache pkg-config cmake libusb-1.0-0-dev autoconf texinfo ncurses-dev doxygen graphviz udev libudev1 libudev-dev automake libtool rsync innoextract sudo libssl-dev device-tree-compiler u-boot-tools sharutils e2fsprogs parted curl unzip imagemagick libncurses5-dev zip - run: name: Make Board (FULL ORDERED BUILD LOGS HERE UNTIL JOB FAILED) command: | diff --git a/Makefile b/Makefile index 539554e1..258911f3 100644 --- a/Makefile +++ b/Makefile @@ -16,6 +16,7 @@ CB_OUTPUT_BASENAME := $(shell echo $(BRAND_NAME) | tr A-Z a-z)-$(BOARD)-$(HEADS_ CB_OUTPUT_FILE := $(CB_OUTPUT_BASENAME).rom CB_OUTPUT_FILE_GPG_INJ := $(CB_OUTPUT_BASENAME)-gpg-injected.rom CB_BOOTBLOCK_FILE := $(CB_OUTPUT_BASENAME).bootblock +CB_UPDATE_PKG_FILE := $(CB_OUTPUT_BASENAME).zip LB_OUTPUT_FILE := linuxboot-$(BOARD)-$(HEADS_GIT_VERSION).rom all: @@ -50,6 +51,12 @@ endif # By default, we are building for x86, up to a board to change this variable CONFIG_TARGET_ARCH := x86 +# Legacy flash boards have to be handled specifically for some functionality +# (e.g. they don't generate upgrade packages, lack bash, etc.) Use this to +# guard behavior that is specific to legacy flash boards only. Don't use it for +# behavior that might be needed for other boards, use specific configs instead. +CONFIG_LEGACY_FLASH := n + include $(CONFIG) # Unless otherwise specified, we are building for heads @@ -159,7 +166,27 @@ payload: $(build)/$(BOARD)/bzImage $(build)/$(initrd_dir)/initrd.cpio.xz ifeq ($(CONFIG_COREBOOT), y) -all: $(board_build)/$(CB_OUTPUT_FILE) +# Legacy flash boards don't generate an update package, the only purpose of +# those boards is to be flashed over vendor firmware via an exploit. +ifneq ($(CONFIG_LEGACY_FLASH), y) +# talos-2 builds its own update package, which is not integrated with the ZIP +# method currently +ifneq ($(BOARD), talos-2) +# Coreboot targets create an update package that can be applied with integrity +# verification before flashing (see flash-gui.sh). The ZIP package format +# allows other metadata that might be needed to added in the future without +# breaking backward compatibility. +$(board_build)/$(CB_UPDATE_PKG_FILE): $(board_build)/$(CB_OUTPUT_FILE) + rm -rf "$(board_build)/update_pkg" + mkdir -p "$(board_build)/update_pkg" + cp "$<" "$(board_build)/update_pkg/" + cd "$(board_build)/update_pkg" && sha256sum "$(CB_OUTPUT_FILE)" >sha256sum.txt + cd "$(board_build)/update_pkg" && zip -9 "$@" "$(CB_OUTPUT_FILE)" sha256sum.txt + +all: $(board_build)/$(CB_OUTPUT_FILE) $(board_build)/$(CB_UPDATE_PKG_FILE) +endif +endif + ifneq ($(CONFIG_COREBOOT_BOOTBLOCK),) all: $(board_build)/$(CB_BOOTBLOCK_FILE) endif diff --git a/boards/UNTESTED_t430-legacy-flash/UNTESTED_t430-legacy-flash.config b/boards/UNTESTED_t430-legacy-flash/UNTESTED_t430-legacy-flash.config index 3d8cdadb..b09fd7ef 100644 --- a/boards/UNTESTED_t430-legacy-flash/UNTESTED_t430-legacy-flash.config +++ b/boards/UNTESTED_t430-legacy-flash/UNTESTED_t430-legacy-flash.config @@ -30,6 +30,8 @@ export CONFIG_BOOTSCRIPT=/bin/xx30-flash.init export CONFIG_BOARD_NAME="ThinkPad T430-legacy-flash" export CONFIG_FLASHROM_OPTIONS="--force --noverify-all -p internal --ifd --image bios" +CONFIG_LEGACY_FLASH=y + # This board is "special" in that we need a 4MB top SPI flashable ROM. # This is enough to allow the board to boot into a minimal Heads and read the full Legacy # ROM from an external USB media. diff --git a/boards/talos-2/talos-2.config b/boards/talos-2/talos-2.config index ad4347bc..7de53584 100644 --- a/boards/talos-2/talos-2.config +++ b/boards/talos-2/talos-2.config @@ -64,6 +64,6 @@ $(board_build)/$(OUTPUT_PREFIX).tgz: \ rm -rf $(board_build)/pkg # cleanup in case directory exists mkdir $(board_build)/pkg cp $^ $(board_build)/pkg - cd $(board_build)/pkg && sha256sum * > hashes.txt + cd $(board_build)/pkg && sha256sum * > sha256sum.txt cd $(board_build)/pkg && tar zcf $@ * rm -r $(board_build)/pkg diff --git a/boards/x230-legacy-flash/x230-legacy-flash.config b/boards/x230-legacy-flash/x230-legacy-flash.config index 1ad51a0f..533b5912 100644 --- a/boards/x230-legacy-flash/x230-legacy-flash.config +++ b/boards/x230-legacy-flash/x230-legacy-flash.config @@ -31,6 +31,8 @@ export CONFIG_BOOTSCRIPT=/bin/xx30-flash.init export CONFIG_BOARD_NAME="ThinkPad X230-legacy-flash" export CONFIG_FLASHROM_OPTIONS="--force --noverify-all -p internal --ifd --image bios" +CONFIG_LEGACY_FLASH=y + # This board is "special" in that we need a 4MB top SPI flashable ROM. # This is enough to allow the board to boot into a minimal Heads and read the full Legacy # ROM from an external USB media. diff --git a/create-npf.sh b/create-npf.sh deleted file mode 100755 index 2c64fede..00000000 --- a/create-npf.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/bash -set -exuo pipefail -HEADS_GIT_VERSION=$(git describe --tags) -BOARD=$1 -cd ./build/x86/${BOARD}/ -sha256sum heads-${BOARD}-${HEADS_GIT_VERSION}.rom > sha256sum.txt -sed -ie 's@ @ /tmp/verified_rom/@g' sha256sum.txt -zip heads-${BOARD}-${HEADS_GIT_VERSION}.npf heads-${BOARD}-${HEADS_GIT_VERSION}.rom sha256sum.txt diff --git a/initrd/bin/flash-gui.sh b/initrd/bin/flash-gui.sh index 4b66d5c0..4f1bb537 100755 --- a/initrd/bin/flash-gui.sh +++ b/initrd/bin/flash-gui.sh @@ -13,6 +13,33 @@ if [ "$CONFIG_RESTRICTED_BOOT" = y ]; then exit 1 fi +# Most boards use a .rom file as a "plain" update, contents of the BIOS flash +UPDATE_PLAIN_EXT=rom +# talos-2 uses a .tgz file for its "plain" update, contains other parts as well +# as its own integrity check. This isn't integrated with the "update package" +# workflow (as-is, a .tgz could be inside that package in theory) but more work +# would be needed to properly integrate it. +if [ "${CONFIG_BOARD%_*}" = talos-2 ]; then + UPDATE_PLAIN_EXT=tgz +fi + +# Check that a glob matches exactly one thing. If so, echoes the single value. +# Otherwise, fails. As always, do not quote the glob. +# +# E.g, locate a ROM with unknown version when only one should be present: +# if ROM_FILE="$(single_glob /media/heads-*.rom)"; then +# echo "ROM is $ROM_FILE" +# else +# echo "Failed to find a ROM" >&2 +# fi +single_glob() { + if [ "$#" -eq 1 ] && [ -f "$1" ]; then + echo "$1" + else + return 1 + fi +} + while true; do unset menu_choice whiptail $BG_COLOR_MAIN_MENU --title "Firmware Management Menu" \ @@ -30,38 +57,72 @@ while true; do ;; f | c) if (whiptail $BG_COLOR_WARNING --title 'Flash the BIOS with a new ROM' \ - --yesno "You will need to insert a USB drive containing your BIOS image (*.rom, *.npf or *.tgz).\n\nAfter you select this file, this program will reflash your BIOS.\n\nDo you want to proceed?" 0 80); then + --yesno "You will need to insert a USB drive containing your BIOS image (*.zip or\n*.$UPDATE_PLAIN_EXT).\n\nAfter you select this file, this program will reflash your BIOS.\n\nDo you want to proceed?" 0 80); then mount_usb if grep -q /media /proc/mounts; then - find /media ! -path '*/\.*' -type f \( -name '*.rom' -o -name '*.tgz' -o -type f -name '*.npf' \) | sort >/tmp/filelist.txt + if [ "${CONFIG_BOARD%_*}" = talos-2 ]; then + find /media ! -path '*/\.*' -type f -name "*.$UPDATE_PLAIN_EXT" | sort >/tmp/filelist.txt + else + find /media ! -path '*/\.*' -type f \( -name "*.$UPDATE_PLAIN_EXT" -o -type f -name "*.zip" \) | sort >/tmp/filelist.txt + fi file_selector "/tmp/filelist.txt" "Choose the ROM to flash" if [ "$FILE" == "" ]; then exit 1 else - ROM=$FILE + PKG_FILE=$FILE fi - # is a .npf provided? - if [ -z "${ROM##*.npf}" ]; then - #preventive cleanup - rm -rf /tmp/verified_rom >/dev/null 2>&1 || true - # unzip to /tmp/verified_rom - mkdir -p /tmp/verified_rom >/dev/null 2>&1 || true - unzip $ROM -d /tmp/verified_rom || die "Failed to unzip ROM file" + # is an update package provided? + if [ -z "${PKG_FILE##*.zip}" ]; then + # Unzip the package + PKG_EXTRACT="/tmp/flash_gui/update_package" + rm -rf "$PKG_EXTRACT" + mkdir -p "$PKG_EXTRACT" + # If extraction fails, delete everything and fall through to the + # integrity failure prompt. This is the most likely path if the ROM + # was actually corrupted in transit. Corrupting the ZIP in a way that + # still extracts is possible (the sha256sum detects this) but less + # likely. + unzip "$PKG_FILE" -d "$PKG_EXTRACT" || rm -rf "$PKG_EXTRACT" + # Older packages had /tmp/verified_rom hard-coded in the sha256sum.txt + # Remove that so it's a relative path to the ROM in the package. + # Ignore failure, if there is no sha256sum.txt the sha256sum will fail + sed -i -e 's| /tmp/verified_rom/\+| |g' "$PKG_EXTRACT/sha256sum.txt" || true # check file integrity - if (cd /tmp/verified_rom/ && sha256sum -cs /tmp/verified_rom/sha256sum.txt); then - ROM="$(head -n1 /tmp/verified_rom/sha256sum.txt | cut -d ' ' -f 3)" - else + if ! (cd "$PKG_EXTRACT" && sha256sum -cs sha256sum.txt); then whiptail --title 'ROM Integrity Check Failed! ' \ - --msgbox "$ROM integrity check failed. Did not flash.\n\nPlease check your file (e.g. re-download).\n" 16 60 - exit + --msgbox "Integrity check failed in\n$PKG_FILE.\nDid not flash.\n\nPlease check your file (e.g. re-download).\n" 16 60 + exit 1 fi + + # The package must contain exactly one *.rom file, flash that. + if ! PACKAGE_ROM="$(single_glob "$PKG_EXTRACT/"*."$UPDATE_PLAIN_EXT")"; then + whiptail --title 'BIOS Image Not Found! ' \ + --msgbox "A BIOS image was not found in\n$PKG_FILE.\n\nPlease check your file (e.g. re-download).\n" 16 60 + exit 1 + fi + + if ! whiptail $BG_COLOR_WARNING --title 'Flash ROM?' \ + --yesno "This will replace your current ROM with:\n\n${PKG_FILE#"/media/"}\n\nDo you want to proceed?" 0 80; then + exit 1 + fi + + # Continue on using the verified ROM + ROM="$PACKAGE_ROM" else + # talos-2 uses a .tgz file for its "plain" update, contains other parts as well, validated against hashes under flash.sh + # Skip prompt for hash validation for talos-2. Only method is through tgz or through bmc with individual parts + if [ "${CONFIG_BOARD%_*}" != talos-2 ]; then # a rom file was provided. exit if we shall not proceed + ROM="$PKG_FILE" ROM_HASH=$(sha256sum "$ROM" | awk '{print $1}') || die "Failed to hash ROM file" if ! (whiptail $CONFIG_ERROR_BG_COLOR --title 'Flash ROM without integrity check?' \ - --yesno "You have provided a *.rom file. The integrity of the file can not be\nchecked automatically for this file type.\n\nROM: $ROM\nSHA256SUM: $ROM_HASH\n\nIf you do not know how to check the file integrity yourself,\nyou should use a *.npf file instead.\n\nIf the file is damaged, you will not be able to boot anymore.\nDo you want to proceed flashing without file integrity check?" 0 80); then - exit + --yesno "You have provided a *.$UPDATE_PLAIN_EXT file. The integrity of the file can not be\nchecked automatically for this file type.\n\nROM: $ROM\nSHA256SUM: $ROM_HASH\n\nIf you do not know how to check the file integrity yourself,\nyou should use a *.zip file instead.\n\nIf the file is damaged, you will not be able to boot anymore.\nDo you want to proceed flashing without file integrity check?" 0 80); then + exit 1 + fi + else + #We are on talos-2, so we have a tgz file. We will pass it directly to flash.sh which will take care of it + ROM="$PKG_FILE" fi fi @@ -79,7 +140,7 @@ while true; do /bin/flash.sh "$ROM" fi whiptail --title 'ROM Flashed Successfully' \ - --msgbox "${ROM#"/media/"}\n\nhas been flashed successfully.\n\nPress Enter to reboot\n" 0 80 + --msgbox "${PKG_FILE#"/media/"}\n\nhas been flashed successfully.\n\nPress Enter to reboot\n" 0 80 umount /media /bin/reboot fi diff --git a/initrd/bin/flash.sh b/initrd/bin/flash.sh index 2d983862..6ef16a52 100755 --- a/initrd/bin/flash.sh +++ b/initrd/bin/flash.sh @@ -180,7 +180,7 @@ if [ "$READ" -eq 0 ] && [ "${ROM##*.}" = tgz ]; then mkdir /tmp/verified_rom tar -C /tmp/verified_rom -xf $ROM || die "Rom archive $ROM could not be extracted" - if ! (cd /tmp/verified_rom/ && sha256sum -cs hashes.txt); then + if ! (cd /tmp/verified_rom/ && sha256sum -cs sha256sum.txt); then die "Provided tgz image did not pass hash verification" fi