Repository navigation
fix(relinker): bound the entry point collector's header and symbol reads - #2196
Conversation
|
Full Linux and Windows builds and tests for this head (
Run: https://github.com/AchrafReyani/AnyPS5/actions/runs/37923946113 |
|
To clarify the note about |
|
Please rebase: |
The CFG/GOT filter's entry point collector checked header and symbol positions as `offset + size > file size`, which wraps for offsets near 2^64. A section header or symbol table offset there passed the check, read bytes before the input buffer, and could reach an in-bounds table through the wrapped address, adding entry points that keep relocations alive. Check every position by subtraction instead. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
fcba0b0 to
b1599a9
Compare
|
Rebased onto current Relinker-only build on Windows: |
|
Other open pull requests touch the same code. Merging one will break the other, or both implement the same thing. If this one builds on them, list them in Depends on.
|
|
Full Linux and Windows builds and tests for this head (
Run: https://github.com/AchrafReyani/AnyPS5/actions/runs/38027423754 |
…ry-point-bounds fix(relinker): bound the entry point collector's header and symbol reads
What
Refs #1666, which asks to review the adjacent table reads for the same arithmetic pattern; this is one such finding.
The CFG/GOT filter (
unused-filter=1, which runs on non-PLT references) collects entry points inUnusedNidFilter/EntryPointCollector.cpp. It checked every position asoffset + size > file sizeor<= file size: the program headers,PT_DYNAMIC, the init/fini arrays, the section headers, the section name table, thesh_linkheader and the symbol entries. With an offset near 2^64 the sum wraps, the check passes, and the uncheckedread*helpersmemcpyfrom outside the input. The relinker validates none of these section header fields before this point.Measured on
main(d70b8998), with the read helpers temporarily instrumented to report out-of-range reads:e_shoff = 2^64 - 32with two section headers reads 8 bytes at offset -8 and 4 bytes at -28, both before the input buffer, and the relink still exits 0.e_shoff = 2^64 - 64ande_shentsize = 0x840, section 1 is read from file offset 0x800. ASHT_SYMTABthere adds a function that nothing else reaches to the entry points, so theGLOB_DATreference it loads is kept (CFG/GOT filtering: 1 -> 1). The same happens with an in-bounds section header whose symbol table offset wraps (sh_offset = 2^64 - 24).The fix checks each position by subtraction (
base <= size && offset <= size - base && length <= size - base - offset), the same formRelinkerPipelineuses for RELA entries since #917. Out-of-range tables keep their existing handling: program headers andPT_DYNAMICstill throw, and the best-effort section and array scans still stop.RelativeRelocationIndex.cpphas the same pattern (pos + RelaEntSize,phPos + 56,segOff + segSz), but it is not reachable: by the time it runs, the pipeline has already rejected a wrappinge_phoff(FileByteOffset out of bounds),PT_DYNAMIC(Dynamic segment out of bounds) and RELA table. I checked by instrumenting its read helpers the same way. So it is left unchanged.Tested
Windows 11, WinLibs GCC 15.2.0 r7, relinker-only Release build,
-DBUILD_TESTING=ON:New
entry_point_boundstest (Python, relinker fixture,--windows unused-filter=1), with aGLOB_DATreference loaded only by a function that only a symbol makes reachable:main1 -> 01 -> 01 -> 11 -> 11 -> 11 -> 01 -> 11 -> 0cteston the relinker-only build: 41/41 passed.tools/check_conventions.pyandtools/check_test_registration.pypass, andtools/pr_overlap.py --branchreports no overlap.Checklist
main; no other open PR implements the same functionsNotImplemented_nid_no_patch); silent stubs are listed in TechnicalDebt.mdfiles or images added to the repository (attach them to this PR)🤖 Generated with Claude Code