-
Notifications
You must be signed in to change notification settings - Fork 647
fix(libabigail): strip scanner-flagged PR30329 sqlite debuginfo fixtures from upstream tarball #17394
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: 4.0
Are you sure you want to change the base?
fix(libabigail): strip scanner-flagged PR30329 sqlite debuginfo fixtures from upstream tarball #17394
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| # The upstream libabigail tarball `libabigail-2.9.tar.xz` (Source0) ships an | ||
| # abidiff regression-test fixture set whose two separated-debuginfo files trip | ||
| # anti-malware scanning on the AZL RPM-signing pipeline, which rejects | ||
| # encrypted / unscannable payloads inside SRPMs: | ||
| # | ||
| # - tests/data/test-abidiff-exit/PR30329/{old,new}-image/usr/lib/debug/ | ||
| # usr/lib/x86_64-linux-gnu/libsqlite3.so.0.8.6.debug | ||
| # Stripped DWARF debuginfo for a pre-built upstream sqlite3 shared | ||
| # library, used (with dwz multifile companions) to exercise abidiff | ||
| # across separated-debuginfo + dwz layouts. The scanner flags both | ||
| # .debug files as "packer_high_entropy:eod". | ||
| # | ||
| # Replace upstream Source0 with a deterministically-repacked tarball produced | ||
| # by base/comps/libabigail/modify_source.sh, which strips the entire | ||
| # PR30329/ fixture directory (so nothing in-tree references the missing | ||
| # files) and patches tests/test-abidiff-exit.cc to drop the two | ||
| # `InOutSpec in_out_specs[]` entries that exercised the fixture, keeping | ||
| # `make check` green. The upstream filename is preserved so | ||
| # `replace-upstream = true` swaps the entry in place in the Fedora `sources` | ||
| # manifest -- no spec edit required. | ||
| [components.libabigail] | ||
|
|
||
| [[components.libabigail.source-files]] | ||
| filename = "libabigail-2.9.tar.xz" | ||
| hash = "526594be5ac79c01406cb33c2cb1b5003f8d2a341dcfb9c007479b89314aa8bea3e58a66605e104d81ab080a1036ff9538e5306c47656af0dc0965f4cbfa0ac0" | ||
| hash-type = "SHA512" | ||
| origin = { type = "download", uri = "https://azltempstaginglookaside.blob.core.windows.net/repo/pkgs_modified/libabigail/libabigail-2.9.tar.xz/sha512/526594be5ac79c01406cb33c2cb1b5003f8d2a341dcfb9c007479b89314aa8bea3e58a66605e104d81ab080a1036ff9538e5306c47656af0dc0965f4cbfa0ac0/libabigail-2.9.tar.xz" } | ||
| replace-upstream = true | ||
| replace-reason = "Repacked source tarball with tests/data/test-abidiff-exit/PR30329/ removed (two libsqlite3.so.0.8.6.debug fixtures inside it were flagged as packer_high_entropy:eod by the AZL signing-pipeline AV scanner) and tests/test-abidiff-exit.cc patched to drop the corresponding InOutSpec entries. See modify_source.sh." |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,244 @@ | ||
| #!/usr/bin/env bash | ||
| # | ||
| # libabigail: deterministic strip-and-repack of upstream `libabigail-2.9.tar.xz` | ||
| # with the PR30329 testsuite fixture set (which trips anti-malware scanning on | ||
| # the AZL RPM-signing pipeline) removed, plus the two corresponding entries | ||
| # in tests/test-abidiff-exit.cc patched out so `make check` still passes. | ||
| # Rationale lives in the comp.toml `replace-reason` field. | ||
| # | ||
| # Usage: bash base/comps/libabigail/modify_source.sh | ||
| # Output: base/build/work/scratch/libabigail/libabigail-2.9.tar.xz (+ .sha512) | ||
| # The upstream tarball is cached under a `.upstream` suffix; re-runs reuse it. | ||
|
|
||
| set -euo pipefail | ||
|
|
||
| # Pin umask so the extraction step below produces the same mode bits | ||
| # regardless of the caller's umask. With `--no-same-permissions`, tar ANDs | ||
| # each entry's mode against `~umask`, so e.g. umask 077 would silently strip | ||
| # group/other read bits and change the bytes of the repacked tarball. The | ||
| # repack step does not re-assert per-file modes (only owner/group/mtime), so | ||
| # this pin is what guarantees a byte-identical output across machines. | ||
| umask 022 | ||
|
|
||
| # --- Constants -------------------------------------------------------------- | ||
|
|
||
| readonly COMPONENT="libabigail" | ||
| readonly UPSTREAM_VERSION="2.9" | ||
| readonly UPSTREAM_FILENAME="${COMPONENT}-${UPSTREAM_VERSION}.tar.xz" | ||
| readonly UPSTREAM_TOPDIR="${COMPONENT}-${UPSTREAM_VERSION}" | ||
| readonly UPSTREAM_URL="https://mirrors.kernel.org/sourceware/libabigail/${UPSTREAM_FILENAME}" | ||
|
|
||
| readonly UPSTREAM_SHA512="5bdf5ec49a5931a61bf28317b41eee583d6277d00ac621b2d2a97bbc0d816c3662bcfe13a5ac7aeee11c947afb69a5a0a9a8015fcebad09965b45af9b1e23606" | ||
|
|
||
| # Directory (relative to ${UPSTREAM_TOPDIR}) to strip in its entirety. The | ||
| # PR30329 fixture set is a libabigail abidiff regression test built around a | ||
| # pair of stripped sqlite3 shared libraries + their separated debuginfo + | ||
| # dwz-multifile components. The two `libsqlite3.so.0.8.6.debug` separated- | ||
| # debuginfo files inside it are flagged as encrypted/unscannable payloads by | ||
| # the AV scanner ("packer_high_entropy:eod") in the AZL RPM-signing pipeline. | ||
| # We strip the whole PR30329/ directory (not just the two .debug files) so | ||
| # nothing in the tarball still references the missing pieces; the two | ||
| # corresponding `InOutSpec` entries in tests/test-abidiff-exit.cc are removed | ||
| # below so `make check` still passes. | ||
| readonly REMOVE_DIRS=( | ||
| "tests/data/test-abidiff-exit/PR30329" | ||
| ) | ||
|
|
||
| # File inside ${UPSTREAM_TOPDIR} to patch, and the marker substring that | ||
| # identifies the two `InOutSpec` entries we need to delete from it. Both | ||
| # entries reference the PR30329 fixture set we are stripping above. | ||
| readonly PATCH_FILE="tests/test-abidiff-exit.cc" | ||
| readonly PATCH_MARKER="PR30329" | ||
|
|
||
| # Deterministic-repack mtime: 2020-01-01T00:00:00Z (1577836800). | ||
| # Any fixed epoch works; do not change without also bumping the | ||
| # `hash` in libabigail.comp.toml. | ||
| readonly DETERMINISTIC_MTIME="@1577836800" | ||
|
|
||
| # --- Work directory --------------------------------------------------------- | ||
|
|
||
| SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" | ||
| REPO_ROOT="$(cd "${SCRIPT_DIR}/../../.." && pwd)" | ||
| WORKDIR="${REPO_ROOT}/base/build/work/scratch/${COMPONENT}" | ||
|
|
||
| mkdir -p "${WORKDIR}" | ||
| cd "${WORKDIR}" | ||
|
|
||
| echo "[1/6] Working in ${WORKDIR}" | ||
|
|
||
| # --- Download upstream ------------------------------------------------------ | ||
| # | ||
| # The upstream tarball is cached under a `.upstream` suffix so that | ||
| # the repacked output written at the canonical `${UPSTREAM_FILENAME}` | ||
| # path below cannot clobber the cache on re-runs. Treat the cache | ||
| # as authoritative only after SHA-512 verification. | ||
|
|
||
| UPSTREAM_CACHE="${WORKDIR}/${UPSTREAM_FILENAME}.upstream" | ||
|
|
||
| if [[ ! -f "${UPSTREAM_CACHE}" ]]; then | ||
| echo "[2/6] Downloading ${UPSTREAM_FILENAME} from ${UPSTREAM_URL}" | ||
| # `--proto` / `--proto-redir` restrict the initial request *and* any | ||
| # redirect target to HTTPS, so a downgrade to plain HTTP is refused. | ||
| curl -fsSL --retry 3 \ | ||
| --proto '=https' --proto-redir '=https' \ | ||
| -o "${UPSTREAM_CACHE}.part" "${UPSTREAM_URL}" | ||
| mv "${UPSTREAM_CACHE}.part" "${UPSTREAM_CACHE}" | ||
| else | ||
| echo "[2/6] Using cached upstream tarball ${UPSTREAM_CACHE}" | ||
| fi | ||
|
|
||
| # --- Verify upstream SHA-512 ------------------------------------------------ | ||
|
|
||
| echo "[3/6] Verifying upstream SHA-512" | ||
| COMPUTED_UPSTREAM_SHA512="$(sha512sum "${UPSTREAM_CACHE}" | awk '{print $1}')" | ||
| if [[ "${COMPUTED_UPSTREAM_SHA512}" != "${UPSTREAM_SHA512}" ]]; then | ||
| echo "ERROR: upstream SHA-512 mismatch (cache may be corrupt; delete ${UPSTREAM_CACHE} and re-run)" >&2 | ||
| echo " expected: ${UPSTREAM_SHA512}" >&2 | ||
| echo " computed: ${COMPUTED_UPSTREAM_SHA512}" >&2 | ||
| exit 1 | ||
| fi | ||
|
|
||
| # --- Extract + strip -------------------------------------------------------- | ||
|
|
||
| echo "[4/6] Extracting and stripping ${#REMOVE_DIRS[@]} fixture dir(s) from ${UPSTREAM_TOPDIR}" | ||
| rm -rf "${WORKDIR}/${UPSTREAM_TOPDIR}" | ||
| # `--no-same-owner` / `--no-same-permissions` prevent tar from applying the | ||
| # archive's uid/gid/mode bits to the extracted tree. They are already the | ||
| # default for non-root users, but explicit hardening makes the script safe | ||
| # to run under sudo (where the defaults flip) and defends against any | ||
| # setuid/setgid bits or unexpected ownership in the upstream tarball. | ||
| # Deterministic owner/group is re-asserted in the repack step below. | ||
| tar -C "${WORKDIR}" --no-same-owner --no-same-permissions -xf "${UPSTREAM_CACHE}" | ||
| for REMOVE_DIR in "${REMOVE_DIRS[@]}"; do | ||
| if [[ ! -d "${WORKDIR}/${UPSTREAM_TOPDIR}/${REMOVE_DIR}" ]]; then | ||
| echo "ERROR: expected '${UPSTREAM_TOPDIR}/${REMOVE_DIR}' not present in upstream tarball" >&2 | ||
| exit 1 | ||
| fi | ||
| echo " stripping ${UPSTREAM_TOPDIR}/${REMOVE_DIR}" | ||
| rm -rf "${WORKDIR}/${UPSTREAM_TOPDIR}/${REMOVE_DIR}" | ||
| done | ||
|
|
||
| # --- Patch testsuite driver ------------------------------------------------- | ||
| # | ||
| # Remove every `{ ... },` array-initializer block in ${PATCH_FILE} that | ||
| # mentions ${PATCH_MARKER}. The testsuite driver in | ||
| # tests/test-abidiff-exit.cc declares a hard-coded `InOutSpec in_out_specs[]` | ||
| # array; two of its entries reference the PR30329 fixture set we just | ||
| # stripped, and would cause `make check` to fail when those fixtures cannot | ||
| # be opened. The blocks are delimited by `{` ... `},` with no nested braces, | ||
| # so a tiny stateful Python pass is exact and robust. | ||
| echo "[5/6] Patching ${PATCH_FILE} to drop entries referencing ${PATCH_MARKER}" | ||
| PATCH_TARGET="${WORKDIR}/${UPSTREAM_TOPDIR}/${PATCH_FILE}" | ||
| if [[ ! -f "${PATCH_TARGET}" ]]; then | ||
| echo "ERROR: expected '${PATCH_FILE}' not present in upstream tarball" >&2 | ||
| exit 1 | ||
| fi | ||
| PRE_COUNT="$(grep -c -F "${PATCH_MARKER}" "${PATCH_TARGET}" || true)" | ||
| python3 - "${PATCH_TARGET}" "${PATCH_MARKER}" <<'PY' | ||
| import sys, pathlib | ||
|
|
||
| # Operate on bytes (not text) so the rewrite is byte-exact regardless of the | ||
| # caller's locale or any newline translation. Path.read_text() / write_text() | ||
| # would otherwise default to locale.getencoding() and `newline=None` | ||
| # (universal-newline mode), both of which can silently rewrite bytes and | ||
| # break deterministic repacking. | ||
| path = pathlib.Path(sys.argv[1]) | ||
| marker = sys.argv[2].encode("utf-8") | ||
| lines = path.read_bytes().splitlines(keepends=True) | ||
|
|
||
| # Scope the edit to the `InOutSpec in_out_specs[] = { ... };` array body. | ||
| # Inside that array, individual entries are ` {` ... ` },` blocks with | ||
| # no internal `{` / `}` (verified by inspection of upstream 2.9). Outside | ||
| # the array we touch nothing, which avoids accidentally eating function | ||
| # bodies, struct initializers in other code, etc. | ||
| ARRAY_DECL = b"InOutSpec in_out_specs[] =" | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I had a similar chat about this with @PawelWMS; we should figure out how to shift this toward legit The only transformation that we should be making to tarballs via these scripts right now is file removal. |
||
| start = None | ||
| for i, line in enumerate(lines): | ||
| if ARRAY_DECL in line: | ||
| start = i | ||
| break | ||
| if start is None: | ||
| sys.exit(f"ERROR: {ARRAY_DECL!r} not found in {path}") | ||
|
|
||
| # The opening `{` is the first line at column 0 starting with `{` after | ||
| # the declaration; the closing `};` is the first line starting with `};` | ||
| # after that. | ||
| body_start = next(i for i in range(start, len(lines)) if lines[i].lstrip().startswith(b"{")) | ||
| body_end = next(i for i in range(body_start + 1, len(lines)) if lines[i].lstrip().startswith(b"};")) | ||
|
|
||
| prefix = lines[: body_start + 1] | ||
| body = lines[body_start + 1 : body_end] | ||
| suffix = lines[body_end:] | ||
|
|
||
| out, buf, in_entry = [], [], False | ||
| for line in body: | ||
| stripped = line.strip() | ||
| if not in_entry and stripped == b"{": | ||
| in_entry = True | ||
| buf = [line] | ||
| continue | ||
| if in_entry: | ||
| buf.append(line) | ||
| if stripped == b"},": | ||
| block = b"".join(buf) | ||
| if marker not in block: | ||
| out.extend(buf) | ||
| buf = [] | ||
| in_entry = False | ||
| continue | ||
| # Comments / blank lines / preprocessor lines between entries: keep. | ||
| out.append(line) | ||
|
|
||
| if in_entry: | ||
| sys.exit(f"ERROR: unterminated entry while patching {path}") | ||
|
|
||
| path.write_bytes(b"".join(prefix + out + suffix)) | ||
| PY | ||
| POST_COUNT="$(grep -c -F "${PATCH_MARKER}" "${PATCH_TARGET}" || true)" | ||
| echo " ${PATCH_MARKER} occurrences in ${PATCH_FILE}: ${PRE_COUNT} -> ${POST_COUNT}" | ||
| if [[ "${POST_COUNT}" != "0" ]]; then | ||
| echo "ERROR: ${PATCH_MARKER} still present in ${PATCH_FILE} after patch" >&2 | ||
| exit 1 | ||
| fi | ||
|
|
||
| # --- Repack deterministically ----------------------------------------------- | ||
|
|
||
| echo "[6/6] Repacking deterministically as ${UPSTREAM_FILENAME}" | ||
| # Deterministic flags: | ||
| # --sort=name stable entry order | ||
| # --owner=0 --group=0 no host uid/gid leakage | ||
| # --numeric-owner force numeric uid/gid | ||
| # --mtime=@<epoch> fixed mtime | ||
| # --format=gnu handles long paths deterministically | ||
| # LC_ALL=C pins sort collation so --sort=name is locale-independent. | ||
| # xz -9e -T1 picks max compression with single-threaded output (multi-threaded | ||
| # xz produces non-deterministic byte streams). The upstream tarball is .xz so | ||
| # we re-emit .xz to keep the filename and Source0 unchanged. | ||
| MODIFIED_TARBALL="${WORKDIR}/${UPSTREAM_FILENAME}" | ||
| rm -f "${MODIFIED_TARBALL}" | ||
| LC_ALL=C tar \ | ||
| -C "${WORKDIR}" \ | ||
| --sort=name \ | ||
| --owner=0 --group=0 --numeric-owner \ | ||
| --mtime="${DETERMINISTIC_MTIME}" \ | ||
| --format=gnu \ | ||
| -cf - "${UPSTREAM_TOPDIR}" \ | ||
| | xz -9e -T1 -c > "${MODIFIED_TARBALL}" | ||
|
|
||
| MODIFIED_SHA512="$(sha512sum "${MODIFIED_TARBALL}" | awk '{print $1}')" | ||
| echo "${MODIFIED_SHA512} ${UPSTREAM_FILENAME}" > "${MODIFIED_TARBALL}.sha512" | ||
|
|
||
| echo | ||
| echo "================================================================" | ||
| echo "DONE" | ||
| echo " modified tarball: ${WORKDIR}/${UPSTREAM_FILENAME}" | ||
| echo " SHA512: ${MODIFIED_SHA512}" | ||
| echo "================================================================" | ||
| echo | ||
| echo " To upload the modified tarball to the lookaside:" | ||
| echo " az storage blob upload \\" | ||
| echo " --auth-mode login \\" | ||
| echo " --account-name azltempstaginglookaside \\" | ||
| echo " --container-name repo \\" | ||
| echo " --name \"pkgs_modified/${COMPONENT}/${UPSTREAM_FILENAME}/sha512/${MODIFIED_SHA512}/${UPSTREAM_FILENAME}\" \\" | ||
| echo " --file \"${WORKDIR}/${UPSTREAM_FILENAME}\"" | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1 +1 @@ | ||
| SHA512 (libabigail-2.9.tar.xz) = 5bdf5ec49a5931a61bf28317b41eee583d6277d00ac621b2d2a97bbc0d816c3662bcfe13a5ac7aeee11c947afb69a5a0a9a8015fcebad09965b45af9b1e23606 | ||
| SHA512 (libabigail-2.9.tar.xz) = 526594be5ac79c01406cb33c2cb1b5003f8d2a341dcfb9c007479b89314aa8bea3e58a66605e104d81ab080a1036ff9538e5306c47656af0dc0965f4cbfa0ac0 |
Uh oh!
There was an error while loading. Please reload this page.