Coder Social home page Coder Social logo

nixos / patchelf Goto Github PK

View Code? Open in Web Editor NEW
3.3K 76.0 462.0 1.15 MB

A small utility to modify the dynamic linker and RPATH of ELF executables

License: GNU General Public License v3.0

Shell 10.65% C 50.20% C++ 28.31% Nix 1.37% Makefile 1.82% M4 5.93% Roff 1.45% Assembly 0.26%

patchelf's Introduction

PatchELF is a simple utility for modifying existing ELF executables and libraries. In particular, it can do the following:

  • Change the dynamic loader ("ELF interpreter") of executables:

    $ patchelf --set-interpreter /lib/my-ld-linux.so.2 my-program
  • Change the RPATH of executables and libraries:

    $ patchelf --set-rpath /opt/my-libs/lib:/other-libs my-program
  • Shrink the RPATH of executables and libraries:

    $ patchelf --shrink-rpath my-program

    This removes from the RPATH all directories that do not contain a library referenced by DT_NEEDED fields of the executable or library. For instance, if an executable references one library libfoo.so, has an RPATH /lib:/usr/lib:/foo/lib, and libfoo.so can only be found in /foo/lib, then the new RPATH will be /foo/lib.

    In addition, the --allowed-rpath-prefixes option can be used for further rpath tuning. For instance, if an executable has an RPATH /tmp/build-foo/.libs:/foo/lib, it is probably desirable to keep the /foo/lib reference instead of the /tmp entry. To accomplish that, use:

    $ patchelf --shrink-rpath --allowed-rpath-prefixes /usr/lib:/foo/lib my-program
  • Remove declared dependencies on dynamic libraries (DT_NEEDED entries):

    $ patchelf --remove-needed libfoo.so.1 my-program

    This option can be given multiple times.

  • Add a declared dependency on a dynamic library (DT_NEEDED):

    $ patchelf --add-needed libfoo.so.1 my-program

    This option can be give multiple times.

  • Replace a declared dependency on a dynamic library with another one (DT_NEEDED):

    $ patchelf --replace-needed liboriginal.so.1 libreplacement.so.1 my-program

    This option can be give multiple times.

  • Change SONAME of a dynamic library:

    $ patchelf --set-soname libnewname.so.3.4.5 path/to/libmylibrary.so.1.2.3

Compiling and Testing

Via Autotools

./bootstrap.sh
./configure
make
make check
sudo make install

Via Nix

You can build with Nix in several ways.

  1. Building via nix build will produce the result in ./result/bin/patchelf. If you would like to build patchelf with musl try nix build .#patchelf-musl

  2. You can launch a development environment with nix develop and follow the autotools steps above. If you would like to develop with musl try nix develop .#musl

Author

Copyright 2004-2019 Eelco Dolstra [email protected].

License

This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/.

patchelf's People

Contributors

abathur avatar am813nt avatar andrewla avatar blitz avatar bo98 avatar bors[bot] avatar brenoguim avatar cgzones avatar darealshinji avatar dependabot[bot] avatar derdakon avatar dezgeg avatar dmsck avatar domenkozar avatar edolstra avatar fsateler avatar fzakaria avatar heirecka avatar iv-m avatar klemensn avatar mayeut avatar mic92 avatar neheb avatar njsmith avatar opanait-wr avatar rmnull avatar rpurdie avatar satmandu avatar vdanjean avatar xavierabellan avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

patchelf's Issues

patchelf's bootstrap doesn't produce a runnable configure script in Mac OS

At the current master branch branch, the bootstrap is not producing working configure script in Mac OS X 10.9.5.

A pull request has been open to treat this issue at #51 written by Felix Fietkau for the OpenWrt project. It would be great to have this patch upstream so everyone can benefit from it.

Log of errors:

$ ./bootstrap.sh
autoreconf: Entering directory `.'
autoreconf: configure.ac: not using Gettext
autoreconf: running: /opt/local/bin/aclocal --force --warnings=all
configure.ac:1: warning: AC_INIT: not a literal: -n 0.8
autoreconf: configure.ac: tracing
configure.ac:1: warning: AC_INIT: not a literal: -n 0.8
autoreconf: configure.ac: creating directory build-aux
autoreconf: configure.ac: not using Libtool
autoreconf: running: /opt/local/bin/autoconf --force --warnings=all
configure.ac:1: warning: AC_INIT: not a literal: -n 0.8
autoreconf: configure.ac: not using Autoheader
autoreconf: running: /opt/local/bin/automake --add-missing --copy --force-missing --warnings=all
configure.ac:1: warning: AC_INIT: not a literal: -n 0.8
configure.ac:6: installing 'build-aux/compile'
configure.ac:4: installing 'build-aux/install-sh'
configure.ac:4: installing 'build-aux/missing'
src/Makefile.am: installing 'build-aux/depcomp'
parallel-tests: installing 'build-aux/test-driver'
autoreconf: Leaving directory `.'
$ ./configure
./configure: line 4: .: filename argument required
.: usage: . filename [arguments]

patchelf breaks hardlinks

Hard links are used extensively by gcc and git. See the example below.

Experiment

$ cc hello.c -o hello
$ ln hello hello2
$ ls -il hello hello2
10099869 -rwxr-xr-x 2 sjackman assembly 7130 Aug 22 13:54 hello
10099869 -rwxr-xr-x 2 sjackman assembly 7130 Aug 22 13:54 hello2
$ patchelf --set-rpath /foo hello

Observed

$ ls -il hello hello2
10099870 -rwxr-xr-x 1 sjackman assembly 11226 Aug 22 13:55 hello
10099869 -rwxr-xr-x 1 sjackman assembly  7130 Aug 22 13:54 hello2

Expected

$ ls -il hello hello2
10099869 -rwxr-xr-x 2 sjackman assembly 11226 Aug 22 13:55 hello
10099869 -rwxr-xr-x 2 sjackman assembly 11226 Aug 22 13:55 hello2

Tests fail on PIC executables: maximum file size exceeded

Fedora Linux distribution started to build all executables as position-independent code.

patchelf fails selftest on such executables (see the 'maximum file size exceeded'):

$  ../src/patchelf --set-interpreter /oops scratch/set-interpreter-short/simple
warning: working around a Linux kernel bug by creating a hole of 18870272 bytes in ‘scratch/set-interpreter-short/simple’
maximum file size exceeded

The reproducer is to call configure as:

$ ./configure CFLAGS='-O0 -fPIE' LDFLAGS='-specs=/usr/lib/rpm/redhat/redhat-hardened-ld' CXXFLAGS='-O0 -fPIE'

The /usr/lib/rpm/redhat/redhat-hardened-ld contains:

*self_spec:
+ %{!shared:%{!r:-pie}}

*link:
+ -z now

Alternatively you can replace LDFLAGS with '-z now' and add '-pie' to LDFLAGS_local variable in tests/Makefile.am (and run autoreconf before ./configure).

Complete test suite results are:

PASS: plain-fail.sh
PASS: plain-run.sh
PASS: shrink-rpath.sh
FAIL: set-interpreter-short.sh
FAIL: set-interpreter-long.sh
FAIL: set-rpath.sh
PASS: no-rpath.sh
FAIL: big-dynstr.sh
FAIL: set-rpath-library.sh
PASS: soname.sh
PASS: no-rpath-amd64.sh
PASS: no-rpath-armel.sh
PASS: no-rpath-armhf.sh
PASS: no-rpath-hurd-i386.sh
PASS: no-rpath-i386.sh
XFAIL: no-rpath-ia64.sh
PASS: no-rpath-kfreebsd-amd64.sh
PASS: no-rpath-kfreebsd-i386.sh
PASS: no-rpath-mips.sh
PASS: no-rpath-mipsel.sh
PASS: no-rpath-powerpc.sh
PASS: no-rpath-s390.sh
PASS: no-rpath-sh4.sh
PASS: no-rpath-sparc.sh

Malformed input will cause invalid memory read / segfault

This file will generate a segfault / invalid memory read with patchelf:
https://crashes.fuzzing-project.org/patchelf-0.8-invalid-memory-read-Elf64_Phdr

The error messages I get from debugging tools aren't really clear, it seems it is causing some read to some wrong memory that is neither part of the stack or the heap.

Here's the address sanitizer stack trace:

