8000 glibc-bedrock-2.42: seal only the sysroot subtree, not a whole second glibc by bryan-minimal · Pull Request #940 · gominimal/pkgs · GitHub
[go: up one dir, main page]

Skip to content

glibc-bedrock-2.42: seal only the sysroot subtree, not a whole second glibc - #940

Closed
bryan-minimal wants to merge 1 commit into
mainfrom
glibc-bedrock-sysroot-only-prebuilt
Closed

bryan-minimal wants to merge 1 commit into
mainfrom
glibc-bedrock-sysroot-only-prebuilt

Conversation

@bryan-minimal
@bryan-minimal bryan-minimal commented Oct 19, 2026 •
Copy link
Copy Markdown
Member

Summary

The sealed (hex0 switch off) arm of glibc-bedrock-2.42 now pins a sysroot-only artifact instead of the whole d0850b65 bedrock glibc.

The problem. d0850b65 is also the production glibc's replace_on_cycle root, so besides the versioned sysroot under usr/lib/glibc-bedrock-2.42/ it ships a full top-level glibc 2.42: usr/lib/libc.so.6, ld-linux-x86-64.so.2, crt*.o, gconv/, usr/include/**, usr/bin/* and usr/share/{i18n,locale}. minimal materializes a prebuilt = true package as its whole tarball and skips the outputs globs (only a consumer's subsetOf filters). So every bare import of glibc-bedrock-2.42 (the 28 JVM rungs, plus their runtime_deps) put a 2.42 libc in the merged /usr/lib next to production glibc 2.44. When two deps ship the same path, the one with the lower spec hash wins and the collision only produces a warning. That is the pkgs#895 classpath-0.93 FTBFS (sort: GLIBC_2.43 not found), and any rehash upstream could cause it again.

The fix. This PR fixes the artifact itself, so no bare import (now or later 8000 ) can bring the collision back. pkgs#937 (closed: subsetOf in build_deps panics minimal's executor). The JVM-only alternative is pkgs#941, which keeps the attested artifact and takes the sysroot slice through a collection. The two are compatible; either alone fixes #895. No companion change is required.

  • New artifact: gs://minimal-staging-archives/prebuilts/bedrock/sha256/62d398ef1e1b689664b982f43d0cfb3570ee2133c6be3ded434c4bb9d1c747bc/glibc-bedrock-2.42-sysroot-2.42.tar.zst (7.2 MB, down from 19.6 MB).
  • How it was made: download d0850b65, verify its sha256, then copy the raw tar records of every entry at or under usr/lib/glibc-bedrock-2.42 (plus the usr and usr/lib dir entries) unchanged. The order, headers, HeaderMode::Deterministic mtimes and GNU format all match the original, and the stream ends with tar-rs's two zero blocks. Recompressed with zstd -5 --no-check, which matches the level and no-checksum setting of minimal's compress_dir; the compressed bytes can't match tar-rs's encoder exactly. Uncompressed tar sha256: 96759457b66774c09ac50923235a5873469d2daa18c09626cbc4fc43efc2565b.
  • Checks run: an identity run of the filter (keeping etc and usr) reproduces the original tar byte-for-byte; diff -r --no-dereference of the extracted sysroot, original against repack, shows no differences (2630 entries kept, 1457 dropped); and a re-download from GCS matches the sha above.
  • The sealed arm's outputs are now sealed_outputs = { sysroot_lib, sysroot_include }, so they say what the tarball holds. The from-source arm (switch on) keeps all_outputs unchanged.

Nothing used the dropped tree.

  • The sysroot is a superset of it. All 503 top-level header files are also under …/include, and every top-level usr/lib library and crt is also under …/lib, except audit/ and locale/, which no consumer references.
  • Every consumer sets SR=/usr/lib/glibc-bedrock-2.42, with includes -isystem $SR/include first, -B$SR/lib -L$SR/lib and the loader at $SR/lib. This covers the 28 JVM rungs, jikes, go-1.4/1.17/1.20/1.22/1.24, mrustc and mrustc-rustc, rustc-1.91.1, binutils-2.46-glibc and gcc-15.2.0-glibc.
  • The only reference to top-level /usr/lib/libc.so.6 is a || true diagnostic in jikes-1.22's failure path.
  • binutils-2.46-glibc, gcc-15.2.0-glibc and rustc-1.91.1 already take subsetOf … ["sysroot_lib"].
  • arm64 is unaffected: there the spec is an empty collection.

Not changed. Production glibc's replace_on_cycle keeps d0850b65. It needs the top-level layout, and minimermetic's update-bedrock-roots.py manages that row (glibc Amd64). The minimermetic seals and in-toto envelopes cover d0850b65. This artifact is a deterministic subset of it that anyone can re-derive with the steps above; it is not separately attested.

