-
-
Notifications
You must be signed in to change notification settings - Fork 486
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Allocate PHT & SHT at the end of the *.elf file #544
base: master
Are you sure you want to change the base?
Conversation
tests/no-rpath-pie-powerpc.sh
Outdated
@@ -37,9 +37,9 @@ if [ "$(echo "$readelfData" | grep -c "PHDR")" != 1 ]; then | |||
fi | |||
|
|||
virtAddr=$(echo "$readelfData" | grep "PHDR" | awk '{print $3}') | |||
if [ "$virtAddr" != "0x00000034" ]; then | |||
if [ "$virtAddr" != "0x01040000" ]; then |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Previously PHDR was always kept right after EHDR, while now it's allocated at the end of the file.
@@ -34,7 +34,7 @@ load_segments_after=$(${READELF} -W -l libbar.so | grep -c LOAD) | |||
# To be even more strict, check that we don't add too many extra LOAD entries | |||
############################################################################### | |||
echo "Segments before: ${load_segments_before} and after: ${load_segments_after}" | |||
if [ "${load_segments_after}" -gt $((load_segments_before + 2)) ] | |||
if [ "${load_segments_after}" -gt $((load_segments_before + 3)) ] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's because now we might sometimes allocate a brand-new LOAD segment just for the PHDR's sake.
Because PHDR is supposed to have been covered by such section before, in | ||
here we assume that we don't have to create any new section, but rather | ||
extend the existing one. */ | ||
for (auto& phdr : phdrs) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This logic used to be run only if neededSpace <= startOffset
, under the assumption that otherwise (when neededSpace > startOffset
), we call shiftFile()
, which will automatically create appropriate PT_LOAD
segment:
Line 557 in 7c2f768
/* Add a segment that maps the new program/section headers and |
But that was done under the assumption that shiftFile()
's startOffset
will land inside a loadable segment that happens to contain PHDR
, which is not necessarily true! Some binaries have a dedicated small LOAD
segment just for PHDR
, making shiftFile()
then pick the next available LOAD
segment.
I believe this is the same case this merge request tried to cover (or at least both make pcloud
a valid binary):
I've also checked it on the reproduction from #264 (comment) - I don't have aarch64-linux at hand, though, so I've just patched the file and ran eu-elflint
(which now doesn't complain about the string sections there).
Also, this is now tested as a part of short-first-segment
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, in a hindsight, now I'm thinking whether this approach can't cause some segments to overlap each other? (maybe that's why tests on a few other architectures fail, as I now see)
Btw, I've got another merge request in the works, one that fixes #75 and hopefully will be able to handle #520 as well, but I've ultimately decided to move it out of this pull request, since it's technically a separate changeset (and less important, at least from my point of view) -- I'll prepare it in the upcoming weeks. |
Another issue is that Definitely seems like a |
Closes #531.
Closes #482.
Closes #244.
Upstream-wise, affects NixOS/nixpkgs#226339.
(didn't want to write
close
so that merging this merge request doesn't close that issue at once)Abstract
Patching an *.elf file might require extending its program header table, which can then cause it to run out of its originally allocated space (both in terms of file offset and virtual memory).
Currently patchelf solves this problem by finding which sections would overlap PHT and then by moving them to the end of *.elf file:
patchelf/src/patchelf.cc
Line 832 in 7c2f768
As compared to similar logic for binaries:
patchelf/src/patchelf.cc
Line 964 in 7c2f768
... the logic for libraries is missing a crucial check: it doesn't take into account whether that particular section can be shuffled around - in particular, sections with
SHT_PROGBITS
can't!As luck would have it,
libnode.so
(e.g. shipped together withpcloud
) does have.rodata
(a section withSHT_PROGBITS
active) right at the beginning of the file:... which patchelf happily moves around, breaking RIP-relative addressing in the assembly (which, after patching, tries to access the
ZZZZ
-ed memory).This commit fixes the issue by changing the logic from:
... to, perhaps a bit more wasteful in terms of storage:
As far as I've checked, the reason why PHT was so strictly kept at the beginning was an old Linux bug:
patchelf/src/patchelf.cc
Line 857 in 7c2f768
patchelf/BUGS
Line 1 in 7c2f768
... which is not present anymore (not sure when precisely was it fixed, though - the original entry in the BUGS file is dated 2005).
Seizing the day, I'm also including another fix (for binaries), so that merging this pull request will solve all pcloud-related problems.