From d5f5e28a6324b253dc7ed3bfbbae2f24cf724085 Mon Sep 17 00:00:00 2001 From: Mathew Blowers Date: Mon, 26 Oct 2026 09:52:48 +0000 Subject: [PATCH] rpi-eeprom-config: Reject oversized bootcode updates The new bootcode was written before any size check so a file larger than the space before the next section silently overwrote the sections after it. Validate the size against the parsed layout first and add tests for the AB and non-AB 2712 images. --- rpi-eeprom-config | 18 +++++++--- test/test-rpi-eeprom-config | 66 ++++++++++++++++++++++++++++++++++++- 2 files changed, 78 insertions(+), 6 deletions(-) diff --git a/rpi-eeprom-config b/rpi-eeprom-config index 02f01b21..96b2ca4d 100755 --- a/rpi-eeprom-config +++ b/rpi-eeprom-config @@ -349,15 +349,23 @@ class BootloaderImage(object): """ if bootcode: hdr_offset, length, is_last, next_offset = self.find_file(dst_filename, partition_start=0, partition_end=READ_ONLY_SIZE) - struct.pack_into('>L', self._bytes, hdr_offset + 4, len(src_bytes)) - struct.pack_into(("%ds" % len(src_bytes)), self._bytes, hdr_offset + 8, src_bytes) - pad_start = hdr_offset + len(src_bytes) + 8 is_last = False debug("bootcode padded to %d" % next_offset); + + # The new bootcode plus its section header must fit in the space + # before the next non-padding section + if next_offset <= hdr_offset: + raise Exception("update-bootcode: Failed to find next section") if not self._is_ab_image and next_offset < 128 * 1024: raise Exception("update-bootcode: Can't update image - 128K must be reserved for bootcode") - if next_offset < 0: - raise Exception("update-bootcode: Failed to find next section") + max_len = next_offset - hdr_offset - 8 + if len(src_bytes) > max_len: + raise Exception("update-bootcode: %s is too large (%d bytes). The maximum size for this image is %d bytes." + % (dst_filename, len(src_bytes), max_len)) + + struct.pack_into('>L', self._bytes, hdr_offset + 4, len(src_bytes)) + struct.pack_into(("%ds" % len(src_bytes)), self._bytes, hdr_offset + 8, src_bytes) + pad_start = hdr_offset + len(src_bytes) + 8 else: hdr_offset, length, is_last, next_offset = self.find_file(dst_filename, partition_start=READ_ONLY_SIZE, partition_end=READ_ONLY_SIZE + PARTITION_SIZE) diff --git a/test/test-rpi-eeprom-config b/test/test-rpi-eeprom-config index b0af3c1a..170bcb79 100755 --- a/test/test-rpi-eeprom-config +++ b/test/test-rpi-eeprom-config @@ -12,11 +12,18 @@ die() { TMP_CONFIG="" TMP_EEPROM="" TMP_EEPROM2="" +TMP_BOOTCODE="" +TMP_DIR="" cleanup() { - rm -f "${TMP_CONFIG}" -f "${TMP_EEPROM}" "${TMP_EEPROM2}" + rm -f "${TMP_CONFIG}" -f "${TMP_EEPROM}" "${TMP_EEPROM2}" "${TMP_BOOTCODE}" + if [ -n "${TMP_DIR}" ]; then + rm -rf "${TMP_DIR}" + fi TMP_CONFIG="" TMP_EEPROM="" TMP_EEPROM2="" + TMP_BOOTCODE="" + TMP_DIR="" } trap cleanup EXIT @@ -164,6 +171,47 @@ check_conf_size_too_large() fi } +# Verify that rpi-eeprom-config can replace the bootcode +check_bootcode_update() +{ + echo "check bootcode update $1" + image="${script_dir}/$1" + + TMP_DIR="$(mktemp -d)" + (cd "${TMP_DIR}" && "${script_dir}/../rpi-eeprom-config" -x "${image}") + [ -f "${TMP_DIR}/bootcode.bin" ] || die "bootcode.bin was not extracted from ${image}" + TMP_BOOTCODE="$(mktemp)" + cp -f "${TMP_DIR}/bootcode.bin" "${TMP_BOOTCODE}" + expected_md5="$(md5sum "${TMP_BOOTCODE}" | awk '{print $1}')" + + TMP_EEPROM="$(mktemp)" + "${script_dir}/../rpi-eeprom-config" \ + "${image}" \ + --bootcode "${TMP_BOOTCODE}" \ + --out "${TMP_EEPROM}" + + rm -f "${TMP_DIR}/bootcode.bin" + (cd "${TMP_DIR}" && "${script_dir}/../rpi-eeprom-config" -x "${TMP_EEPROM}") + actual_md5="$(md5sum "${TMP_DIR}/bootcode.bin" | awk '{print $1}')" + [ "${actual_md5}" = "${expected_md5}" ] || die "EEPROM bootcode update: checksum mismatch" +} + +# Verify that rpi-eeprom-config rejects a bootcode which does not fit in the +# space before the next section +check_bootcode_too_large() +{ + echo "check bootcode which exceeds the available space $1 $2" + image="${script_dir}/$1" + + TMP_BOOTCODE="$(mktemp)" + head -c "$2" /dev/zero > "${TMP_BOOTCODE}" + + TMP_EEPROM="$(mktemp)" + if "${script_dir}/../rpi-eeprom-config" "${image}" --bootcode "${TMP_BOOTCODE}" --out "${TMP_EEPROM}" > /dev/null 2>&1; then + die "bootcode of $2 bytes should have been rejected" + fi +} + echo "Check config read and loopback read/write against reference config files" versions="$(cd configs; ls *.txt | sed 's/bootconf-//g' | sed 's/.txt//g')" for ver in ${versions}; do @@ -192,3 +240,19 @@ cleanup check_conf_size_too_large "../firmware-2711/old/beta/pieeprom-2019-07-15.bin" cleanup + +echo "Test bootcode replacement in BCM2712 images (AB and non-AB layouts)" +check_bootcode_update "../firmware-2712/old/latest/pieeprom-2026-05-13.bin" +cleanup + +check_bootcode_update "../firmware-2712/old/latest/pieeprom-2025-12-08.bin" +cleanup + +check_bootcode_too_large "../firmware-2712/old/latest/pieeprom-2026-05-13.bin" 70000 +cleanup + +check_bootcode_too_large "../firmware-2712/old/latest/pieeprom-2026-05-13.bin" 3145728 +cleanup + +check_bootcode_too_large "../firmware-2712/old/latest/pieeprom-2025-12-08.bin" 200000 +cleanup