Test plan

  • MINIMAL_SCIENCE_MODE=1 mip dump --packages evaluates on amd64 and arm64.
  • minimal build on this PR (the JVM ladder rungs rehash): green, a real 52-minute JVM-ladder rebuild.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Chores
    • Updated the glibc build setup for amd64 configurations with the ladder disabled to use a version-pinned sysroot package. Configurations with the ladder enabled continue to use the existing source build.
    • No end-user-facing behavior changes are included in this update.

Known limitation (pre-existing, not a regression; thanks @norrietaylor): two linker scripts inside the sysroot still point outside it. usr/lib/glibc-bedrock-2.42/lib/libm.so is GROUP(/usr/lib/libm.so.6 AS_NEEDED(/usr/lib/libmvec.so.1)) and lib/libm.a is GROUP(/usr/lib/libm-2.42.a /usr/lib/libmvec.a). The JVM rungs only rewrite libc.so (e.g. openjdk-17/build.sh:57-59), so -lm links against production libm (2.44) while the $SR/lib rpath loads 2.42 at runtime. That was already true on main. The follow-up is a libm fixlib rewrite in the JVM rungs, as the GHC ladder does (ghc-7.6.3/build.sh:84-85). The sealed tarball also predates today's recipe, which rewrites every sysroot linker script (build.sh:155-167).

… glibc

The sealed (hex0 switch off) arm pinned d0850b65, the artifact the production
glibc's replace_on_cycle slot anchors on. Besides the versioned sysroot under
usr/lib/glibc-bedrock-2.42/, it carries a full top-level glibc 2.42
(usr/lib/libc.so.6, ld-linux-x86-64.so.2, crt*.o, gconv, usr/include,
usr/bin). A prebuilt lands as its whole tarball (minimal skips outputs globs
for it), so every bare import put that 2.42 libc in the sandbox's merged
/usr/lib next to production glibc 2.44, and the lower spec hash won. That is
the pkgs#895 classpath-0.93 FTBFS (`sort: GLIBC_2.43 not found`).

Pin 62d398ef instead: d0850b65 with every tar entry outside
usr/lib/glibc-bedrock-2.42 dropped. The kept tar records are byte-identical
to the original (order, headers, mtimes; uncompressed sha256 96759457...),
recompressed with zstd -5 --no-check. The sealed arm's outputs narrow to
sysroot_lib + sysroot_include so they say what the tarball holds.

Nothing used the dropped tree: the sysroot is a superset of its headers and
libraries, every consumer reaches glibc through SR=/usr/lib/glibc-bedrock-2.42,
and the only top-level reference (jikes-1.22 build.sh) is a `|| true`
diagnostic. Production glibc keeps d0850b65, which its cycle root needs whole.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@bryan-minimal
bryan-minimal requested a review from a team as a code owner October 19, 2026 23:03
@coderabbitai
coderabbitai Bot commented Oct 19, 2026 •
Copy link
Copy Markdown
Contributor

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Repository: gominimal/pkgs/.coderabbit.yaml
  • Review profile: CHILL
  • Plan: Essentials
  • Run ID: 703ad8e6-67d8-4429-b0b7-f1b8ec2244ed
📥 Commits

Reviewing files that changed from the base of the PR and between 9dc1fd6 and 9b6d72e.

📒 Files selected for processing: 1
  • packages/glibc-bedrock-2.42/build.ncl

Included review availability: This review used your included allowance. 3 included reviews remain after this review. Your included PR review attempts over the past 7 days set your current allowance at 5 reviews per hour.

📝 Walkthrough

When the amd64 ladder is disabled, glibc-bedrock-2.42 now selects a SHA-pinned prebuilt archive containing the sysroot subtree and declares only the sysroot library and include outputs. The source build for the enabled ladder is unchanged.

Changes: glibc-bedrock prebuilt selection

Layer / File(s) Summary
Disabled-ladder prebuilt and outputs
packages/glibc-bedrock-2.42/build.ncl
The disabled-ladder configuration uses a SHA-pinned sysroot-only archive and declares only sysroot_lib and sysroot_include outputs. The archive omits the top-level glibc tree, including /usr/lib libraries and headers.

Priority: ➖ Normal

Estimated code review effort: 2 (Simple) | ~10 minutes

Change: Bug fix

Suggested reviewers: 0chroma

Merge Risk: ⚪ Minimal · up to 9b6d7

No concrete issue remains that blocks merging. The changed branch has not had a reported full build.

Pre-merge checks: Passed 5
Check name Status Explanation
Description Check Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check Passed The title clearly and concisely describes the main change: the sealed configuration now exports only the glibc sysroot subtree instead of a full second glibc tree.
Docstring Coverage Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff. Analyzed 0 functions across 0…
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
Full details: Docstring Coverage

Explanation

No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff. Analyzed 0 functions across 0 files. (1 skipped: 1 unsupported.)

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Comment @coderabbitai help to get the list of available commands.

@bryan-minimal
Copy link
Copy Markdown
Member Author

