fix(elf): keep program header table intact through eu-strip#75
Merged
Conversation
`Elf::append` relocates the program header table past the original EOF, into the file gap just before the appended note. `eu-strip` (elfutils, as run by flatpak-builder) lays the stripped output out itself with `ELF_F_LAYOUT` and zero-fills every file gap that falls between two allocated sections. With only a note-sized `.note.sui` section past that gap, eu-strip treats the relocated program header table as dead space and zeroes it, producing a binary with an all-zero program header table that segfaults on exec (exit 139). This is the deno 2.9 "compiled binary segfaults in flatpak" regression (denoland/deno#35633), introduced when the in-place append landed in 0.16.0. Cover the program header table with its own allocated `.sui.phdrs` (SHT_PROGBITS) section so section-based strip tools that preserve the byte layout keep it. It must be a separate PROGBITS section rather than folding the bytes into `.note.sui`: BFD `strip` parses SHT_NOTE contents, so a note section spanning the (non-note) program header bytes corrupts the note and loses it on strip. `.note.sui` keeps covering only the note; the runtime still discovers it through its PT_NOTE program header. Adds a regression test that appends a note, runs `eu-strip`, and asserts the program header table is not zeroed, the note still round-trips, and the stripped binary still executes.
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #75 +/- ##
==========================================
+ Coverage 72.00% 72.74% +0.73%
==========================================
Files 3 3
Lines 1036 1064 +28
==========================================
+ Hits 746 774 +28
Misses 290 290 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
littledivy
added a commit
to denoland/deno
that referenced
this pull request
Jul 2, 2026
…35699) Fixes #35633 ## Problem Standalone binaries produced by `deno compile` segfault (exit 139) after `eu-strip` runs over them — which `flatpak-builder` does automatically during a flatpak build. Regression in Deno 2.9, bisected to the libsui 0.16.0 bump (#35467). ## Root cause libsui's in-place `Elf::append` (new in 0.16.0) relocates the program header table past the original EOF, into the file gap just before the appended note. `eu-strip` (elfutils, as run by flatpak-builder) lays the stripped output out itself with `ELF_F_LAYOUT` and zero-fills every file gap that falls between two allocated sections. With only a note-sized `.note.sui` section past that gap, eu-strip treats the relocated program header table as dead space and zeroes it → all-NULL program headers → segfault on exec. ## Fix libsui 0.16.1 (denoland/sui#75) covers the relocated program header table with a dedicated allocated `.sui.phdrs` section so section-based strip tools preserve it. This bumps the dependency and adds a spec test that `eu-strip`s a compiled binary and asserts it still runs (skips gracefully where `eu-strip` isn't installed). ## Verification Reproduced and fixed against the exact flatpak toolchain (elfutils **0.193**, built from source) on Linux x86_64: - real `deno 2.9.0` compiled binary + eu-strip 0.193 (flatpak flags) → **segfault 139**; with 0.16.1 → **runs** - every binary shape (PIE+RELR, plain PIE, non-PIE, large `.bss`, section-header-stripped, fully stripped) × eu-strip 0.193 & 0.190 → runs, program headers intact - payload sizes 1 B – 1 MB → payload still recoverable after strip - real denort 2.9.0 base → program headers intact after strip - binutils `strip` note-survival preserved (unchanged from 0.16.0)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
deno compilebinaries built inside a flatpak sandbox segfault at startup (exit 139) since Deno 2.9 — denoland/deno#35633. Bisected to libsui 0.16.0 (the in-placeElf::appendfrom #72).Root cause
Elf::appendrelocates the program header table past the original EOF, into the file gap just before the appended note.flatpak-builderrunseu-strip(elfutils), which lays the stripped output out itself withELF_F_LAYOUTand zero-fills every file gap that falls between two allocated sections. With only a note-sized.note.suisection past that gap, eu-strip treats the relocated program header table as dead space and zeroes it → all-NULL program headers → segfault on exec.Reproduced directly with
deno 2.9.0on Linux: compiled binary →eu-strip→ 14 NULL program headers, exit 139.Two other theories were ruled out empirically:
.note.suisection stops the crash but eu-strip then discards the unbacked note → "Could not find standalone binary section" (payload lost).PT_LOADis not the trigger —patchelfproduces the same layout and survives eu-strip; the deciding factor is whether the phdr table is covered by an allocated section.Fix
Cover the relocated program header table with its own allocated
.sui.phdrs(SHT_PROGBITS) section so section-based strip tools that preserve the byte layout keep it. It has to be a separate PROGBITS section rather than folding the bytes into.note.sui: BFDstripparsesSHT_NOTEcontents, so a note section spanning the (non-note) program header bytes corrupts the note and loses it on strip..note.suikeeps covering only the note; the runtime still discovers it via itsPT_NOTEprogram header.Test
Adds
test_elf_note_survives_eu_strip: appends a note, runseu-strip, and asserts the program header table is not zeroed, the note still round-trips, and the stripped binary still executes (skips gracefully ifeu-stripis absent). Updatestest_elf_append_preserves_original_bytesfor the extra section header.Verified on Linux (elfutils 0.190): before — segfault; after — runs, phdrs intact, payload found.
test_elf_note_survives_strip(BFDstrip) still passes.Note: BFD
stripstill breaks exec on these binaries, but that is pre-existing (0.16.0 behaves the same) and flatpak uses eu-strip.