==5570==ERROR: AddressSanitizer: unknown-crash on address 0x8030afdac1201830 at pc 0x00000049ed24 bp 0x7fff61a59e10 sp 0x7fff61a595c0
READ of size 56 at 0x8030afdac1201830 thread T0
    #0 0x49ed23 in __asan_memcpy (/tmp/patchelf-0.8/src/patchelf+0x49ed23)
    #1 0x521b7b in __gnu_cxx::new_allocator<Elf64_Phdr>::construct(Elf64_Phdr*, Elf64_Phdr const&) /usr/lib/gcc/x86_64-pc-linux-gnu/5.2.0/include/g++-v5/ext/new_allocator.h:130:28
    #2 0x521b7b in void __gnu_cxx::__alloc_traits<std::allocator<Elf64_Phdr> >::construct<Elf64_Phdr>(std::allocator<Elf64_Phdr>&, Elf64_Phdr*, Elf64_Phdr const&) /usr/lib/gcc/x86_64-pc-linux-gnu/5.2.0/include/g++-v5/ext/alloc_traits.h:189
    #3 0x521b7b in std::vector<Elf64_Phdr, std::allocator<Elf64_Phdr> >::_M_insert_aux(__gnu_cxx::__normal_iterator<Elf64_Phdr*, std::vector<Elf64_Phdr, std::allocator<Elf64_Phdr> > >, Elf64_Phdr const&) /usr/lib/gcc/x86_64-pc-linux-gnu/5.2.0/include/g++-v5/bits/vector.tcc:361
    #4 0x517d8f in std::vector<Elf64_Phdr, std::allocator<Elf64_Phdr> >::push_back(Elf64_Phdr const&) /usr/lib/gcc/x86_64-pc-linux-gnu/5.2.0/include/g++-v5/bits/stl_vector.h:925:4
    #5 0x517d8f in ElfFile<Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr, unsigned long, unsigned long, Elf64_Dyn, Elf64_Sym>::parse() /tmp/patchelf-0.8/src/patchelf.cc:281
    #6 0x4e5ab9 in void patchElf2<ElfFile<Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr, unsigned long, unsigned long, Elf64_Dyn, Elf64_Sym> >(ElfFile<Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr, unsigned long, unsigned long, Elf64_Dyn, Elf64_Sym>&, unsigned int) /tmp/patchelf-0.8/src/patchelf.cc:1105:5
    #7 0x4e5ab9 in patchElf() /tmp/patchelf-0.8/src/patchelf.cc:1156
    #8 0x4e5ab9 in main /tmp/patchelf-0.8/src/patchelf.cc:1245
    #9 0x7faa93de77af in __libc_start_main /var/tmp/portage/sys-libs/glibc-2.21-r1/work/glibc-2.21/csu/libc-start.c:289
    #10 0x4190f8 in _start (/tmp/patchelf-0.8/src/patchelf+0x4190f8)

==5570==AddressSanitizer CHECK failed: /var/tmp/portage/sys-devel/llvm-3.7.0/work/llvm-3.7.0.src/projects/compiler-rt/lib/asan/asan_report.cc:347 "((0 && "Address is not in memory and not in shadow?")) != (0)" (0x0, 0x0)
    #0 0x4bbf2d in __asan::AsanCheckFailed(char const*, int, char const*, unsigned long long, unsigned long long) (/tmp/patchelf-0.8/src/patchelf+0x4bbf2d)
    #1 0x4c29c3 in __sanitizer::CheckFailed(char const*, int, char const*, unsigned long long, unsigned long long) (/tmp/patchelf-0.8/src/patchelf+0x4c29c3)
    #2 0x4b7f66 in __asan::DescribeAddressIfShadow(unsigned long, __asan::AddressDescription*, bool) (/tmp/patchelf-0.8/src/patchelf+0x4b7f66)
    #3 0x4b9306 in __asan::DescribeAddress(unsigned long, unsigned long, char const*) (/tmp/patchelf-0.8/src/patchelf+0x4b9306)
    #4 0x4bb0eb in __asan_report_error (/tmp/patchelf-0.8/src/patchelf+0x4bb0eb)
    #5 0x49ed44 in __asan_memcpy (/tmp/patchelf-0.8/src/patchelf+0x49ed44)
    #6 0x521b7b in __gnu_cxx::new_allocator<Elf64_Phdr>::construct(Elf64_Phdr*, Elf64_Phdr const&) /usr/lib/gcc/x86_64-pc-linux-gnu/5.2.0/include/g++-v5/ext/new_allocator.h:130:28
    #7 0x521b7b in void __gnu_cxx::__alloc_traits<std::allocator<Elf64_Phdr> >::construct<Elf64_Phdr>(std::allocator<Elf64_Phdr>&, Elf64_Phdr*, Elf64_Phdr const&) /usr/lib/gcc/x86_64-pc-linux-gnu/5.2.0/include/g++-v5/ext/alloc_traits.h:189
    #8 0x521b7b in std::vector<Elf64_Phdr, std::allocator<Elf64_Phdr> >::_M_insert_aux(__gnu_cxx::__normal_iterator<Elf64_Phdr*, std::vector<Elf64_Phdr, std::allocator<Elf64_Phdr> > >, Elf64_Phdr const&) /usr/lib/gcc/x86_64-pc-linux-gnu/5.2.0/include/g++-v5/bits/vector.tcc:361
    #9 0x517d8f in std::vector<Elf64_Phdr, std::allocator<Elf64_Phdr> >::push_back(Elf64_Phdr const&) /usr/lib/gcc/x86_64-pc-linux-gnu/5.2.0/include/g++-v5/bits/stl_vector.h:925:4
    #10 0x517d8f in ElfFile<Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr, unsigned long, unsigned long, Elf64_Dyn, Elf64_Sym>::parse() /tmp/patchelf-0.8/src/patchelf.cc:281
    #11 0x4e5ab9 in void patchElf2<ElfFile<Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr, unsigned long, unsigned long, Elf64_Dyn, Elf64_Sym> >(ElfFile<Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr, unsigned long, unsigned long, Elf64_Dyn, Elf64_Sym>&, unsigned int) /tmp/patchelf-0.8/src/patchelf.cc:1105:5
    #12 0x4e5ab9 in patchElf() /tmp/patchelf-0.8/src/patchelf.cc:1156
    #13 0x4e5ab9 in main /tmp/patchelf-0.8/src/patchelf.cc:1245
    #14 0x7faa93de77af in __libc_start_main /var/tmp/portage/sys-libs/glibc-2.21-r1/work/glibc-2.21/csu/libc-start.c:289
    #15 0x4190f8 in _start (/tmp/patchelf-0.8/src/patchelf+0x4190f8)

Assertion `shstrtabIndex < shdrs.size()' failed

I'm attempting to create a package for the XCTU application which is distributed only as a Linux binary. Unfortunately, patchelf seems to barf on it:

patchelf: patchelf.cc:292: void ElfFile<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Addr, Elf_Off, Elf_Dyn, Elf_Sym>::parse() [with Elf_Ehdr = Elf64_Ehdr; Elf_Phdr = Elf64_Phdr; Elf_Shdr = Elf64_Shdr; Elf_Addr = long unsigned int; Elf_Off = long unsigned int; Elf_Dyn = Elf64_Dyn; Elf_Sym = Elf64_Sym]: Assertion `shstrtabIndex < shdrs.size()' failed.

file says:

ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), statically linked, stripped

readelf -a says:

ELF Header:
  Magic:   7f 45 4c 46 02 01 01 03 00 00 00 00 00 00 00 00 
  Class:                             ELF64
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - GNU
  ABI Version:                       0
  Type:                              EXEC (Executable file)
  Machine:                           Advanced Micro Devices X86-64
  Version:                           0x1
  Entry point address:               0x46f9f0
  Start of program headers:          64 (bytes into file)
  Start of section headers:          0 (bytes into file)
  Flags:                             0x0
  Size of this header:               64 (bytes)
  Size of program headers:           56 (bytes)
  Number of program headers:         3
  Size of section headers:           64 (bytes)
  Number of section headers:         0
  Section header string table index: 0

There are no sections in this file.

There are no sections to group in this file.

Program Headers:
  Type           Offset             VirtAddr           PhysAddr
                 FileSiz            MemSiz              Flags  Align
  LOAD           0x0000000000000000 0x0000000000300000 0x0000000000300000
                 0x0000000000170b4e 0x0000000000170b4e  R E    100000
  LOAD           0x000000000014e508 0x000000000064e508 0x000000000064e508
                 0x0000000000000000 0x0000000000000000  RW     100000
  PAX_FLAGS      0x0000000000000000 0x0000000000000000 0x0000000000000000
                 0x0000000000000000 0x0000000000000000         4

There is no dynamic section in this file.

There are no relocations in this file.

The decoding of unwind sections for machine type Advanced Micro Devices X86-64 is not currently supported.

No version information found in this file.

patchelf --set-interpreter fails with `cannot find section `

I have a binary compiled with the Go 1.4 compiler from nixpkgs, and I'd like to run it outside of a nix environment, so I'm trying to patch the interpreter.

