diff --git a/Makefile b/Makefile index d9ed41b2c..ef27d9697 100644 --- a/Makefile +++ b/Makefile @@ -271,18 +271,30 @@ else # 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. +# --- UPDATE PACKAGE (ZIP) --- +# +# The update zip contains three files: +# - The Heads ROM image (16 MiB flashable image) +# sha256sum.txt - SHA-256 of the ROM only (for update integrity checks) +# hashes.txt - Per-file hash manifest for reproducibility +# verification (same-commit CI comparison) and +# future flash-gui.sh introspection: compare the +# current ROM's files against the update ZIP's +# hashes.txt to report which scripts, modules, +# or kernel changed before deciding to flash $(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/" + cp "$(HASHES)" "$(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 + cd "$(board_build)/update_pkg" && zip -9 "$@" "$(CB_OUTPUT_FILE)" sha256sum.txt "$(notdir $(HASHES))" # Only add the hash and size if split_8mb4mb.mk is not included ifeq ($(wildcard split_8mb4mb.mk),) all: $(board_build)/$(CB_OUTPUT_FILE) $(board_build)/$(CB_UPDATE_PKG_FILE) - @sha256sum $(board_build)/$(CB_OUTPUT_FILE) | tee -a "$(HASHES)" - @stat -c "%8s:%n" $(board_build)/$(CB_OUTPUT_FILE) | tee -a "$(SIZES)" + @sha256sum $(board_build:$(pwd)/%=%)/$(CB_OUTPUT_FILE) | tee -a "$(HASHES)" + @stat -c "%8s:%n" $(board_build:$(pwd)/%=%)/$(CB_OUTPUT_FILE) | tee -a "$(SIZES)" else all: $(board_build)/$(CB_OUTPUT_FILE) $(board_build)/$(CB_UPDATE_PKG_FILE) endif @@ -300,8 +312,8 @@ $(error "$(BOARD): neither CONFIG_COREBOOT nor CONFIG_LINUXBOOT is set?") endif all payload: - @sha256sum $< | tee -a "$(HASHES)" - @stat -c "%8s:%n" $< | tee -a "$(SIZES)" + @sha256sum $(<:$(pwd)/%=%) | tee -a "$(HASHES)" + @stat -c "%8s:%n" $(<:$(pwd)/%=%) | tee -a "$(SIZES)" # Validate coreboot CBFS size against IFD BIOS region validate_cbfs_ifd: @@ -407,8 +419,8 @@ define do-cpio = echo "$(DATE) UNCHANGED $(1:$(pwd)/%=%)" ; \ rm "$1.tmp" ; \ fi - @sha256sum "$1" | tee -a "$(HASHES)" - @stat -c "%8s:%n" "$1" | tee -a "$(SIZES)" + @sha256sum "$(1:$(pwd)/%=%)" | tee -a "$(HASHES)" + @stat -c "%8s:%n" "$(1:$(pwd)/%=%)" | tee -a "$(SIZES)" $(call do,HASHES , $1,\ ( cd "$2"; \ echo "-----" ; \ diff --git a/doc/reproducible-builds.md b/doc/reproducible-builds.md index 82e74a9b6..4f69dcf2a 100644 --- a/doc/reproducible-builds.md +++ b/doc/reproducible-builds.md @@ -13,7 +13,9 @@ produce the same build triplet instead of probing the Docker host kernel. `-Wa,--no-pad-sections` prevents gas from padding section ends (non-deterministic alignment). `--with-debug-prefix-map=$(pwd)=.` normalizes build paths in debug info. `--enable-compressed-debug-sections=no` disables zlib debug-section -compression. `SOURCE_DATE_EPOCH` from the pinned musl-cross-make commit epoch +compression. `SOURCE_DATE_EPOCH=0` (extracted tarballs lack .git; the build system cannot +derive a commit timestamp from extracted tarballs, so `modules/musl-cross-make` falls back to +`echo 0` when `git log` fails) prevents `__DATE__`/`__TIME__` embedding during the GCC build. ## Userland compiler flags @@ -123,6 +125,18 @@ fetch_source_archive.sh. "https://output.circle-artifacts.com/output/job/circleci-job-id/artifacts/0/build/x86/EOL_t480-hotp-maximized/hashes.txt" ``` +### Output files + +A build produces these hash-related files under `build///`: + +| File | Content | +|---|---| +| `hashes.txt` | SHA-256 of every build artifact (cpio archives, bzImage, ROM) plus per-file hashes inside each cpio. Reset at each `make` invocation; appended by each build rule. The authoritative source for reproducibility verification. | +| `sizes.txt` | Byte sizes of each artifact, matching the hashes.txt entries. | +| `sha256sum.txt` | SHA-256 of the final ROM only. Packaged inside the update zip for integrity checks during flash updates. | + +Both `hashes.txt` and `sha256sum.txt` are included in the update zip for offline reproducibility verification. + ### Understanding hashes.txt `build/$ARCH/$BOARD/hashes.txt` records the SHA256 of **every file inside every diff --git a/modules/busybox b/modules/busybox index 07c51effa..462f72f9e 100644 --- a/modules/busybox +++ b/modules/busybox @@ -11,8 +11,6 @@ busybox_hash := b8cc24c9574d809e7279c3be349795c5d5ceb6fdf19ca709f80cde50e47de314 busybox_configure := $(MAKE) CC="$(heads_cc)" oldconfig busybox_config := config/busybox.config busybox_output := busybox -# Host compiler used by applets/busybox.mkll (busybox's Makefile uses gcc too) -busybox_hostcc ?= gcc busybox_target := \ $(CROSS_TOOLS) \ $(MAKE_JOBS) \ @@ -36,11 +34,15 @@ endif $(initrd_bin_dir)/busybox: $(build)/$(busybox_dir)/.build # Regenerate busybox.links (may be missing after clean/cache restore) + # mkll only runs the preprocessor (-E): cross-compiler is + # identical to host gcc for text-only header parsing and keeps + # the build chain self-contained (no host tools assumed) $(call do,INSTALL,bin/busybox,\ cp $(build)/$(busybox_dir)/busybox \ $(initrd_bin_dir)/busybox && \ cd $(build)/$(busybox_dir) && \ - HOSTCC="$(busybox_hostcc)" $(SHELL) applets/busybox.mkll include/autoconf.h include/applets.h > busybox.links && \ + HOSTCC="$(heads_cc)" \ + $(SHELL) applets/busybox.mkll include/autoconf.h include/applets.h > busybox.links && \ test -s busybox.links && \ $(SHELL) applets/install.sh $(initrd_bin_dir)/.. --symlinks \ ) diff --git a/modules/linux b/modules/linux index 6685d6530..9cef3100e 100644 --- a/modules/linux +++ b/modules/linux @@ -201,16 +201,18 @@ $(build)/$(BOARD)/modules.cpio: $(build)/$(linux_dir)/.build FORCE # linux build directory. We need to copy it into our board # specific directory for ease of locating it later. $(build)/$(BOARD)/$(LINUX_IMAGE_FILE): $(build)/$(linux_dir)/.build FORCE - $(call do-copy,$(dir $<)/$(linux_output),$@.tmp) - @if ! cmp --quiet "$@.tmp" "$@" ; then \ + $(call do,INSTALL ,$< => $@.tmp,\ + cp -a "$(dir $<)/$(linux_output)" "$@.tmp" \ + ) + @if [ ! -f "$@" ] || ! cmp --quiet "$@.tmp" "$@" ; then \ mv "$@.tmp" "$@" ; \ touch "$@" ; \ else \ echo "$(DATE) UNCHANGED $(@:$(pwd)/%=%)" ; \ rm "$@.tmp" ; \ fi - @sha256sum "$@" | tee -a "$(HASHES)" - @stat -c "%8s:%n" "$@" | tee -a "$(SIZES)" + @sha256sum "$(@:$(pwd)/%=%)" | tee -a "$(HASHES)" + @stat -c "%8s:%n" "$(@:$(pwd)/%=%)" | tee -a "$(SIZES)" # Build kernel second time, now that initrd is built. $(build)/$(BOARD)/$(LINUX_IMAGE_FILE).bundled: \