From 888d393f8be25021ae687c71ba810ccfe23f0b36 Mon Sep 17 00:00:00 2001 From: Johnathan Corgan Date: Thu, 1 Oct 2026 14:26:25 +0000 Subject: [PATCH] Report inputs the glibc floor check could not examine as unchecked check-glibc-floor.sh counted a missing path, a file that is not an ELF object and a .deb with no ELF executables as floor failures, so each exited 1 with "A binary above the floor installs cleanly and then fails to start" and the advice to rebuild in the container. Passing a release tarball, which is the usual mistake, therefore read as a broken release when nothing had been examined. A .deb that dpkg-deb could not unpack killed the script under set -e with no summary, leaving later arguments unexamined. Those inputs are now recorded as "could not check" with the reason, and listed at the end. A tarball's reason says to unpack it and pass its binaries. Exit status is 1 only when a binary is above the floor (still listing anything unchecked), 2 when anything could not be examined, and 0 only when every input was examined and passed. Neither caller branches on the status, and both stop on 1 or 2 as before. Two setup failures also exited 1: a missing packaging/build-floor.env ended the run through set -e when it was sourced, and an empty FIPS_GLIBC_FLOOR ended it through the ":?" expansion. The env file is now read only after a readable-file check, and an empty floor is caught by an explicit test; both exit 2 with a message saying there is no floor to check against. The file's shellcheck source directive now resolves from the script's directory, so shellcheck -x run from the repository root no longer reports SC1091. The floor check runs only at release time, so a regression in how it reports would surface on a release day. testing/glibc-floor/test.sh builds its inputs at run time from the host's own true executable (a text file, a tarball holding the binary, a missing path, an unreadable file, a corrupt .deb, a .deb holding only a script, and a .deb holding the binary), sets the floor explicitly in every case, and asserts the exit status, the "could not check" listing and the presence or absence of the rebuild advice. Scratch copies of the check cover a missing build-floor.env, an empty floor, a file that declares none, and one whose file supplies a floor. The test exits 2 rather than passing when readelf, dpkg-deb or a dynamic true is missing. ci-local.sh runs it beside the Debian version check, and ci.yml's static job runs the same script. --- .github/workflows/ci.yml | 5 + testing/check-glibc-floor.sh | 108 +++++++++++++++---- testing/ci-local.sh | 12 +++ testing/glibc-floor/test.sh | 195 +++++++++++++++++++++++++++++++++++ 4 files changed, 298 insertions(+), 22 deletions(-) create mode 100755 testing/glibc-floor/test.sh diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index daf8c116..c57cf625 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -106,6 +106,11 @@ jobs: # reports. Kept in step with ci-local.sh's run_nextest_flaky by hand. - name: Check the flaky-test reporter against its fixtures run: bash testing/nextest-flaky/test.sh + # The glibc floor check's cases, built from the host's own true + # executable. Not a matrix suite, so it is kept in step with + # ci-local.sh's run_glibc_floor by hand. + - name: Check the glibc floor check against its cases + run: bash testing/glibc-floor/test.sh fmt: name: Format check diff --git a/testing/check-glibc-floor.sh b/testing/check-glibc-floor.sh index 1ca81deb..cdce9506 100755 --- a/testing/check-glibc-floor.sh +++ b/testing/check-glibc-floor.sh @@ -16,17 +16,37 @@ # Anything else is treated as a single ELF binary. # # Reads the floor from packaging/build-floor.env unless FIPS_GLIBC_FLOOR is set. +# +# Exit 0 = every input was examined and none is above the floor. Exit 1 = a +# binary needs a newer glibc than the floor. Exit 2 = an input could not be +# examined (missing, not an ELF object, a .deb that would not unpack or holds +# no binaries), or the check could not run at all; never treated as a pass, +# and never reported as a binary above the floor. set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" +# A missing or empty floor means the check cannot run, so it exits 2 here +# rather than letting `set -e` or a `:?` expansion end the run with status 1, +# which callers would read as a binary above the floor. +FLOOR_ENV="$REPO_ROOT/packaging/build-floor.env" if [ -z "${FIPS_GLIBC_FLOOR:-}" ]; then - # shellcheck source=../packaging/build-floor.env - . "$REPO_ROOT/packaging/build-floor.env" + [ -r "$FLOOR_ENV" ] || { + echo "check-glibc-floor: cannot read $FLOOR_ENV and FIPS_GLIBC_FLOOR is not set;" >&2 + echo " there is no floor to check against." >&2 + exit 2 + } + # shellcheck source-path=SCRIPTDIR source=../packaging/build-floor.env + . "$FLOOR_ENV" fi -FLOOR="${FIPS_GLIBC_FLOOR:?no floor declared}" +if [ -z "${FIPS_GLIBC_FLOOR:-}" ]; then + echo "check-glibc-floor: $FLOOR_ENV declares no FIPS_GLIBC_FLOOR;" >&2 + echo " there is no floor to check against." >&2 + exit 2 +fi +FLOOR="$FIPS_GLIBC_FLOOR" for tool in readelf dpkg dpkg-deb; do command -v "$tool" >/dev/null 2>&1 || { @@ -65,6 +85,18 @@ max_glibc_need() { FAILED=0 CHECKED=0 +UNCHECKED=0 +UNCHECKED_LIST=() + +# unchecked