Otherwise, patchelf segfaults when it encounters DT_NEEDED in the read
garbage. Corresponding backtrace is:
#0 0x00007ffff7c275f7 in __strlen_avx2 () from /nix/store/cvr0kjg2q7z2wwhjblx6c73rv422k8cm-glibc-2.33-47/lib/libc.so.6
#1 0x00007ffff7f2d448 in std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(char const*, std::allocator<char> const&) () from /nix/store/lg104nh0szci8slz5z6494m457jm5y3p-gcc-10.3.0-lib/lib/libstdc++.so.6
#2 0x000000000040fe0f in ElfFile<Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr, unsigned long, unsigned long, Elf64_Dyn, Elf64_Sym, Elf64_Verneed, unsigned short>::modifyRPath (this=0x7fffffffbaa0,
op=ElfFile<Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr, unsigned long, unsigned long, Elf64_Dyn, Elf64_Sym, Elf64_Verneed, unsigned short>::rpPrint, allowedRpathPrefixes=std::vector of length 0, capacity 0, newRPath="") at patchelf.cc:1351
#3 0x00000000004061c3 in patchElf2<ElfFile<Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr, unsigned long, unsigned long, Elf64_Dyn, Elf64_Sym, Elf64_Verneed, unsigned short> > (elfFile=..., fileContents=std::shared_ptr<std::vector<unsigned char, std::allocator<unsigned char> >> (use count 3, weak count 0) = {...},
fileName="libsystemd.debug") at patchelf.cc:1805
#4 0x0000000000404774 in patchElf () at patchelf.cc:1848
#5 0x000000000040551c in mainWrapped (argc=3, argv=0x7fffffffc148) at patchelf.cc:2003
#6 0x0000000000405913 in main (argc=3, argv=0x7fffffffc148) at patchelf.cc:2011
NOBIT sections are included in the section headers table but occupy no
actual space in the file. .dynamic sections of this types are created,
for example, by `strip --only-keep-debug`.
I'm not sure whether calling error() would be more appropriate than
ignoring this situation with debug/return. I chose ignoring it,
because error() caused autoPatchelfHook to fail with my package. Also
the rest of modifyRPath method simply calls debug/return in similar
situations.
When loading the executable on MIPS, the dynamic loader looks for MIPS
ABI flags using PT_MIPS_ABIFLAGS header. The flags themselves are stored
in the .MIPS.abiflags section, so the header must be updated when the
section is moved.
Here we also import PT_MIPS_ABIFLAGS definition from glibc commit
0bd956720c457ff054325b48f26ac7c91cb060e8.
Closes: #82
Signed-off-by: Ivan A. Melnikov <iv@altlinux.org>
`patchelf --set-rpath` corrupted executables on mips32el: the dynamic
liker crushed with Segmentation fault when loading any executable with
RPATH added that way.
The problem was around the MIPS-specific mechanism of setting up the
debug map pointer. When DT_MIPS_RLD_MAP_REL entry in the dynamic section
is present, it holds the relative address of __RLD_MAP -- an offset
relative to this dynamic section entry. Dynamic linker puts the
pointer to the `r_debug` structure there.
When patchelf updates the executable RPATH, it moves the .dynamic
section both in the binary and in memory, while __RLD_MAP is not moved
in memory, since it belongs to special .rld_map section that has type
PROGBITS. So, the offset stored in DT_MIPS_RLD_MAP_REL entry is not
valid anymore and should be updated.
This commit adds the necessary update.
In the corner case when DT_MIPS_RLD_MAP_REL is present, but
.rld_map section is not, the dynamic loader writes the debug
pointer to some arbitrary bytes in memory. To avoid crushes
on otherwise "working" binaries, we set offset to zero
so that the dynamic loader would just overwrite the dynamic
section.
Here we also import DT_MIPS_RLD_MAP_REL definition in elf.h form
glibc commit a2057c984e4314c3740f04cf54e36c824e4c8f32.
Refs: #82
Signed-off-by: Ivan A. Melnikov <iv@altlinux.org>
Add a testcase for the following reported alignment issue with contiguous note
sections (#275):
"""
If a binary has multiple SHT_NOTE sections and corresponding PT_NOTE
headers, we can see the error:
patchelf: cannot normalize PT_NOTE segment: non-contiguous SHT_NOTE sections
if the SHT_NOTE sections aren't sized to end on aligned boundaries. An example
would be a binary with:
[ 2] .note.ABI-tag NOTE 00000000000002f4 000002f4
0000000000000020 0000000000000000 A 0 0 4
[ 3] .note.gnu.propert NOTE 0000000000000318 00000318
0000000000000030 0000000000000000 A 0 0 8
[ 4] .note.gnu.build-i NOTE 0000000000000348 00000348
0000000000000024 0000000000000000 A 0 0 4
NOTE 0x0000000000000318 0x0000000000000318 0x0000000000000318
0x0000000000000030 0x0000000000000030 R 0x8
NOTE 0x00000000000002f4 0x00000000000002f4 0x00000000000002f4
0x0000000000000078 0x0000000000000074 R 0x4
since the PT_NOTE section at 2f4 covers [2] and [3] but the code
calclates curr_off should be 314, not the 318 in the binary. This
is an alignment issue.
"""
Signed-off-by: Ovidiu Panait <ovidiu.panait@windriver.com>
When running "--add-needed" subcommand on a hello world binary, the
following assertion is triggered:
"""
$ echo "int main() {}" | gcc -xc -o test -
$ patchelf --add-needed foo.so --output /dev/null test
patching ELF file 'scratch/plain-needed/main'
patchelf: patchelf.cc:1167: void setSubstr(std::string&, unsigned int, const string&): Assertion `pos + t.size() <= s.size()' failed.
Aborted (core dumped)
"""
This is due to the fact that .dynstr section is resized incorrectly:
"""
unsigned int length = std::count_if(libs.begin(), libs.end(),
[](const std::string & lib) { return lib.size() + 1; });
"""
std::count_if() will return the number of strings in std::set<std::string> libs
(e.g. 1 in the foo.so example). However, in order to properly resize the
.dynstr section, subsequent code expects the size (in bytes) of all the strings
that are to be appended:
"""
std::string & newDynStr = replaceSection(".dynstr",
rdi(shdrDynStr.sh_size) + length + 1);
"""
To fix this, iterate over "libs" and compute the length of all the strings that
need to be added to the .dynstr section.
Fixes#291.
Fixes: fce77b7cd8 ("replace for loop with any_of")
Signed-off-by: Ovidiu Panait <ovidiu.panait@windriver.com>
Add a testcase for the following reported alignment issue with contiguous note
sections (#275):
"""
If a binary has multiple SHT_NOTE sections and corresponding PT_NOTE
headers, we can see the error:
patchelf: cannot normalize PT_NOTE segment: non-contiguous SHT_NOTE sections
if the SHT_NOTE sections aren't sized to end on aligned boundaries. An example
would be a binary with:
[ 2] .note.ABI-tag NOTE 00000000000002f4 000002f4
0000000000000020 0000000000000000 A 0 0 4
[ 3] .note.gnu.propert NOTE 0000000000000318 00000318
0000000000000030 0000000000000000 A 0 0 8
[ 4] .note.gnu.build-i NOTE 0000000000000348 00000348
0000000000000024 0000000000000000 A 0 0 4
NOTE 0x0000000000000318 0x0000000000000318 0x0000000000000318
0x0000000000000030 0x0000000000000030 R 0x8
NOTE 0x00000000000002f4 0x00000000000002f4 0x00000000000002f4
0x0000000000000078 0x0000000000000074 R 0x4
since the PT_NOTE section at 2f4 covers [2] and [3] but the code
calclates curr_off should be 314, not the 318 in the binary. This
is an alignment issue.
"""
Signed-off-by: Ovidiu Panait <ovidiu.panait@windriver.com>
Currently, patchelf creats a broken PPC binary in
tests/no-rpath-pie-powerpc.sh:
$ readelf -l scratch/no-rpath-pie-powerpc/no-rpath
[...]
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
PHDR 0x000034 0x34000000 0x34000000 0x00120 0x00120 R 0x4
[...]
That happens because 4efbce41 lost endianness conversion
for rewriteSectionsLibrary. This commit puts it back.
Fixes: 4efbce410d
Without '&', the code updates temporary and thus
does essentially nothing. But updating PT_PHDR
segment is required for many architectures.
Fixes: dd4d2af8db
If a binary has multiple SHT_NOTE sections and corresponding PT_NOTE
headers, we can see the error:
patchelf: cannot normalize PT_NOTE segment: non-contiguous SHT_NOTE sections
if the SHT_NOTE sections aren't sized to end on aligned boundaries. An example
would be a binary with:
[ 2] .note.ABI-tag NOTE 00000000000002f4 000002f4
0000000000000020 0000000000000000 A 0 0 4
[ 3] .note.gnu.propert NOTE 0000000000000318 00000318
0000000000000030 0000000000000000 A 0 0 8
[ 4] .note.gnu.build-i NOTE 0000000000000348 00000348
0000000000000024 0000000000000000 A 0 0 4
NOTE 0x0000000000000318 0x0000000000000318 0x0000000000000318
0x0000000000000030 0x0000000000000030 R 0x8
NOTE 0x00000000000002f4 0x00000000000002f4 0x00000000000002f4
0x0000000000000078 0x0000000000000074 R 0x4
since the PT_NOTE section at 2f4 covers [2] and [3] but the code
calclates curr_off should be 314, not the 318 in the binary. This
is an alignment issue.
To fix this, we need to round curr_off to the next section alignment.
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
../../patchelf/src/patchelf.cc:835:19: warning: comparison of integer expressions of different signedness: 'long long unsigned int' and 'off_t' {aka 'long long int'} [-Wsign-compare]
835 | assert(curOff == startOffset + neededSpace);
| ~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~
The original code which worked was size_t(A + B * C). size_t(A + B)
breaks it. A + size_t(B * C) is correct.
Signed-off-by: Rosen Penev <rosenp@gmail.com>