patchelf 0.8 gives the following error:

$ patchelf --set-interpreter /lib64/ld-linux-x86-64.so.2  prog
patchelf: patchelf.cc:693: void ElfFile<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Addr, Elf_Off, Elf_Dyn, Elf_Sym>::rewriteSectionsExecutable() [with Elf_Ehdr = Elf64_Ehdr; Elf_Phdr = Elf64_Phdr; Elf_Shdr = Elf64_Shdr; Elf_Addr = long unsigned int; Elf_Off = long unsigned int; Elf_Dyn = Elf64_Dyn; Elf_Sym = Elf64_Sym]: Assertion `(off_t) rdi(hdr->e_shoff) >= startOffset' failed.
Aborted

Which I think was fixed in pull 39.

I built a patchelf from master @ 63296c4, and I now get a different error:

 ./result/bin/patchelf --set-interpreter /lib64/ld-linux-x86-64.so.2 --debug prog
patching ELF file `prog'
Kernel page size is 4096 bytes
replacing section `.interp' with size 28
this is an executable
using replaced section `.interp'
last replaced is 2
looking at section `'
replacing section `' which is in the way
looking at section `.interp'
first reserved offset/addr is 0xc00/0x400c00
first page is 0x400000
needed space is 600
clearing first 2504 bytes
cannot find section 

headers:

$ readelf -e prog
ELF Header:
  Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
  Class:                             ELF64
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              EXEC (Executable file)
  Machine:                           Advanced Micro Devices X86-64
  Version:                           0x1
  Entry point address:               0x43dee0
  Start of program headers:          64 (bytes into file)
  Start of section headers:          568 (bytes into file)
  Flags:                             0x0
  Size of this header:               64 (bytes)
  Size of program headers:           56 (bytes)
  Number of program headers:         9
  Size of section headers:           64 (bytes)
  Number of section headers:         33
  Section header string table index: 11

Section Headers:
  [Nr] Name              Type             Address           Offset
       Size              EntSize          Flags  Link  Info  Align
  [ 0]                   NULL             0000000000000000  00000000
       0000000000000000  0000000000000000           0     0     0
  [ 1] .text             PROGBITS         0000000000400c00  00000c00
       000000000029d3fb  0000000000000000  AX       0     0     16
  [ 2] .plt              PROGBITS         000000000069e000  0029e000
       0000000000000170  0000000000000010  AX       0     0     4
  [ 3] .rodata           PROGBITS         000000000069f000  0029f000
       00000000001cd6c0  0000000000000000   A       0     0     32
  [ 4] .typelink         PROGBITS         000000000086c6c0  0046c6c0
       0000000000001308  0000000000000000   A       0     0     8
  [ 5] .gosymtab         PROGBITS         000000000086d9c8  0046d9c8
       0000000000000000  0000000000000000   A       0     0     1
  [ 6] .gopclntab        PROGBITS         000000000086d9e0  0046d9e0
       00000000000f879d  0000000000000000   A       0     0     32
  [ 7] .rela             RELA             0000000000966180  00566180
       0000000000000018  0000000000000018   A      14     0     8
  [ 8] .gnu.version      VERSYM           00000000009661a0  005661a0
       0000000000000038  0000000000000002   A      14     0     2
  [ 9] .gnu.version_r    VERNEED          00000000009661e0  005661e0
       0000000000000040  0000000000000000   A      12     2     8
  [10] .hash             HASH             0000000000966220  00566220
       0000000000000090  0000000000000004   A      14     0     8
  [11] .shstrtab         STRTAB           0000000000000000  005662c0
       0000000000000185  0000000000000000           0     0     1
  [12] .dynstr           STRTAB           0000000000966460  00566460
       0000000000000189  0000000000000000   A       0     0     1
  [13] .rela.plt         RELA             0000000000966600  00566600
       0000000000000210  0000000000000018   A      14     2     8
  [14] .dynsym           DYNSYM           0000000000966820  00566820
       00000000000002a0  0000000000000018   A      12     0     8
  [15] .got              PROGBITS         0000000000967000  00567000
       0000000000000008  0000000000000008  WA       0     0     8
  [16] .got.plt          PROGBITS         0000000000967020  00567020
       00000000000000c8  0000000000000008  WA       0     0     8
  [17] .dynamic          DYNAMIC          0000000000967100  00567100
       0000000000000130  0000000000000010  WA      12     0     8
  [18] .noptrdata        PROGBITS         0000000000967240  00567240
       0000000000015eac  0000000000000000  WA       0     0     32
  [19] .data             PROGBITS         000000000097d100  0057d100
       0000000000006f90  0000000000000000  WA       0     0     32
  [20] .bss              NOBITS           00000000009840a0  005840a0
       0000000000009520  0000000000000000  WA       0     0     32
  [21] .noptrbss         NOBITS           000000000098d5c0  0058d5c0
       0000000000013448  0000000000000000  WA       0     0     32
  [22] .interp           PROGBITS         0000000000400bb0  00000bb0
       0000000000000050  0000000000000000   A       0     0     1
  [23] .symtab           SYMTAB           0000000000000000  00585000
       00000000000340f8  0000000000000018          24   195     8
  [24] .strtab           STRTAB           0000000000000000  005b90f8
       0000000000044f9a  0000000000000000           0     0     1
  [25] .tbss             NOBITS           0000000000000000  00000000
       0000000000000010  0000000000000000 WAT       0     0     8
  [26] .debug_abbrev     PROGBITS         0000000000000000  005fe092
       00000000000000fd  0000000000000000           0     0     1
  [27] .debug_line       PROGBITS         0000000000000000  005fe18f
       00000000000386b7  0000000000000000           0     0     1
  [28] .debug_frame      PROGBITS         0000000000000000  00636846
       00000000000409a4  0000000000000000           0     0     1
  [29] .debug_info       PROGBITS         0000000000000000  006771ea
       000000000010c120  0000000000000000           0     0     1
  [30] .debug_pubnames   PROGBITS         0000000000000000  0078330a
       000000000004cf2d  0000000000000000           0     0     1
  [31] .debug_pubtypes   PROGBITS         0000000000000000  007d0237
       000000000001d88b  0000000000000000           0     0     1
  [32] .debug_aranges    PROGBITS         0000000000000000  007edac2
       0000000000000030  0000000000000000           0     0     1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings), l (large)
  I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown)
  O (extra OS processing required) o (OS specific), p (processor specific)

Program Headers:
  Type           Offset             VirtAddr           PhysAddr
                 FileSiz            MemSiz              Flags  Align
  PHDR           0x0000000000000040 0x0000000000400040 0x0000000000400040
                 0x00000000000001f8 0x00000000000001f8  R      1000
  INTERP         0x0000000000000bb0 0x0000000000400bb0 0x0000000000400bb0
                 0x0000000000000050 0x0000000000000050  R      1
      [Requesting program interpreter: /nix/store/q0m70q5wg21hxrixkp1xk4x95sfs2fln-glibc-2.21/lib/ld-linux-x86-64.so.2]
  LOAD           0x0000000000000040 0x0000000000400040 0x0000000000400040
                 0x000000000029e130 0x000000000029e130  R E    1000
  LOAD           0x000000000029f000 0x000000000069f000 0x000000000069f000
                 0x00000000002c7ac0 0x00000000002c7ac0  R      1000
  LOAD           0x0000000000567000 0x0000000000967000 0x0000000000967000
                 0x000000000001d0a0 0x0000000000039a08  RW     1000
  DYNAMIC        0x0000000000567100 0x0000000000967100 0x0000000000967100
                 0x0000000000000130 0x0000000000000130  RW     8
  TLS            0x0000000000000000 0x0000000000000000 0x0000000000000000
                 0x0000000000000000 0x0000000000000010  R      8
  GNU_STACK      0x0000000000000000 0x0000000000000000 0x0000000000000000
                 0x0000000000000000 0x0000000000000000  RW     8
  LOOS+5041580   0x0000000000000000 0x0000000000000000 0x0000000000000000
                 0x0000000000000000 0x0000000000000000         8

 Section to Segment mapping:
  Segment Sections...
   00
   01     .interp
   02     .text .plt .interp
   03     .rodata .typelink .gosymtab .gopclntab .rela .gnu.version .gnu.version_r .hash .shstrtab .dynstr .rela.plt .dynsym
   04     .got .got.plt .dynamic .noptrdata .data .bss .noptrbss
   05     .dynamic
   06     .tbss
   07
   08

Add tags for latest releases

The last version tag is for 0.6, but it looks like 0.8 is the most recent release. Could you please add the tags for 0.7 and 0.8?

patchelf breaks this Linux shared library

When I run patchelf --set-rpath '$ORIGIN' libgomp.so.1 (Git master) on this particular shared library:

http://newton.cx/~peter/files/libgomp.so.1 (86 K)

it does not report an error, but it apparently breaks the file. For instance, ldd libgomp.so.1 then reports "not a dynamic executable", and in one case loading the library yields an error of "failed to map segment from shared object".

There's probably something about this particular file where modifying the RPATH entry is not feasible, but in that case patchelf should exit with an error rather than breaking the file.

patchelf apparently doesn't update _DYNAMIC symbol?

I was trying to make a function that determined if a program had already the correct runpath set (don't ask...) This should be possible by inspecting the _DYNAMIC symbol as show here and just looking at my own d_tag == DT_RUNPATH entry:
http://stackoverflow.com/a/2846736

However, after running a binary through patchelf, it seems like the _DYNAMIC symbol points to garbage? I haven't investigated more, but I suspect that it just isn't updating that symbol after replacing that ELF header section... if that's the case than probably some other programs that are trying to be clever with _DYNAMIC-introspection

DT_SONAME section handling

Hello,

It would be great to add --print-soname and --set-soname options to manipulate DT_SONAME section contents. I will shortly submit a contribution on this issue,

Regards,
Chingis

Dynamic pageSize breaks (or exposes breakage) when patching foreign binaries

#54 causes problems when patchelf is applied to a binary from other architecture, because the pagesize of the currently running kernel need not be the same for the binary in question. On ppc64el, the following tests fail (as of commit 63296c4):

FAIL: no-rpath-armel.sh
FAIL: no-rpath-armhf.sh
FAIL: no-rpath-hurd-i386.sh
FAIL: no-rpath-i386.sh
FAIL: no-rpath-kfreebsd-i386.sh

All of those fail with the same assertion:

patchelf: patchelf.cc:695: void ElfFile<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Addr, Elf_Off, Elf_Dyn, Elf_Sym>::rewriteSectionsExecutable() [with Elf_Ehdr = Elf32_Ehdr; Elf_Phdr = Elf32_Phdr; Elf_Shdr = Elf32_Shdr; Elf_Addr = unsigned int; Elf_Off = unsigned int; Elf_Dyn = Elf32_Dyn; Elf_Sym = Elf32_Sym]: Assertion `startAddr % getPageSize() == startOffset % getPageSize()' failed.

