Add DT_NEEDED dependency injection#49
Merged
Merged
Conversation
There was no way to add a dependency to an existing dynamically-linked image. Growing .dynamic and .dynstr in place is not viable: it would shift every later section's file offset while its virtual address stays fixed, breaking the loader's vaddr-to-offset mapping and every stored address reference. Adds ElfFile.AddNeededLibrary, which never changes an existing section's byte offset. It relocates the .dynamic and .dynstr sections to end-of-file (backfilling their old offsets with equal-size padding so no other section moves), maps them with a PT_LOAD built from a spare PT_NOTE program header, and repoints PT_DYNAMIC, DT_STRTAB/DT_STRSZ and the _DYNAMIC symbol at the new location. Section and segment stay consistent, so a re-read sees the injected dependency.
Covers ElfFile.AddNeededLibrary in-process: injecting into a real shared object repurposes a PT_NOTE into a PT_LOAD and moves PT_DYNAMIC, and resolving DT_NEEDED the way the loader does (PT_DYNAMIC to the dynamic array, then DT_STRTAB) shows the existing dependencies preserved and the injected one resolvable, with the section view agreeing. Also checks that a non-dynamic object file is rejected.
Adds ElfFile.AddNeededLibrary to the ELF feature list.
Owner
|
Thanks! |
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.
Builds on #48. This PR is stacked on it, so the diff to look at is just the injection commits on top.
Adds
ElfFile.AddNeededLibrary(name), which injects aDT_NEEDEDdependency into an existing dynamically-linked image so the loader loads that library at startup. It's essentiallypatchelf --add-neededas an in-process .NET API.What's new
ElfFile.AddNeededLibrary(string libraryName). It's address-preserving: no existing section changes byte offset, so existing symbols, relocations and code stay valid. The mechanism is the same idea patchelf uses:.dynstrwith the new name and adds aDT_NEEDEDentry..dynamicand.dynstrsections to end-of-file, backfilling the space they vacated with equal-size padding so every other section keeps its offset.PT_LOADbuilt from a sparePT_NOTEprogram header, so the program-header table doesn't grow.PT_DYNAMIC,DT_STRTAB/DT_STRSZ, and the_DYNAMICsymbol at the new location.Because the sections move (not just the segment), section and segment stay consistent:
Both
readelf -dand a LibObjectFile re-read see the injected dependency. You can use that to check whether a binary is already patched, so re-running the injection is a no-op.Trade-offs / limits (documented and enforced with diagnostics)
PT_NOTEto repurpose and aPT_DYNAMIC(a dynamically-linked image). If either ismissing it throws rather than producing a broken file.
PT_NOTE's contents (e.g. the build-id note) drop from the load image..dynamic/.dynstrbytes stay in the file as padding. This is the same trade-off patchelf makes.Tests
PT_NOTEinto aPT_LOAD, movesPT_DYNAMIC, and resolvingDT_NEEDEDthe way the loader does (PT_DYNAMIC->DT_STRTAB) shows existing dependencies preserved and the injected one resolvable, and the section view agrees with it. Plus rejection of a non-dynamic file.dlopen'd shared object both load and run with the injected library's constructor firing, andeu-elflintseem happy versus the original binary.