Commit Graph

216 Commits

Author SHA1 Message Date
Michal Sojka
64fe89b6b2 Don't try to parse .dynamic section of type NOBITS
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.
2021-08-23 20:57:47 +02:00
Jörg Thalheim
bf62fda4ec fix use-after-free in normalizeNoteSegments 2021-08-21 09:43:23 +02:00
Jörg Thalheim
83864998bd Merge pull request #300 from NixOS/eintr
handle EINTR correctly on write
2021-08-19 14:06:01 +01:00
Jörg Thalheim
3fc63c945c use memcpy instead of strcpy to set rpath
Since we already no the size, this is faster.
2021-08-18 08:29:14 +02:00
Jörg Thalheim
51626341b6 correct EINTR handling in writeFile 2021-08-18 08:16:49 +02:00
Jörg Thalheim
10cd631cce fixup PACKAGE_STRING macro
it was introduced in b9dcf5b705
but contained a stray \
2021-08-18 08:16:26 +02:00
Ivan A. Melnikov
bf73d6ea39 Adjust PT_MIPS_ABIFLAGS segment if present
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>
2021-08-11 17:50:04 +04:00
Ivan A. Melnikov
b240bb8dcf Adjust DT_MIPS_RLD_MAP_REL dynamic section entry if present
`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>
2021-08-11 17:49:41 +04:00
Jörg Thalheim
b9dcf5b705 define default PACKAGE_STRING
This allows to build patchelf without build system.
Fixes https://github.com/NixOS/patchelf/pull/114 and https://github.com/NixOS/patchelf/issues/102
2021-08-10 20:48:56 +02:00
Jörg Thalheim
57fe1d3835 fix binaries without .gnu.hash section 2021-08-10 07:54:50 +02:00
Domen Kožar
eed0a903c5 Merge branch 'master' into multiple 2021-08-05 17:59:01 +02:00
Domen Kožar
dab44118d7 Merge pull request #246 from xavierabellan/add-rpath
Added option --add-rpath
2021-08-05 12:10:59 +02:00
Domen Kožar
4ee62cbd52 Merge pull request #269 from telent/endianness-fix-for-shrink-rpath
convert endian when checking library machine type
2021-08-05 12:03:48 +02:00
Domen Kožar
add92c1fe7 Merge pull request #235 from emlix/cleanups
minor improvements
2021-08-04 15:45:27 +02:00
Domen Kožar
9592fdf3a1 Merge pull request #275 from rpurdie/master
patchelf: Fix alignment issues with contiguous note sections
2021-08-04 15:43:07 +02:00
Ovidiu Panait
f533f7b898 addNeeded: fix assertion triggered due to bad .dynstr section resize
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>
2021-07-24 19:25:16 +03:00
Ivan A. Melnikov
83eab25c30 rewriteSectionsLibrary: Fix endianness issue
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
2021-06-21 12:29:30 +04:00
Satadru Pramanik
f276b58ebb Change to 'for (auto & phdr : phdrs) { .' as used elsewhere 2021-05-27 23:06:58 -04:00
Satadru Pramanik
4efbce410d merge from PR243 2021-05-20 16:52:21 -04:00
Richard Purdie
2d0e0b9218 patchelf: Fix alignment issues with contiguous note sections
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>
2021-05-02 13:06:31 +01:00
MatrixLing
ff6f21fad5 fixed phdr bug 2021-04-12 09:25:35 +08:00
Daniel Barlow
013ce840ab convert endian when checking library machine type 2021-03-31 22:27:40 +01:00
Rolf Eike Beer
acb4665c17 avoid needless copies of std::string 2021-03-16 08:28:10 +01:00
Rolf Eike Beer
554dec3668 do not add new string entries when changing libraries to themself 2021-03-16 08:26:28 +01:00
Rolf Eike Beer
4967cdcd0e fix -Wshadow warnings 2021-03-16 08:26:27 +01:00
Rolf Eike Beer
0fcf278953 silence compiler warning because of different signedness
../../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);
      |            ~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~
2021-03-16 08:24:20 +01:00
Rolf Eike Beer
40640a9c11 add new SHF_* flags from binutils 2021-03-16 08:24:20 +01:00
Rolf Eike Beer
a935c61e74 only one section name can match 2021-03-16 08:23:32 +01:00
Rolf Eike Beer
d628ab9378 avoid needless memory allocation when replacing sections 2021-03-16 08:23:09 +01:00
Rosen Penev
1af4453428 fix wrong cast
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>
2021-02-25 15:01:21 -08:00
Eelco Dolstra
0ad9548c02 Style fixes 2021-02-15 13:12:02 +01:00
Rosen Penev
dd4d2af8db manual for loop conversions
Signed-off-by: Rosen Penev <rosenp@gmail.com>
2021-02-14 18:14:26 -08:00
Rosen Penev
b399885dd0 clang-tidy: use auto
Found with modernize-use-auto

Signed-off-by: Rosen Penev <rosenp@gmail.com>
2021-02-14 17:50:10 -08:00
Rosen Penev
3f91ab276b clang-tidy: replace typedef with using
Found with modernize-use-using

Signed-off-by: Rosen Penev <rosenp@gmail.com>
2021-02-14 17:48:44 -08:00
Rosen Penev
706eb6b1e7 clang-tidy: sort includes alphabetically
Found with llvm-include-order

Signed-off-by: Rosen Penev <rosenp@gmail.com>
2021-02-14 17:48:26 -08:00
Rosen Penev
24e6dd7a5f clang-tidy: use C++ casts
Found with google-readability-casting

Signed-off-by: Rosen Penev <rosenp@gmail.com>
2021-02-14 17:48:26 -08:00
Rosen Penev
85393d3ecc clang-tidy: use explicit constructors
Found with google-explicit-constructor

Signed-off-by: Rosen Penev <rosenp@gmail.com>
2021-02-14 17:47:57 -08:00
Rosen Penev
ddd28fe319 clang-tidy: do not use else after return
Found with readability-else-after-return

Signed-off-by: Rosen Penev <rosenp@gmail.com>
2021-02-14 17:47:45 -08:00
Rosen Penev
cedf284111 clang-tidy: fix bad cast
Found with bugprone-misplaced-widening-cast

Signed-off-by: Rosen Penev <rosenp@gmail.com>
2021-02-14 17:47:43 -08:00
Rosen Penev
7695c62652 clang-tidy: remove pointless string init
Found with readability-redundant-string-init

Signed-off-by: Rosen Penev <rosenp@gmail.com>
2021-02-14 17:47:41 -08:00
Rosen Penev
04052810f0 clang-tidy: use empty()
Found with readability-container-size-empty

Signed-off-by: Rosen Penev <rosenp@gmail.com>
2021-02-14 17:47:36 -08:00
Rosen Penev
900c673c27 clang-tidy: reference conversions
Found with performance-unnecessary-value-param

Signed-off-by: Rosen Penev <rosenp@gmail.com>
2021-02-14 17:47:36 -08:00
Rosen Penev
e17744d966 clang-tidy: avoid copying loop variable
Found with performance-for-range-copy

Signed-off-by: Rosen Penev <rosenp@gmail.com>
2021-02-14 17:47:17 -08:00
Rosen Penev
fce77b7cd8 replace for loop with any_of
Signed-off-by: Rosen Penev <rosenp@gmail.com>
2021-02-14 17:47:05 -08:00
Rosen Penev
60affdea0c clang-tidy: use nullptr
Found with modernize-use-nullptr

Signed-off-by: Rosen Penev <rosenp@gmail.com>
2021-02-14 17:46:49 -08:00
Xavier Abellan Ecija
8703e4611e Added option conflict between --set-rpath and --add-rpath 2020-11-26 07:12:11 +00:00
Eelco Dolstra
81a48fd138 Merge pull request #230 from rmNULL/fix-wrong-unsupported-overlap
[BUG FIX] false alarm for non overlapping sections
2020-11-19 11:08:08 +01:00
Julian Stecklina
883fdf99c5 Gracefully handle ELF files with out-of-bounds shdr offsets
This is similar to the earlier fix for phdr offsets, but the fuzzer
didn't find this.
2020-11-15 16:46:53 +01:00
Julian Stecklina
d148bae6c1 Fix endian issue when creating sectionsByOldIndex
sectionsByOldIndex was resized to hdr->e_shnum instead of
rdi(hdr->e_shnum). This omitted the endianness conversion and probably
only worked by accident, because the 16-bit LE->BE conversion results
in integers that are larger as long as there no more than 255 section
headers.

This would be a good usecase for std::transform, but I'm unsure
whether we want to bump requirements to build patchelf to C++ 2017.
2020-11-15 16:46:53 +01:00
Julian Stecklina
52e9dd5900 Gracefully handle ELF files with out-of-bounds phdr offsets 2020-11-15 16:46:53 +01:00