I'm not sure if the bug is introduced by #54 or just makes it more likely to happen due to sometimes pagesize being larger than 4096, or c4220ea should never really be expected to work, and the correct fix is to somehow get the pagesize from the binary currently being operated on.

It seems to me that patchelf expects the current binaries it operates on to match the current ABI, and that expectation is voided when run over foreign binaries.

CC @adevress @vdanjean

--set-interpreter problem (ubuntu 14 64 bits)

Hi,

Here is what i do :

patchelf --set-interpreter libs_myexe/ld-linux-x86-64.so.2 ./myexe

After it i check with :

ldd myexe | grep ld-linux
libs_myexe/ld-linux-x86-64.so.2 => /lib64/ld-linux-x86-64.so.2 (0x00007f2b025b4000)

It doesn't use the right on when i start the program, because the new path should be the contrary?
ie : /lib64/ld-linux-x86-64.so.2 => libs_myexe/ld-linux-x86-64.so.2

I do something wrong?
Thanks

fail aarch64 -- Need to detect page size from ELF file

make check
Making check in src
make[1]: Entering directory `/home/admin/nix-boot/patchelf-0.8/src'
make[1]: Nothing to be done for `check'.
make[1]: Leaving directory `/home/admin/nix-boot/patchelf-0.8/src'
Making check in tests
make[1]: Entering directory `/home/admin/nix-boot/patchelf-0.8/tests'
make  simple main main-scoped big-dynstr libfoo.so libfoo-scoped.so libbar.so libbar-scoped.so
make[2]: Entering directory `/home/admin/nix-boot/patchelf-0.8/tests'
make[2]: `simple' is up to date.
make[2]: `main' is up to date.
make[2]: `main-scoped' is up to date.
make[2]: `big-dynstr' is up to date.
make[2]: `libfoo.so' is up to date.
make[2]: `libfoo-scoped.so' is up to date.
make[2]: `libbar.so' is up to date.
make[2]: `libbar-scoped.so' is up to date.
make[2]: Leaving directory `/home/admin/nix-boot/patchelf-0.8/tests'
make  check-TESTS
make[2]: Entering directory `/home/admin/nix-boot/patchelf-0.8/tests'
make[3]: Entering directory `/home/admin/nix-boot/patchelf-0.8/tests'
PASS: plain-fail.sh
PASS: plain-run.sh
PASS: shrink-rpath.sh
PASS: set-interpreter-short.sh
FAIL: set-interpreter-long.sh
PASS: no-rpath.sh
FAIL: set-rpath.sh
FAIL: big-dynstr.sh
FAIL: set-rpath-library.sh
make[4]: Entering directory `/home/admin/nix-boot/patchelf-0.8/tests'
make[4]: Nothing to be done for `all'.
make[4]: Leaving directory `/home/admin/nix-boot/patchelf-0.8/tests'
============================================================================
Testsuite summary for patchelf 0.8
============================================================================
# TOTAL: 9
# PASS:  5
# SKIP:  0
# XFAIL: 0
# FAIL:  4
# XPASS: 0
# ERROR: 0
============================================================================
See tests/test-suite.log
============================================================================
make[3]: *** [test-suite.log] Error 1
make[3]: Leaving directory `/home/admin/nix-boot/patchelf-0.8/tests'
make[2]: *** [check-TESTS] Error 2
make[2]: Leaving directory `/home/admin/nix-boot/patchelf-0.8/tests'
make[1]: *** [check-am] Error 2
make[1]: Leaving directory `/home/admin/nix-boot/patchelf-0.8/tests'
make: *** [check-recursive] Error 1

Failed on a dynamic ELF without rela.dyn

Hello,

I've a dynamically linked binary (it has rpath, it has interpeter), on linux x86_64, that lacks rela.dyn. Patchelf complains as if it couldn't do anything with the binary because it lacks rela.dyn.

The binary comes prebuilt from a software distributor, and I don't have access to its source or its build recipes.

Could patchelf be made to work without rela.dyn section?

Changing rpath causes Exec format error on FreeBSD

vks01# cp which git /tmp
vks01# ./patchelf --set-rpath /Software/Git /tmp/git
vks01# ldd /tmp/git
/tmp/git:
libz.so.1 => not found (0)
libiconv.so.3 => not found (0)
libcrypto.so.1.0.0 => not found (0)
libthr.so.3 => /lib/libthr.so.3 (0x800948000)
libc.so.7 => /lib/libc.so.7 (0x800b6b000)
vks01# ./patchelf --set-rpath /Software/Git/lib /tmp/git
vks01# ldd /tmp/git
/tmp/git:
ldd: /tmp/git: Exec format error
/tmp/git: exit status 1

Forking this program under a different name?

It seems that edolstra isn't really interrested in working on this tool together with the community. The last official commit was the version bump to 0.8. I forked the master branch and added a lot of changes that had been offered but he didn't commit. All the authors are now mentioned.
If nothing happens here in a while and more people are offering pull requests, I will rename the program to something like "hackelf" or "elfpatch" and bump the version number. Unfortunately I can't program but maybe someone is interrested in helping me?

edit: I already did that. I'm not creative so I called the fork "patchelfmod".

Cannot force rpath

I'm having trouble setting the RPATH on a binary when it already has a RUNPATH, even when the --force-rpath option is employed. Test case:

cp `which ls` .
readelf -d ./ls | egrep -i "runpath|rpath"

Displays nothing, as ls by default appears to have no rpath or runpath.

patchelf --set-rpath ~/libs ./ls
readelf -d ./ls | egrep -i "runpath|rpath"

Now it displays 0x000000000000001d (RUNPATH) Library runpath: [/home/mpn/libs]. OK, fine!

Next do:

patchelf --force-rpath --set-rpath ~/libs ./ls
readelf -d ./ls | egrep -i "runpath|rpath"

Expected result: It will display an RPATH for the binary
Actual result: It still displays only a RUNPATH for the binary