Verified against the failing case. On the lab (amd64, mip), I built classpath-0.93 from this PR's head (9b6d72e) with #895's python change applied on top:

  • jikes-1.22 and classpath-0.93 build (rc=0).
  • No glibc path collision in classpath's sandbox. The only Not linking … already exists lines left are the pre-existing libstdc++/libgcc pair.

Without the fix, the same tree with the original bedrock tarball reproduces the prod failure: /usr/lib/libc.so.6 is 2.42, and sort: … GLIBC_2.43 not found. So this fixes #895 by itself. It's also the broader fix, since the repacked tarball makes every bare glibc-bedrock-2.42 import safe (GHC, Go and mrustc ladders as well as the JVM one). #941, the JVM-only collection workaround, isn't needed if this merges.

🤖 Generated with Claude Code

8000

@norrietaylor norrietaylor left a comment
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks like the right root-cause fix. I re-derived the artifact:

  • The tarball's sha256 is 62d398ef…, and uncompressed it is 96759457…, matching the PR.
  • All 2,628 sysroot members are identical to d0850b65's (type, mode, mtime, link target and content sha), and nothing else remains outside usr/lib/glibc-bedrock-2.42.
  • crt files, libc_nonshared.a, the loader, libm*/libmvec*, gconv/ and the headers are all present, and libc.so already points inside the sysroot.
  • CI is green, and the 52-minute build looks like a real JVM-ladder rebuild.

Holding approval on one decision: the new artifact is hand-repacked and uploaded to staging, with no seal or in-toto envelope, replacing the minimermetic-attested d0850b65. It can be re-derived (as above), but I want to confirm we're OK with an unattested bedrock before approving. The alternative is #941, which keeps the attested artifact and filters it.

Other points:

  • Two linker scripts in the sysroot point outside it. …/lib/libm.so reads GROUP(/usr/lib/libm.so.6 AS_NEEDED(/usr/lib/libmvec.so.1)) and …/lib/libm.a reads GROUP(/usr/lib/libm-2.42.a /usr/lib/libmvec.a). After this PR, /usr/lib/libm.so.6 is always production 2.44, and /usr/lib/libm-2.42.a no longer exists anywhere.
    • The JVM rungs only rewrite libc.so (e.g. openjdk-17/build.sh:57-59), so -lm links against 2.44 but loads 2.42 at runtime through the $SR/lib rpath.
    • That's already true on main, so it isn't a regression. Still, the body's "nothing used the dropped tree" should mention it, and the JVM rungs need a follow-up libm fixlib rewrite, as the GHC ladder does (ghc-7.6.3/build.sh:84-85).
  • The body cites #937 as the companion change, but #937 was closed unmerged. Please reference #941, or say no companion is needed.
  • FYI: the current recipe (build.sh:155-167) rewrites every sysroot linker script, but the sealed artifact still has the /usr/lib/libm… paths, so the sealed tarball predates today's recipe.
  • The minimal build box in the test plan can be ticked.

Generated by Claude Code

@bryan-minimal
8000
Copy link
Copy Markdown
Member Author

@norrietaylor thanks for re-deriving it. Point by point:

The attestation question you're holding on is Bryan's call. I've laid out the options for him: take #941 now (attested, JVM-only), take this as-is (unattested but re-derivable, as you showed), or re-seal the sysroot-only artifact through minimermetic before merging. Either #940 or #941 unblocks #950 and #895, since the classpath-0.93 failure is what kills those runs.

🤖 Generated with Claude Code

@bryan-minimal
bryan-minimal added this pull request to the merge queue Oct 21, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to no response for status checks Oct 21, 2026
@bryan-minimal
Copy link
Copy Markdown
Member Author

Closing in favour of #941. Both fix the same failure (the glibc-bedrock-2.42 libc collision that breaks classpath-0.93 whenever python rehashes glibc: #895, #950), and landing both would cost two ~50-minute amd64 JVM-ladder rebuilds for no extra coverage today.

Why #941 over this one:

  • Provenance. jvm ladder: take only the glibc-bedrock-2.42 sysroot, via a collection #941 keeps the minimermetic-attested bedrock (d0850b65, gominimal/minimermetic#16) and filters it to the sysroot at the consumer, via a subsetOf collection. This PR swaps in a hand-repacked tarball (62d398ef…) with no seal or in-toto envelope. @norrietaylor re-derived it as bit-identical, but shipping an unattested bedrock in the middle of a security response is the wrong trade.
  • Coverage. This PR is broader (it also makes bare imports safe in the GHC, Go and mrustc ladders), but none of those is hitting the collision right now.

If we want the broader fix later: re-seal the sysroot-only artifact through minimermetic, then revive this change against the attested tarball. The repacked object stays at gs://minimal-staging-archives/prebuilts/bedrock/sha256/62d398ef…/ for reference; nothing references it once this is closed.

Thanks @norrietaylor and Mike for the reviews. The libm linker-script caveat noted here applies to #941 as well and is documented there.

🤖 Generated with Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

0