Repository navigation
fix(relinker): validate executable export names and attributes like guest modules - #11381
Conversation
…uest modules The executable export loop accepted names that are empty after stripping '#', IFUNC, FILE, COMMON and SECTION types, bindings above STB_WEAK, st_other bits above the visibility, and same-name exports that differ, and Linux copied them into .dynsym. It now rejects them before the location checks with the rule GuestImageReader applies to non-local guest symbols, while identical aliases stay accepted. Every target reports the same line at the symbol entry offset, and the macOS attribute and empty-name checks, now unreachable, are removed.
…able-export-attributes
…able-export-attributes
|
Review follow-up: the new executable export validation is well specified and the hosted Linux, macOS and macOS x86_64 relinker checks pass. The Windows relinker job failed after 253.68 s with four |
|
Some comparisons could not be completed because a pull request conflicts with the base branch. Review these shared files manually before concluding that there is no overlap.
|
|
@MarcZX10 Thanks. The Windows failure was on the earlier head de709f9 (Build run 40304520175). On the current head 12ad27b, which merges |
MarcZX10
left a comment
There was a problem hiding this comment.
Thanks for clarifying the scope: I verified the current diff against main; it is the six-file change you described, and the Windows relinker rerun passed alongside the other hosted relinker jobs and ASan. The implementation and focused tests look sound.
One current-main gate remains before merge. The branch contains the merge of main at 5b5d24cb22, while current main is cbf76e7a6e and includes the later #9408 macOS import-tracing changes in RelinkerPipeline.cpp. The preview merge is clean, but the reported local matrix and current hosted checks are on the older merged base. Please sync the latest main and rerun the focused export tests (and hosted relinker matrix) on that exact head. CONTRIBUTING.md asks branches to stay up to date with main; I’m holding approval until that integration is checked.
…able-export-attributes
|
@MarcZX10 Merged current |
MarcZX10
left a comment
There was a problem hiding this comment.
Reviewed the refreshed head a9d053f4be0c13b1a8679e04aa07f345213435e9. The export-name, binding, visibility, type and duplicate checks match the documented guest-module restrictions; the author reports the focused export/tracing tests and current-head relinker matrix passing. The remaining request is integration validation: this head is based on 4b1a9a3b2f, while current main is 2db37cf1de46fd7b133fc5d0be1e395340f0fd2c and adds TLS-symbol bounds handling in the same RelinkerPipeline.cpp before the export loop. The hunk is separate, but the branch/report do not include it. Please sync current main and rerun the focused export tests before merge. AI-assisted review; the author-reported Windows/full-suite results are accurately distinguished from the hosted matrix.
|
Correction to my earlier base note: |
…able-export-attributes
|
@MarcZX10 Synced: b93be68 merges current |
THEMANnt
left a comment
There was a problem hiding this comment.
Reviewed b93be6845b4d against 7b415520b607. No actionable findings.
The relinker validates defined, nonlocal, visible executable exports before target conversion: stripped names must be nonempty; binding, visibility and type must be supported; same-name entries must match in every field after st_name. Identical aliases remain accepted for Linux/Windows, while macOS retains its duplicate-trie rejection. This closes malformed IFUNC and conflicting dynamic-symbol paths and matches guest-module validation.
Validation: Hosted relinker CTests passed on the pinned head: Windows 310, Ubuntu 314, and both macOS jobs 304 each; the ASan job’s 34 TLS-coverage tests passed. Full-product Windows/Linux jobs were skipped. Locally, the current-main-plus-patch relinker built with GCC 15.3 and 12 focused CTests passed. A 28-case review-only sweep covered duplicate-field differences and ordering, hidden/internal IFUNC skips, input preservation, and absent outputs on rejection. Unpatched main accepted the empty-name negative-control fixture that the candidate rejects.
The local cache lacked the pinned PR objects, so local tests used the patch on 035ac96; hosted checks ran exact head b93be6845b4d.
Dismissing a stale review: the requested changes were addressed after it (new head) and the merge queue blocks on it. Please request changes again if anything is still open.
|
Checked the export name, attribute and duplicate rules against |
What
The executable export loop in
RelinkerPipeline.cpp(#10646) checked where an export lies but not its name or attributes: on untouched 4017310,relinker --skip-sce-modulefor Linux, Linux--lazy-bindingand--windowsexited 0 for an export whose name is empty after stripping#("",#A#B), anSTT_GNU_IFUNC,STT_FILE,STT_COMMONor globalSTT_SECTIONexport, binding 3 or 10 (STB_GNU_UNIQUE),st_other0x10, and two exports with the same stripped name and different values or bindings. Linux copies these entries into.dynsymwith only the name rewritten, so ld.so calls an IFUNC export as a resolver and binds conflicting duplicates by hash-chain order;--macosalready refused all of them exceptst_other0x10, with its own messages (Empty macOS executable export,Unsupported macOS executable export attributes,Duplicate Mach-O export), andGuestImageReader.cpp:189-192refuses all of them in guest modules.STB_LOCAL, visibility not hidden or internal), and before the fix(relinker): reject executable exports outside PT_LOAD and PT_TLS memory #10646 location checks so an IFUNC is not reported as misplaced data, the relinker throws, at the symbol entry's file offset:Empty executable export namewhen the name is empty after stripping#;Unsupported executable export attributes: <name>when the binding is aboveSTB_WEAK,st_other & ~3is not 0, or the type is notSTT_NOTYPE,STT_OBJECT,STT_FUNCorSTT_TLS, the setGuestImageReader.cpp:189accepts for non-local symbols;Conflicting executable exports after stripping #: <name>when a later export has the same stripped name and differs in any byte afterst_name(info, other, section, value, size). Identical aliases stay accepted, unlike in the guest reader, which accepts only identical function exports and only for Windows: the pipeline does not know the target, identical entries are not ambiguous for ld.so, and--macosstill refuses them in its export trie (Duplicate Mach-O export). Local, hidden and internal symbols stay unchecked.ElfConstants.hppgetsSTT_OBJECT. Windows writes no executable exports (only the names feedGuestModuleBuilder), so its output does not change; it only refuses these inputs now, as with fix(relinker): reject executable exports outside PT_LOAD and PT_TLS memory #10646. The macOS attribute and empty-name checks inMacOsMachOPatcher.cpp(lines 84-86 and 88 ofmain) are removed:Conversion.cpp:178is their only caller, every defined entry of the symbol table it passes is one thatRelinkerPipeline.cppcopied from the pipeline's exports with stripped names (its import entries have section index 0 and the same filter skips them), andGuestModuleBuilderrewrites only undefined entries, so every symbol that reached them now passes the stricter pipeline rule. Lines 92-99 ofmain(the TLS and section checks of the same loop, unreachable since fix(relinker): reject executable exports outside PT_LOAD and PT_TLS memory #10646 rather than through this change) are left as they are for a separate follow-up.test_executable_export_attributes.py, registered afterexecutable_export_bounds, reuses that test's fixture. Thirteen inputs must fail on Linux, Linux--lazy-binding,--windowsand--macoswith the sameFAIL:line at the symbol entry offset (0x4918, or 0x4930 for the later entry of a pair) and no output: empty name,#A#B, IFUNC (0x1a at 0x200),STT_FILE,STT_COMMON, globalSTT_SECTION, binding 3, binding 10,st_other0x10,foo/fooat 0x1100 and 0x1108,foo/foo#A#Bat 0x1100 and 0x1108, globalfooagainst weakfoo, andSTT_FUNCfn/fn#A#Bat 0x200 and 0x206. Identicalfn/fn#A#Band identicalobj/objduplicates must convert on Linux, lazy and Windows and fail on macOS withDuplicate Mach-O export; a protected object and a local IFUNC must convert on all four targets. 68 runs.test_macos_executable_exports.pynow expectsUnsupported executable export attributes: Indirectfor its IFUNC case.pr_overlap.pyreports no shared lines with open pull requests that merge withmain. It cannot compare this branch with feat(aot): consolidate native ARM64 compiler, runtime and consumers #5021 and fix(libc): use the default heap for an executable without process parameters #6713 (core/relinker/CMakeLists.txt), feat(relinker): route ps5-payload-dev pathconf stub to libkernel export #10792 (CMakeLists.txt,RelinkerPipeline.cpp) and fix(relinker): analyze referenced code beyond SCE scan boundaries #10861 (CMakeLists.txt,RelinkerPipeline.cpp,MacOsMachOPatcher.cpp), because those do not merge withmain. Checked by hand, in lines ofmain7b41552: inCMakeLists.txtthis PR registersexecutable_export_attributesafterexecutable_export_bounds(after line 592), while feat(aot): consolidate native ARM64 compiler, runtime and consumers #5021 addsmacos_fixturesaftermacos_output(lines 671 to 679), fix(libc): use the default heap for an executable without process parameters #6713 adds a test after line 772, feat(relinker): route ps5-payload-dev pathconf stub to libkernel export #10792 after line 632, and fix(relinker): analyze referenced code beyond SCE scan boundaries #10861 rewrites lines 261 to 270 and 274 to 283 and adds tests after line 800. InRelinkerPipeline.cppthis PR adds an#includeafter line 11 and changes the executable export loop (after lines 446 and 457); feat(relinker): route ps5-payload-dev pathconf stub to libkernel export #10792 addsFindPathconfImportafter line 25 and changes the syscall patch loop (lines 431 to 437), and fix(relinker): analyze referenced code beyond SCE scan boundaries #10861 changes the unwind block that fix(relinker): mask embedded data tables in inter-FDE gaps #8076 rewrote onmain(thehasEhFrameblock, lines 403 to 416), adds a tail scan after line 439 andSyscallContinuationsafter line 632. InMacOsMachOPatcher.cppfix(relinker): analyze referenced code beyond SCE scan boundaries #10861 adds one line after line 77, before the export loop whose lines 84 to 86 and 88 this PR removes. Trial merges of this branch with each of the four conflict in the same files and regions asmaindoes, and apart from the conflict marker labels the merged trees differ from those ofmainonly by the lines of this PR. feat(relinker): route ps5-payload-dev pathconf stub to libkernel export #10792 reads only imports, and feat(aot): consolidate native ARM64 compiler, runtime and consumers #5021 and fix(libc): use the default heap for an executable without process parameters #6713 do not touch export handling; the tail scan of fix(relinker): analyze referenced code beyond SCE scan boundaries #10861 runs before the export loop and uses defined function symbols as code roots but does not change exports, and the only executable export in its new test,tail(a global function, or a global object in itslea-observercases), passes the new rule.Tested
Windows 11, GCC 15.2.0 (WinLibs UCRT), relinker-only Release build (
-DANYPS5_RELINKER_ONLY=ON -DBUILD_TESTING=ON); synthetic fixtures only, no title or homebrew.test_macos_executable_exports.pyedit on untouched 4017310,executable_export_attributesfails withAssertionError: ('empty_name-linux', 0, ...)andmacos_executable_exportswithAssertionError: ('attributes', 2, 'FAIL: Unsupported macOS executable export attributes ...'). A per-case probe of the same build: all 13 refusal inputs exited 0 on Linux, lazy and Windows; on macOS empty name and#A#Bfailed withEmpty macOS executable export, the six attribute inputs withUnsupported macOS executable export attributes, the four conflicting pairs withDuplicate Mach-O export, andst_other0x10 exited 0. The accepted inputs behaved as with the change. With the change every refusal input fails with the new line on all four targets.main, on 4017310:ctest -R 'export|executable|macos|guest' -j 3: 43 tests passed in 19.5 s, among themexecutable_export_attributes(2.1 s),executable_export_bounds,macos_executable_exports,linux_executable_exports,executable_tls_relocations,executable_segments,relinker_executables,guest_export_lookup,windows_guest_export_aliases,macos_output,macos_empty_tls,macos_tls_overlapand theguest_*tests. 55 further tests whose fixtures carryDT_OS_SYMTABSZand so reach the export loop passed in 42.1 s (-j 3):strict_nid_filter,gnu_hash_analysis,init_array_roots,jmprel_table_bounds,needed_libraries,none_relocations,null_symbol_relocations,optional_plt,sce_code_extent,sce_module_code_extent,sce_relro,string_table_bounds,unused_filter_indirect,windows_tls_protected_entries,linux_named_imports,linux_trace_imports,weak_imports,windows_import_modules,windows_named_imports,windows_trace_imports, the twowindows_kernel_variant_*and the 33tls_function_coverage_*tests.main(7b41552, which includes feat(relinker): trace function imports on macOS #9408 and fix(relinker): reject out-of-range executable TLS symbols #11058) into the branch without conflicts (b93be68; the earlier merges are 4b1a9a3 in a9d053f, 5b5d24c in 12ad27b and 204c674 in de709f9);tools/check_main_sync.py --base upstream/mainreported 0 behind and a clean merge at 7b41552, and the later merges onmainup to 035ac96 touch no relinker file. On b93be68,ctest -R 'executable_export|macos_executable_exports|linux_executable_exports|guest_symbol|weak_imports|macos_trace_imports|trace_imports|executable_tls_relocations' -j 6: 12 tests passed:executable_export_attributes(2.8 s),executable_export_bounds,macos_executable_exports,linux_executable_exports,guest_symbol_names,weak_imports,windows_guest_weak_imports,macos_guest_weak_imports,macos_trace_imports(added by feat(relinker): trace function imports on macOS #9408),linux_trace_imports,windows_trace_imports,executable_tls_relocations(extended by fix(relinker): reject out-of-range executable TLS symbols #11058).ctest --test-dir build-relinker -j 6: 310 tests, 307 passed,long_pathsskipped; failures known on this machine onmainas well:select_tests(Windows symlink fixture) andpatch_advisor_unit(path with spaces, which open test(tools): compare quoted and resolved paths in the patch advisor test #10667 fixes); both failed again alone.python tools/check_conventions.py --base upstream/mainwith this title and description passed on b93be68.Checklist
main; no other open PR implements the same functionsNotImplemented_nid_no_patch); silent stubs are listed under Silent stubs in their library's technical debt file.mdfiles or images added to the repository (attach them to this PR)