Skip to content

rewriteSections: rewrite executables like shared objects (#622)#637

Open
JamieMagee wants to merge 1 commit into
NixOS:masterfrom
JamieMagee:fix-vaddr-underrun
Open

rewriteSections: rewrite executables like shared objects (#622)#637
JamieMagee wants to merge 1 commit into
NixOS:masterfrom
JamieMagee:fix-vaddr-underrun

Conversation

@JamieMagee

@JamieMagee JamieMagee commented Apr 30, 2026

Copy link
Copy Markdown
Member

Patching a non-PIE (ET_EXEC) binary so the program header table grows made the executable rewrite path shift every LOAD segment's p_vaddr down, producing LOAD segments below the input's lowest p_vaddr. Where vm.mmap_min_addr is set to that floor (e.g. riscv64-linux at 0x10000), the kernel rejects the fixed-address mmap and the patched binary fails to load.

Shared objects already avoid this: rewriteSectionsLibrary appends the rewritten sections in a fresh PT_LOAD at the end of the file, leaving existing LOAD vaddrs unchanged. This routes ET_EXEC through the same path and removes rewriteSectionsExecutable.

Keeping the program header table at its canonical front offset matters for executables: loaders like qemu-user compute AT_PHDR as (lowest LOAD vaddr) + e_phoff, so a PHT moved into a tail segment is found at the wrong address.

Also hardens --build-resolution-cache to fail loudly on an already-present note even when .dynamic/.dynstr are unparseable.

Tested with no-vaddr-underrun.sh and under qemu-user (x86_64, aarch64); on the nixpkgs riscv64 bootstrap-tools gcc the load base stays at 0x10000 instead of dropping to 0xe000. CI is green across the emulated arches.

Closes #622

@domenkozar

Copy link
Copy Markdown
Member

Could you resolve conflicts?

@JamieMagee JamieMagee force-pushed the fix-vaddr-underrun branch from e4ae562 to b01116e Compare June 26, 2026 19:23
@JamieMagee

Copy link
Copy Markdown
Member Author

@domenkozar done!

@JamieMagee JamieMagee force-pushed the fix-vaddr-underrun branch from b01116e to cf2ebf3 Compare June 26, 2026 19:41
Patching a non-PIE (ET_EXEC) binary so that the program header table
grows made the executable rewrite path shift every LOAD segment's
p_vaddr down by one or more pages, producing LOAD segments below the
input's lowest p_vaddr. On systems that enforce vm.mmap_min_addr at that
floor (e.g. riscv64-linux at 0x10000) the kernel rejects the
fixed-address mmap at exec time and the patched binary fails to load.

Shared objects already avoid this: rewriteSectionsLibrary appends the
rewritten sections in a fresh PT_LOAD at the end of the file, leaving
every existing LOAD's vaddr unchanged. Route ET_EXEC through the same
path and drop the executable-specific rewriteSectionsExecutable.

The program header table stays at its canonical front offset, which
executables need: loaders such as qemu-user (and the dynamic linkers it
runs) compute AT_PHDR as (lowest LOAD vaddr) + e_phoff, so a PHT moved
to a tail segment with a different vaddr/offset skew would be found at
the wrong address.

Also harden buildResolutionCache to report an already-present cache note
loudly even when .dynamic/.dynstr are too malformed to parse, instead of
erroring on the section first.

Adds no-vaddr-underrun.sh (asserts the post-patch lowest LOAD p_vaddr is
not below the pre-patch value on a non-PIE x86_64 binary).
build-resolution-cache-no-pie.sh bakes a link-time DT_RPATH into the
main-no-pie fixture so it can build its layout without patchelf.

Closes NixOS#622
@JamieMagee JamieMagee force-pushed the fix-vaddr-underrun branch from cf2ebf3 to bd12049 Compare June 26, 2026 21:55
@JamieMagee JamieMagee changed the title rewriteSectionsExecutable: fall back to tail-append on vaddr underrun rewriteSections: rewrite executables like shared objects (#622) Jun 26, 2026
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.

patchelf should never generate LOAD segments with p_vaddr less than the lowest such address in the original file

2 participants