My current workaround has been to delete the existing RUNPATH using chrpath -d (using --set-rpath "" with patchelf doesn't appear to do it, as that looks rather to set RUNPATH to an empty string instead), and then to use --force-rpath with patchelf. Force-rpath does appear to work when there is no RUNPATH present.

Problem with patchelf and some security features

There appears to be a problem with patchelf in hardened Gentoo. The problem is due to the "hole" put in some files, which is done in as described in this comment:

"As a workaround, make sure that the virtual address of our new
PT_LOAD segment relative to the first PT_LOAD segment is equal
to its offset"

In most cases this hole is getting very large (~18MB) and exceeds the maxSize, causing growFile to error out. It's not clear to me what specific feature is causing this. (ASLR is a common cause of bugs.)

create new DT_SONAME if none was found

A feature to create a new DT_SONAME would be nice. That could be useful when working with some closed-source libs like FMOD. I'm currently trying but can't get it to work.
Maybe I should try to copy the RPATH void and rework its code so that it modifies soname entries.

Workaround for when PatchELF fails?

Sorry if this question is off-topic, but I figure anyone working on this project would know the answer (and anyone using this project probably could benefit from the answer).

I'm trying to run Otto on NixOS and I'm blocked by issues #38 and/or #66. So I'm wondering what are the alternatives to PatchELF in cases where it doesn't work?

The only workaround I've come up with so far is to symlink ld-linux-x86-64.so.2 from /nix/store/... to /lib64/, which is pretty ugly.

gcc -V not found

My patchelf build using gcc 4.8.3 is failing because gcc -V is no longer an option. I found here that this option was removed around gcc 4.6. Using gcc 4.3.4 worked fine. My config.log file is attached.

config.txt

patchelf tests fail to pass on powerpc64

The patchelf "make check" tests fail to execute on linux powerpc64.

PASS: set-interpreter-short.sh
FAIL: set-interpreter-long.sh
FAIL: set-rpath.sh
FAIL: no-rpath.sh
FAIL: big-dynstr.sh
FAIL: set-rpath-library.sh
PASS: soname.sh

This is a blocking issue for the usage of Nix/NixOS on the power architecture.

warning working around a Linux kernel bug by creating a hole

patchelf --set-rpath /opt/lib /opt/lib/libQtCore.so.4.8.7
warning: working around a Linux kernel bug by creating a hole of 2088960 bytes in ‘/opt/lib//libQtCore.so.4.8.7’

I am using patchelf 0.9

I saw a related bug here: #47 and its fix f6886c2

But that didn't solved my issue.

size of libQtCore.so.4.8.7 is only 3.1 M

Improve --remove-needed option usability (and other things)

Instead of
patchelf --remove-needed libfoo1.so --remove-needed libfoo2.so bar
I would prefer something like
patchelf --remove-needed libfoo1.so:libfoo2.so bar

And please update the manpage ("--remove-needed" and "--interpreter" aren't mentioned there) and add "-h" as an alternative to "--help", as it has been requested before. "-v" as an alternative to "--version" would be nice too.

edit:
I've seen that vdanjean contributed changes that were added without mentioning him. But you should mention him and other contributors too, no matter if you merged their pull requests or if you manually applied those changes.

ldconfig warns about truncated libraries

ldconfig puts a warning on files that were modified with patchelf:

djcj patchelf-master $ sudo src/patchelf --set-rpath /usr/lib /usr/lib/x86_64-linux-gnu/libx264.so.142
djcj patchelf-master $ LANG=C sudo ldconfig
/sbin/ldconfig.real: file /usr/lib/x86_64-linux-gnu/libx264.so.142 is truncated

djcj patchelf-master $ 

Tag for each release

Please don't stop tagging the project so we downstream packagers can track the updates as usual.

Thanks.

patchelf --replace-needed forgets to modify .gnu.version_r section

If I have an ELF binary that is linked to a DSO that uses symbol versioning, then the DSO's SONAME appears in two different places: once as a DT_NEEDED entry, and once in the .gnu.version_r version requirements section. If I use patchelf --replace-needed, then it updates the DT_NEEDED entry, but doesn't update the .gnu.version_r table. The resulting binary is completely broken -- trying to load it triggers an assertion failure inside the dynamic loader, as it tries to check the version of a library that was never loaded:

Inconsistency detected by ld.so: dl-version.c: 224: _dl_check_map_versions: Assertion `needed != ((void *)0)' failed!

For example, here's readelf output for a library that's had patchelf --replace-needed libgfortran.so.3 libgfortran-ed201abd.so.3.0.0 run on it:

$ readelf -a lib/python2.7/site-packages/numpy/.libs/libopenblasp-r0-4830d766.2.17.so
[...]
Dynamic section at offset 0x2318100 contains 28 entries:
  Tag        Type                         Name/Value
 0x0000000000000001 (NEEDED)             Shared library: [libm.so.6]
 0x0000000000000001 (NEEDED)             Shared library: [libpthread.so.0]
 0x0000000000000001 (NEEDED)             Shared library: [libgfortran-ed201abd.so.3.0.0]
[...]
Version needs section '.gnu.version_r' contains 4 entries:
 Addr: 0x00000000000aff18  Offset: 0x0aff18  Link: 28 (.dynstr)
  000000: Version: 1  File: libgfortran.so.3  Cnt: 1
  0x0010:   Name: GFORTRAN_1.0  Flags: none  Version: 7

Notice that the DT_NEEDED entry is correct, but the .gnu.version_r entry still refers to the original libgfortran.so.3.

The fix is simple, at least conceptually :-). patchelf --replace-needed should check for any references to the replaced SONAME inside the .gnu.version_r section and update it if necessary.

This bug is a show-stopper for a major effort to enable binary distribution of Python packages as a standard feature on Linux -- we need patchelf --replace-needed to work around this glibc bug or misfeature in the presence of vendored libraries. So FYI, if there's anything we can do to help fix this then we're extremely motivated to do that -- if you don't have time to work on it but can provide hints on where to look then that'd be very much appreciated, or we could probably find some $$ to fund work if that would make a difference...

(Original issue/diagnosis is in pypa/auditwheel#25)

Broken binaries generated on mipsel

Tests failed on mipsel on debian:

FAIL: set-rpath.sh
==================

Kernel page size is 16384 bytes
patching ELF file `scratch/set-rpath/main'
Kernel page size is 16384 bytes
new rpath is `/oops:/home/fsateler/patchelf/tests/scratch/set-rpath/libsA:/home/fsateler/patchelf/tests/scratch/set-rpath/libsB'
rpath is too long, resizing...
DT_NULL index is 27
replacing section `.dynamic' with size 272
replacing section `.dynstr' with size 404
this is an executable
using replaced section `.dynamic'
using replaced section `.dynstr'
last replaced is 9
looking at section `.interp'
replacing section `.interp' which is in the way
looking at section `.note.ABI-tag'
replacing section `.note.ABI-tag' which is in the way
looking at section `.MIPS.abiflags'
replacing section `.MIPS.abiflags' which is in the way
looking at section `.reginfo'
replacing section `.reginfo' which is in the way
looking at section `.note.gnu.build-id'
replacing section `.note.gnu.build-id' which is in the way
looking at section `.dynamic'
looking at section `.hash'
replacing section `.hash' which is in the way
looking at section `.dynsym'
replacing section `.dynsym' which is in the way
looking at section `.dynstr'
first reserved offset/addr is 0x65e/0x40065e
first page is 0x400000
needed space is 1748
needed space is 1780
needed pages is 1
changing alignment of program header 4 from 65536 to 16384
changing alignment of program header 5 from 65536 to 16384
clearing first 17578 bytes
rewriting section `.MIPS.abiflags' from offset 0x41c8 (size 24) to offset 0x1b4 (size 24)
rewriting section `.dynamic' from offset 0x421c (size 264) to offset 0x1cc (size 272)
rewriting section `.dynstr' from offset 0x453c (size 290) to offset 0x2dc (size 404)
rewriting section `.dynsym' from offset 0x43cc (size 368) to offset 0x470 (size 368)
rewriting section `.hash' from offset 0x4324 (size 168) to offset 0x5e0 (size 168)
rewriting section `.interp' from offset 0x4194 (size 13) to offset 0x688 (size 13)
rewriting section `.note.ABI-tag' from offset 0x41a4 (size 32) to offset 0x698 (size 32)
rewriting section `.note.gnu.build-id' from offset 0x41f8 (size 36) to offset 0x6b8 (size 36)
rewriting section `.reginfo' from offset 0x41e0 (size 24) to offset 0x6dc (size 24)
rewriting symbol table section 4
rewriting symbol table section 38
./main: error while loading shared libraries: libfoo.so: cannot open shared object file: No such file or directory
bad exit code!
FAIL set-rpath.sh (exit status: 1)

FAIL: no-rpath.sh
=================

Kernel page size is 16384 bytes
Kernel page size is 16384 bytes
patching ELF file `scratch/no-rpath/no-rpath'
Kernel page size is 16384 bytes
new rpath is `/foo:/bar:/xxxxxxxxxxxxxxx'
rpath is too long, resizing...
DT_NULL index is 26
replacing section `.dynamic' with size 264
replacing section `.dynstr' with size 234
replacing section `.interp' with size 13
this is an executable
using replaced section `.interp'
using replaced section `.dynamic'
using replaced section `.dynstr'
last replaced is 9
looking at section `.interp'
looking at section `.note.ABI-tag'
replacing section `.note.ABI-tag' which is in the way
looking at section `.MIPS.abiflags'
replacing section `.MIPS.abiflags' which is in the way
looking at section `.reginfo'
replacing section `.reginfo' which is in the way
looking at section `.note.gnu.build-id'
replacing section `.note.gnu.build-id' which is in the way
looking at section `.dynamic'
looking at section `.hash'
replacing section `.hash' which is in the way
looking at section `.dynsym'
replacing section `.dynsym' which is in the way
looking at section `.dynstr'
first reserved offset/addr is 0x518/0x400518
first page is 0x400000
needed space is 1336
needed space is 1368
needed pages is 1
changing alignment of program header 4 from 65536 to 16384
changing alignment of program header 5 from 65536 to 16384
clearing first 17252 bytes
rewriting section `.MIPS.abiflags' from offset 0x41c8 (size 24) to offset 0x1b4 (size 24)
rewriting section `.dynamic' from offset 0x421c (size 256) to offset 0x1cc (size 264)
rewriting section `.dynstr' from offset 0x4448 (size 207) to offset 0x2d4 (size 234)
rewriting section `.dynsym' from offset 0x4368 (size 224) to offset 0x3c0 (size 224)
rewriting section `.hash' from offset 0x431c (size 76) to offset 0x4a0 (size 76)
rewriting section `.interp' from offset 0x4194 (size 13) to offset 0x4ec (size 13)
rewriting section `.note.ABI-tag' from offset 0x41a4 (size 32) to offset 0x4fc (size 32)
rewriting section `.note.gnu.build-id' from offset 0x41f8 (size 36) to offset 0x51c (size 36)
rewriting section `.reginfo' from offset 0x41e0 (size 24) to offset 0x540 (size 24)
rewriting symbol table section 4
rewriting symbol table section 38
Kernel page size is 16384 bytes
./no-rpath: error while loading shared libraries: libc.so.6: cannot open shared object file: No such file or directory
FAIL no-rpath.sh (exit status: 127)

FAIL: big-dynstr.sh
===================

Kernel page size is 16384 bytes
patching ELF file `scratch/big-dynstr/big-dynstr'
Kernel page size is 16384 bytes
new rpath is `/oops:/home/fsateler/patchelf/tests/scratch/big-dynstr/libsA:/home/fsateler/patchelf/tests/scratch/big-dynstr/libsB'
rpath is too long, resizing...
DT_NULL index is 27
replacing section `.dynamic' with size 272
replacing section `.dynstr' with size 406
this is an executable
using replaced section `.dynamic'
using replaced section `.dynstr'
last replaced is 9
looking at section `.interp'
replacing section `.interp' which is in the way
looking at section `.note.ABI-tag'
replacing section `.note.ABI-tag' which is in the way
looking at section `.MIPS.abiflags'
replacing section `.MIPS.abiflags' which is in the way
looking at section `.reginfo'
replacing section `.reginfo' which is in the way
looking at section `.note.gnu.build-id'
replacing section `.note.gnu.build-id' which is in the way
looking at section `.dynamic'
looking at section `.hash'
replacing section `.hash' which is in the way
looking at section `.dynsym'
replacing section `.dynsym' which is in the way
looking at section `.dynstr'
first reserved offset/addr is 0x65e/0x40065e
first page is 0x400000
needed space is 1752
needed space is 1784
needed pages is 1
changing alignment of program header 4 from 65536 to 16384
changing alignment of program header 5 from 65536 to 16384
clearing first 17578 bytes
rewriting section `.MIPS.abiflags' from offset 0x41c8 (size 24) to offset 0x1b4 (size 24)
rewriting section `.dynamic' from offset 0x421c (size 264) to offset 0x1cc (size 272)
rewriting section `.dynstr' from offset 0x453c (size 290) to offset 0x2dc (size 406)
rewriting section `.dynsym' from offset 0x43cc (size 368) to offset 0x474 (size 368)
rewriting section `.hash' from offset 0x4324 (size 168) to offset 0x5e4 (size 168)
rewriting section `.interp' from offset 0x4194 (size 13) to offset 0x68c (size 13)
rewriting section `.note.ABI-tag' from offset 0x41a4 (size 32) to offset 0x69c (size 32)
rewriting section `.note.gnu.build-id' from offset 0x41f8 (size 36) to offset 0x6bc (size 36)
rewriting section `.reginfo' from offset 0x41e0 (size 24) to offset 0x6e0 (size 24)
rewriting symbol table section 4
rewriting symbol table section 38
./big-dynstr: error while loading shared libraries: libfoo.so: cannot open shared object file: No such file or directory
bad exit code!
FAIL big-dynstr.sh (exit status: 1)

FAIL: set-rpath-library.sh
==========================

Kernel page size is 16384 bytes
patching ELF file `scratch/set-rpath-library/main-scoped'
Kernel page size is 16384 bytes
new rpath is `/oops:/home/fsateler/patchelf/tests/scratch/set-rpath-library/libsA:/home/fsateler/patchelf/tests/scratch/set-rpath-library/libsB'
rpath is too long, resizing...
DT_NULL index is 27
replacing section `.dynamic' with size 272
replacing section `.dynstr' with size 427
this is an executable
using replaced section `.dynamic'
using replaced section `.dynstr'
last replaced is 9
looking at section `.interp'
replacing section `.interp' which is in the way
looking at section `.note.ABI-tag'
replacing section `.note.ABI-tag' which is in the way
looking at section `.MIPS.abiflags'
replacing section `.MIPS.abiflags' which is in the way
looking at section `.reginfo'
replacing section `.reginfo' which is in the way
looking at section `.note.gnu.build-id'
replacing section `.note.gnu.build-id' which is in the way
looking at section `.dynamic'
looking at section `.hash'
replacing section `.hash' which is in the way
looking at section `.dynsym'
replacing section `.dynsym' which is in the way
looking at section `.dynstr'
first reserved offset/addr is 0x666/0x400666
first page is 0x400000
needed space is 1772
needed space is 1804
needed pages is 1
changing alignment of program header 4 from 65536 to 16384
changing alignment of program header 5 from 65536 to 16384
clearing first 17586 bytes
rewriting section `.MIPS.abiflags' from offset 0x41c8 (size 24) to offset 0x1b4 (size 24)
rewriting section `.dynamic' from offset 0x421c (size 264) to offset 0x1cc (size 272)
rewriting section `.dynstr' from offset 0x453c (size 297) to offset 0x2dc (size 427)
rewriting section `.dynsym' from offset 0x43cc (size 368) to offset 0x488 (size 368)
rewriting section `.hash' from offset 0x4324 (size 168) to offset 0x5f8 (size 168)
rewriting section `.interp' from offset 0x4194 (size 13) to offset 0x6a0 (size 13)
rewriting section `.note.ABI-tag' from offset 0x41a4 (size 32) to offset 0x6b0 (size 32)
rewriting section `.note.gnu.build-id' from offset 0x41f8 (size 36) to offset 0x6d0 (size 36)
rewriting section `.reginfo' from offset 0x41e0 (size 24) to offset 0x6f4 (size 24)
rewriting symbol table section 4
rewriting symbol table section 38
./main-scoped: error while loading shared libraries: libfoo-scoped.so: cannot open shared object file: No such file or directory
Kernel page size is 16384 bytes
patching ELF file `scratch/set-rpath-library/libsA/libfoo-scoped.so'
Kernel page size is 16384 bytes
new rpath is `/oops:/home/fsateler/patchelf/tests/scratch/set-rpath-library/libsB'
rpath is too long, resizing...
DT_NULL index is 27
replacing section `.dynamic' with size 272
replacing section `.dynstr' with size 324
this is a dynamic library
last page is 0x14000
needed space is 948
warning: working around a Linux kernel bug by creating a hole of 65536 bytes in ‘scratch/set-rpath-library/libsA/libfoo-scoped.so’
rewriting section `.dynamic' from offset 0x1cc (size 264) to offset 0x14160 (size 272)
rewriting section `.dynstr' from offset 0x4b0 (size 256) to offset 0x14270 (size 324)
rewriting symbol table section 5
rewriting symbol table section 34
./main-scoped: error while loading shared libraries: libfoo-scoped.so: cannot open shared object file: No such file or directory
bad exit code!
FAIL set-rpath-library.sh (exit status: 1)

Further debug shows that the library is found, it just can't be loaded because there is an invalid MIPS.abiflags:

 % LD_DEBUG=all  ./scratch/set-rpath-library/main-scoped
     27384:
     27384:     file=libfoo-scoped.so [0];  needed by ./scratch/set-rpath-library/main-scoped [0]
     27384:     find library=libfoo-scoped.so [0]; searching
     27384:      search path=/oops/tls/loongson3a:/oops/tls:/oops/loongson3a:/oops:/home/fsateler/patchelf/tests/scratch/set-rpath-library/libsA/tls/loongson3a:/home/fsateler/patchelf/tests/scratch/set-rpath-library/libsA/tls:/home/fsateler/patchelf/tests/scratch/set-rpath-library/libsA/loongson3a:/home/fsateler/patchelf/tests/scratch/set-rpath-library/libsA:/home/fsateler/patchelf/tests/scratch/set-rpath-library/libsB/tls/loongson3a:/home/fsateler/patchelf/tests/scratch/set-rpath-library/libsB/tls:/home/fsateler/patchelf/tests/scratch/set-rpath-library/libsB/loongson3a:/home/fsateler/patchelf/tests/scratch/set-rpath-library/libsB                (RUNPATH from file ./scratch/set-rpath-library/main-scoped)
     27384:       trying file=/oops/tls/loongson3a/libfoo-scoped.so
     27384:       trying file=/oops/tls/libfoo-scoped.so
     27384:       trying file=/oops/loongson3a/libfoo-scoped.so
     27384:       trying file=/oops/libfoo-scoped.so
     27384:       trying file=/home/fsateler/patchelf/tests/scratch/set-rpath-library/libsA/tls/loongson3a/libfoo-scoped.so
     27384:       trying file=/home/fsateler/patchelf/tests/scratch/set-rpath-library/libsA/tls/libfoo-scoped.so
     27384:       trying file=/home/fsateler/patchelf/tests/scratch/set-rpath-library/libsA/loongson3a/libfoo-scoped.so
     27384:       trying file=/home/fsateler/patchelf/tests/scratch/set-rpath-library/libsA/libfoo-scoped.so
     27384:        : unknown MIPS.abiflags flags2: 1482184792
     27384:       trying file=/home/fsateler/patchelf/tests/scratch/set-rpath-library/libsB/tls/loongson3a/libfoo-scoped.so
     27384:       trying file=/home/fsateler/patchelf/tests/scratch/set-rpath-library/libsB/tls/libfoo-scoped.so
     27384:       trying file=/home/fsateler/patchelf/tests/scratch/set-rpath-library/libsB/loongson3a/libfoo-scoped.so
     27384:       trying file=/home/fsateler/patchelf/tests/scratch/set-rpath-library/libsB/libfoo-scoped.so

Further testing shows that this problem happens even when libfoo-scoped has not been touched. The problem appears to be when touching the main-scoped binary. So, I dug up the mentioned header, and indeed it is different in the touched binary:

 % readelf -x .MIPS.abiflags ./scratch/set-rpath-library/main-scoped ; readelf -x .MIPS.abiflags main-scoped

Hex dump of section '.MIPS.abiflags':
  0x003fc1b4 00000200 01010001 00000000 00000000 ................
  0x003fc1c4 00000000 00000000                   ........


Hex dump of section '.MIPS.abiflags':
  0x004001c8 00000200 01010001 00000000 00000000 ................
  0x004001d8 00000000 00000000                   ........

Why would patchelf modify a section it is not supposed to?

Unable to run patchelf on some Ubuntu binaries

Namely on the dynamically linked qemu-user (non-static) binaries. I'm not sure how Ubuntu compiles them

With the newest version of patchelf compiled:
I try
./patchelf --set-interpreter /path/to/ld-linux.so.2 /path/to/qemu-arm
and get
warning: working around a Linux kernel bug by creating a hole of 33796096 bytes in ‘/path/to/qemu-arm’
maximum file size exceeded

I get the same error with --set-rpath as well on the same binary

Section re-ordering confuses `strip`

Running patchelf to enlarge my RUNPATH entry causes my section headers to change from this:

Section Headers:
  [Nr] Name              Type             Address           Offset
       Size              EntSize          Flags  Link  Info  Align
  [ 0]                   NULL             0000000000000000  00000000
       0000000000000000  0000000000000000           0     0     0
  [ 1] .interp           PROGBITS         0000000000400238  00000238
       000000000000001c  0000000000000000   A       0     0     1
  [ 2] .note.ABI-tag     NOTE             0000000000400254  00000254
       0000000000000020  0000000000000000   A       0     0     4
  [ 3] .note.gnu.build-i NOTE             0000000000400274  00000274
       0000000000000024  0000000000000000   A       0     0     4
  [ 4] .gnu.hash         GNU_HASH         0000000000400298  00000298
       0000000000000064  0000000000000000   A       5     0     8
  [ 5] .dynsym           DYNSYM           0000000000400300  00000300
       00000000000011b8  0000000000000018   A       6     1     8
  [ 6] .dynstr           STRTAB           00000000004014b8  000014b8
       0000000000000868  0000000000000000   A       0     0     1
...

To this:

Section Headers:
  [Nr] Name              Type             Address           Offset
       Size              EntSize          Flags  Link  Info  Align
  [ 0]                   NULL             0000000000000000  00000000
       0000000000000000  0000000000000000           0     0     0
  [ 1] .dynsym           DYNSYM           00000000003ffb00  001ffb00
       00000000000011b8  0000000000000018   A       2     1     8
  [ 2] .dynstr           STRTAB           00000000003ff270  00000270
       0000000000000890  0000000000000000   A       0     0     8
  [ 3] .gnu.hash         GNU_HASH         0000000000400cb8  00001cb8
       0000000000000064  0000000000000000   A       1     0     8
  [ 4] .interp           PROGBITS         0000000000400d20  00001d20
       000000000000001c  0000000000000000   A       0     0     8
  [ 5] .note.ABI-tag     NOTE             0000000000400d40  00001d40
       0000000000000020  0000000000000000   A       0     0     8
  [ 6] .note.gnu.build-i NOTE             0000000000400d60  00001d60
       0000000000000024  0000000000000000   A       0     0     8
...

This confuses tools such as strip because they use a header offset of 0 as an error code; here's the relevant function assign_file_positions_for_non_load_sections in elf.c from binutils. Running e.g. gdb --args strip -g my_binary, and setting a breakpoint at that position shows that we get a valid section, but since its filepos is equal to zero, binutils ignores it and continues on, getting confused. Note that even readelf gets a little confused by this, as it doesn't even list the .dynsym segment:

$ readelf -l my_binary
...
 Section to Segment mapping:
  Segment Sections...
   00     
   01     .interp 
   02     .interp .note.ABI-tag .note.gnu.build-id .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.dyn .rela.plt .init .plt .text .fini .rodata .eh_frame_hdr .eh_frame 
   03     .init_array .fini_array .jcr .data.rel.ro .dynamic .got .got.plt .data .bss 
   04     .dynamic 
   05     .note.ABI-tag .note.gnu.build-id 
   06     .eh_frame_hdr 
   07     
   08     .init_array .fini_array .jcr .data.rel.ro .dynamic .got 
$ readelf my_patched_binary
...
 Section to Segment mapping:
  Segment Sections...
   00     
   01     
   02     .dynstr 
   03     .gnu.hash .interp .note.ABI-tag .note.gnu.build-id .gnu.version .gnu.version_r .rela.dyn .rela.plt .init .plt .text .fini .rodata .eh_frame_hdr .eh_frame 
   04     
   05     .interp 
   06     .eh_frame_hdr 
   07     .init_array .fini_array .jcr .data.rel.ro .dynamic .got .got.plt .data .bss 
   08     .init_array .fini_array .jcr .data.rel.ro .dynamic .got 
   09     .dynamic 

I theorize that if we keep the .interp section at the beginning of the file, we might be able to still use tools such as strip, but I don't actually know. Is there an easy way to permute the order of headers that patchelf outputs? If you can just point me in the direction of how to do this, I can submit a PR.

Patchelf --add-needed fails on Android4.1。

Modified program header is stored at the end of elf files. But, linker of Android4.1 read program header at the first PAGE in elf.

code of linker~~~~~~~~:

static soinfo *
load_library(const char *name)
{
...

if ((cnt = read(fd, &__header[0], PAGE_SIZE)) < 0) {
    DL_ERR("read() failed!");
    goto fail;
}

...

if (load_segments(fd, &__header[0], si) < 0) {
    goto fail;
}

...

}

static int
load_segments(int fd, void *header, soinfo *si)
{
Elf32_Ehdr *ehdr = (Elf32_Ehdr *)header;
Elf32_Phdr *phdr = (Elf32_Phdr *)((unsigned char *)header + ehdr->e_phoff);

...

}

Suggestion: use getpagesize()

patchelf.cc has hard-coded values for pageSize.
I believe it would be more portable if PageSize were
discovered using the getpagesize() function.

Also, when I do code that involves size of any kind,
including page size, I use type, size_t. But, in this
case no one would care. Besides, getpagesize()
returns an int, but that is only because it is old.

Request: New option --expand-rpath

AFAIK, I can only replace the whole path with --set-rpath. However, I would like to append / prepend entries to the rpath. I can do print-rpath but that returns an $ORIGIN var which is empty when echo'd (NixOS).

hardcoded maxSize?

During a --set-rpath operation on a vmware binary (vmware-vmx-debug) I get a "maximum file size exceeded" error. After looking at the code I have seen that the maxSize is calculated adding 32MB to the file size. Is there any reason for this limit?

is there any other dependency for patchelf

We were using patchelf 0.8. but we hit a bug about "working around a Linux kernel bug by creating a hole of".
It was already fixed here f6886c2

For that, we tried to use latest 0.9 downloaded from github.com/releases and having some issues with configure.

Running bootstrap.sh says

autoreconf: Entering directory `.'
autoreconf: configure.ac: not using Gettext
autoreconf: running: aclocal --force
autoreconf: configure.ac: tracing
autoreconf: configure.ac: creating directory build-aux
autoreconf: configure.ac: not using Libtool
autoreconf: running: /usr/bin/autoconf --force --warnings=all
autoreconf: configure.ac: not using Autoheader
autoreconf: running: automake --add-missing --copy --force-missing --warnings=all
configure.ac:4: option `color-tests' not recognized
autoreconf: automake failed with exit status: 1

I am wondering if we could make patchelf binaries simply with a gcc patchelf.cc -o patchelf -lc
#47

patchelf fails to --set-interpreter for executable with section headers near start

The following command fails on an executable I am trying to patch to run on NixOS:

$ patchelf --set-interpreter /nix/store/ywxpkmy9kagcsvbjjhi46pr4xwpd6sfm-glibc-2.19/lib/ld-linux-x86-64.so.2 --debug server 
patching ELF file `server'
replacing section `.interp' with size 80
this is an executable
using replaced section `.interp'
last replaced is 1
looking at section `.interp'
first reserved offset/addr is 0xc00/0x400c00
first page is 0x400000
patchelf: patchelf.cc:693: void ElfFile<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Addr, Elf_Off, Elf_Dyn, Elf_Sym>::rewriteSectionsExecutable() [with Elf_Ehdr = Elf64_Ehdr; Elf_Phdr = Elf64_Phdr; Elf_Shdr = Elf64_Shdr; Elf_Addr = long unsigned int; Elf_Off = long unsigned int; Elf_Dyn = Elf64_Dyn; Elf_Sym = Elf64_Sym]: Assertion `(off_t) rdi(hdr->e_shoff) >= startOffset' failed.

I think the assertion is here.

Here are the headers:

$ readelf -e server                                                               
ELF Header:
  Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 
  Class:                             ELF64
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              EXEC (Executable file)
  Machine:                           Advanced Micro Devices X86-64
  Version:                           0x1
  Entry point address:               0x41c9f6
  Start of program headers:          64 (bytes into file)
  Start of section headers:          456 (bytes into file)
  Flags:                             0x0
  Size of this header:               64 (bytes)
  Size of program headers:           56 (bytes)
  Number of program headers:         7
  Size of section headers:           64 (bytes)
  Number of section headers:         22
  Section header string table index: 13

Section Headers:
  [Nr] Name              Type             Address           Offset
       Size              EntSize          Flags  Link  Info  Align
  [ 0]                   NULL             0000000000000000  00000000
       0000000000000000  0000000000000000           0     0     0
  [ 1] .interp           PROGBITS         0000000000400be4  00000be4
       000000000000001c  0000000000000000   A       0     0     1
  [ 2] .got              PROGBITS         0000000000707000  00307000
       0000000000000008  0000000000000008  WA       0     0     8
  [ 3] .got.plt          PROGBITS         0000000000707008  00307008
       0000000000000098  0000000000000008  WA       0     0     8
  [ 4] .dynsym           DYNSYM           0000000000705f50  00305f50
       00000000000001f8  0000000000000018   A       5     0     8
  [ 5] .dynstr           STRTAB           0000000000705c90  00305c90
       0000000000000140  0000000000000000   A       0     0     1
  [ 6] .gnu.version      VERSYM           00000000007059d8  003059d8
       000000000000002a  0000000000000002   A       4     0     2
  [ 7] .gnu.version_r    VERNEED          0000000000705a08  00305a08
       0000000000000040  0000000000000000   A       5     2     8
  [ 8] .rela.plt         RELA             0000000000705dd0  00305dd0
       0000000000000180  0000000000000018   A       4     9     8
  [ 9] .plt              PROGBITS         0000000000705b80  00305b80
       0000000000000110  0000000000000010  AX       0     0     4
  [10] .hash             HASH             0000000000705a48  00305a48
       0000000000000074  0000000000000004   A       4     0     8
  [11] .rela             RELA             00000000007059c0  003059c0
       0000000000000018  0000000000000018   A       4     0     8
  [12] .dynamic          DYNAMIC          00000000007070a0  003070a0
       0000000000000130  0000000000000010  WA       5     0     8
  [13] .shstrtab         STRTAB           0000000000000000  00305ac0
       00000000000000bd  0000000000000000           0     0     1
  [14] .text             PROGBITS         0000000000400c00  00000c00
       0000000000189780  0000000000000000  AX       0     0     8
  [15] .rodata           PROGBITS         000000000058a380  0018a380
       000000000017b640  0000000000000000   A       0     0     8
  [16] .gosymtab         PROGBITS         00000000007059c0  003059c0
       0000000000000000  0000000000000000   A       0     0     8
  [17] .gopclntab        PROGBITS         00000000007059c0  003059c0
       0000000000000000  0000000000000000   A       0     0     8
  [18] .noptrdata        PROGBITS         00000000007071d0  003071d0
       000000000000fd38  0000000000000000  WA       0     0     8
  [19] .data             PROGBITS         0000000000716f08  00316f08
       0000000000007888  0000000000000000  WA       0     0     8
  [20] .bss              NOBITS           000000000071e790  0031e790
       0000000000012bb0  0000000000000000  WA       0     0     8
  [21] .noptrbss         NOBITS           0000000000731340  00331340
       0000000002009e00  0000000000000000  WA       0     0     8
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings), l (large)
  I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown)
  O (extra OS processing required) o (OS specific), p (processor specific)

Program Headers:
  Type           Offset             VirtAddr           PhysAddr
                 FileSiz            MemSiz              Flags  Align
  PHDR           0x0000000000000040 0x0000000000400040 0x0000000000400040
                 0x0000000000000188 0x0000000000000188  R E    1000
  INTERP         0x0000000000000be4 0x0000000000400be4 0x0000000000400be4
                 0x000000000000001c 0x000000000000001c  R      1
      [Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
  LOAD           0x0000000000000040 0x0000000000400040 0x0000000000400040
                 0x0000000000306108 0x0000000000306108  R E    1000
  LOAD           0x0000000000307000 0x0000000000707000 0x0000000000707000
                 0x0000000000017790 0x0000000002034140  RW     1000
  DYNAMIC        0x00000000003070a0 0x00000000007070a0 0x00000000007070a0
                 0x0000000000000130 0x0000000000000130  RW     8
  TLS            0x0000000000000000 0x0000000000000000 0x0000000000000000
                 0x0000000000000000 0x0000000000000010  R      8
  GNU_STACK      0x0000000000000000 0x0000000000000000 0x0000000000000000
                 0x0000000000000000 0x0000000000000000  RW     8

 Section to Segment mapping:
  Segment Sections...
   00     
   01     .interp 
   02     .interp .dynsym .dynstr .gnu.version .gnu.version_r .rela.plt .plt .hash .rela .shstrtab .text .rodata .gosymtab .gopclntab 
   03     .got .got.plt .dynamic .noptrdata .data .bss .noptrbss 
   04     .dynamic 
   05     
   06

Has anyone encountered this before? Is there a workaround? Please let me know if there's anything else I need to do to debug the issue.

patchelf breaks ledger 2.6.3 rpaths

When ledger 2.6.3 is built with dontPatchELF = true, it works just fine. If patchelf is run, however, it breaks the rpath of libamounts.so.0 and libledger-2.6.3.so. Run

ldd $out/bin/ledger

to see the broken paths.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.