summaryrefslogtreecommitdiffstats
path: root/src/patchelf.cc
Commit message (Collapse)AuthorAgeFilesLines
* Improve the default section alignment choicePierre Bourdon2020-06-191-11/+32
| | | | | | | | | | | | | | | | | | | | | | | | | | | | Currently patchelf uses the host system's page size (determined at build time) as the default section load memory alignment. This causes multiple issues - Cross-compilation: when using patchelf on ELFs targetting a different architecture from the host, the host page size is still used by default. - Variable page size architectures: ARMv8 systems can be configured in either 4K, 16K, or 64K page size mode depending on kernel configuration. An ARMv8 patchelf built on a 4K page size system will end up creating ELFs that cannot be used on a 64K page size system. - Reproducibility: the page size of the machine that built patchelf "leaks" into the binary. The build time --with-page-size as well as the run time --page-size options can be used to work around some of these issues. But it's much better to have patchelf do the right thing without explicit configuration. This commit adds support for inferring page size from the ELF header's "machine" field. The default values are extracted from GNU gold's source code. Note that both --with-page-size as well as --page-size continue to work and take precedence on the default value.
* Merge pull request #210 from AaronDMarasco/const_cleanupDomen Kožar2020-06-161-41/+37
|\ | | | | Some const-correctness and C++11 auto
| * Some const-correctness and C++11 autoAaron D. Marasco2020-06-101-41/+37
| | | | | | | | (cherry picked from commit 76e2cdbee4705c45cae4eca55278530a02be2f83)
* | Add libasan build option and test print-neededAaron D. Marasco2020-06-101-2/+1
|/ | | | (cherry picked from commit 288eb61a173ce6f4cdf0be0d744c9c6b6b5598a4)
* Merge pull request #171 from lkollar/no-memset-sonameDomen Kožar2020-06-031-7/+0
|\ | | | | Remove zeroing out logic in modifySoname
| * Remove zeroing out logic in modifySonameLaszlo Kiss-Kollar2019-05-291-7/+0
| | | | | | | | | | | | | | The original SONAME is filled with 'X' characters in the modifySoname function. This can cause issues if the .dynstr entry is still referenced in other sections, e.g. some libraries use the SONAME entry as version specifiers.
* | Merge pull request #202 from rpurdie/masterDomen Kožar2020-06-031-0/+1
|\ \ | | | | | | Fix shared library corruption when rerunning patchelf
| * | Fix shared library corruption when rerunning patchelfRichard Purdie2020-06-031-0/+1
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | When running patchelf on some existing patchelf'd binaries to change to longer RPATHS, ldd would report the binaries as invalid. The output of objdump -x on those libraryies should show the top of the .dynamic section is getting trashed, something like: 0x600000001 0x0000000000429000 0x335000 0x0000000000335000 0xc740 0x000000000000c740 0x1000 0x0000000000009098 SONAME libglib-2.0.so.0 (which should be RPATH and DT_NEEDED entries) This was tracked down to the code which injects the PT_LOAD section. The issue is that if the program headers were previously relocated to the end of the file which was how patchelf operated previously, the relocation code wouldn't work properly on a second run as it now assumes they're located after the elf header. This change forces them back to immediately follow the elf header which is where the code has made space for them. Should fix https://github.com/NixOS/patchelf/issues/170 and https://github.com/NixOS/patchelf/issues/192 Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
* | | Merge pull request #127 from bartosh/masterDomen Kožar2020-06-031-4/+2
|\ \ \ | | | | | | | | fix adjusting startPage
| * | | fix adjusting startPageEd Bartosh2017-07-211-4/+2
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | startPage is adjusted unconditionally for all executables. This results in incorrect addresses assigned to INTERP and LOAD program headers, which breaks patched executable. Adjusting startPage variable only when startOffset > startPage should fix this. This change is related to the issue NixOS#10 Signed-off-by: Ed Bartosh <ed.bartosh@linux.intel.com>
* | | | Consistently use --force-rpath (fixes #94)Thomas Holder2020-06-031-10/+11
| |/ / |/| |
* | | Added --output flagDan L. Stahlke2020-06-011-4/+21
| | |
* | | Update doc to describe multiple filename args allowedPau Espin Pedrol2020-04-081-1/+1
| |/ |/| | | | | | | | | | | | | Commit 936bae418b77ee9e06a93cd3cd444f4204446973 added support to handle several files at once, but forgot to update the man and help output to describe it. Fixes: 936bae418b77ee9e06a93cd3cd444f4204446973
* | Fix issue #66 by ignoring the first section header when sorting, and not ↵Ezra Cooper2018-06-211-2/+3
| | | | | | | | overwriting NOBITS entries.
* | fix reading and writing big files (e.g. > 2Gb)stanislav.markevich2018-05-081-2/+12
| |
* | Merge pull request #123 from lheckemann/multiple-argsEelco Dolstra2018-01-291-13/+16
|\ \ | | | | | | Allow multiple filenames to patch
| * | Allow multiple filenames to patchLinus Heckemann2017-05-281-13/+16
| | | | | | | | | | | | | | | | | | | | | This makes behaviour less confusing when multiple filenames are passed — previously, any extra filenames would be ignored completely, as would any options passed after a filename. Now these are taken into account.
* | | Fix indentationEelco Dolstra2018-01-081-5/+5
| | |
* | | Merge branch 'strict_ordering' of https://github.com/kmillar/patchelfEelco Dolstra2018-01-081-3/+6
|\ \ \
| * | | Simplify ordering code as suggested in PR comments.Karl Millar2018-01-081-6/+6
| | | |
| * | | Modified CompPhdr::operator() so that it provides a strictKarl Millar2017-12-071-1/+4
| |/ / | | | | | | | | | weak ordering as required by std::sort.
* | | Merge pull request #121 from dezgeg/better-error-messagesEelco Dolstra2018-01-051-4/+11
|\ \ \ | |/ / |/| | Better error messages when run on statically-linked (or otherwise weird) binaries
| * | Give a better error message if the file lacks a section header tableTuomas Tynkkynen2017-04-191-2/+5
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Currently, patchelf outputs this when run on a UPX-compressed ELF file: patchelf: patchelf.cc:420: ElfFile<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Addr, Elf_Off, Elf_Dyn, Elf_Sym, Elf_Verneed>::ElfFile(FileContents): Assertion `shstrtabIndex < shdrs.size()' failed. Make it give a nicer error message: patchelf: no section headers. The input file is probably a statically linked, self-decompressing binary Fixes #63
| * | Improve error message when run on statically linked binariesTuomas Tynkkynen2017-04-191-2/+6
| | | | | | | | | | | | | | | If .dynamic, .dynstr or .interp sections aren't found, give an extra hint to the user that the input file is statically linked.
* | | Fix multiple --add-neededEelco Dolstra2017-05-031-0/+1
| | | | | | | | | | | | Reported by Jannis Harder.
* | | Merge branch 'master' of https://github.com/rpurdie/patchelfEelco Dolstra2017-04-211-32/+40
|\ \ \ | |/ / |/| / | |/
| * Avoid inflating file sizes needlessly and allow binaries to be strippedRichard Purdie2017-03-071-32/+40
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | The current approach to changing sections in ET_DYN executables is to move the INTERP section to the end of the file. +This means changing PT_PHDR to add an extra PT_LOAD section so that the new section is mmaped into memory by the elf loader in the kernel. In order to extend PHDR, this means moving it to the end of the file. Its documented in BUGS there is a kernel 'bug' which means that if you have holes in memory between the base load address and the PT_LOAD segment that contains PHDR, it will pass an incorrect PHDR address to ld.so and fail to load the binary, segfaulting. To avoid this, the code currently inserts space into the binary to ensure that when loaded into memory there are no holes between the PT_LOAD sections. This inflates the binaries by many MBs in some cases. Whilst we could make them sparse, there is a second issue which is that strip can fail to process these binaries: $ strip fixincl Not enough room for program headers, try linking with -N [.note.ABI-tag]: Bad value This turns out to be due to libbfd not liking the relocated PHDR section either (https://github.com/NixOS/patchelf/issues/10). Instead this patch implements a different approach, leaving PHDR where it is but extending it in place to allow addition of a new PT_LOAD section. This overwrites sections in the binary but those get moved to the end of the file in the new PT_LOAD section. This is based on patches linked from the above github issue, however whilst the idea was good, the implementation wasn't correct and they've been rewritten here. Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
* | Fix Debian 7 buildEelco Dolstra2017-04-141-0/+1
|/ | | | http://hydra.nixos.org/build/49825195
* Don't check whether DT_STRTAB matches .dynstrEelco Dolstra2017-02-171-23/+2
| | | | | | | We don't really care whether DT_STRTAB is correct, since we overwrite it anyway. https://github.com/NixOS/nixpkgs/issues/22333
* Use exceptionsEelco Dolstra2016-09-191-16/+64
|
* --shrink-rpath: Ignore libraries for different architecturesEelco Dolstra2016-09-191-6/+16
| | | | Fixes #93.
* Factor out fetching ELF typeEelco Dolstra2016-09-191-24/+34
|
* Remove apparently incorrect usage of "static"Eelco Dolstra2016-09-191-5/+3
|
* Some C++11 cleanupEelco Dolstra2016-09-191-22/+15
|
* Cleanup: Remove "using namespace std"Eelco Dolstra2016-09-191-108/+104
|
* Use a std::vector for holding the file contentsEelco Dolstra2016-09-191-58/+59
|
* Remove tabEelco Dolstra2016-09-191-1/+1
|
* Add '--allowed-rpath-prefixes' option to '--shrink-rpath'Tuomas Tynkkynen2016-06-031-6/+26
| | | | | | | | | | | | | | | | | | Fixes #97. In essence, the problem is that some packages in Nixpkgs have RPATHs pointing to both $NIX_BUILD_TOP and $out, e.g.: /tmp/nix-build-openldap-2.4.44.drv-0/openldap-2.4.44/libraries/libldap_r/.libs /tmp/nix-build-openldap-2.4.44.drv-0/openldap-2.4.44/libraries/liblber/.libs /nix/store/bfkmdxmv3a3f0g3d2q8jkdz2wam93c5z-openldap-2.4.44/lib /nix/store/bfkmdxmv3a3f0g3d2q8jkdz2wam93c5z-openldap-2.4.44/lib64 Currently, running `patchelf --shrink-rpath` does the wrong thing by keeping the /tmp/ paths and deleting the /nix/store ones. Now we can fix the problem by using patchelf --shrink-rpath --allowed-rpath-prefixes $NIX_STORE_DIR in the Nixpkgs fixupPhase instead.
* Extract a function for splitting a colon-separated stringTuomas Tynkkynen2016-06-031-9/+19
| | | | | We're going to need this logic in another place, so make a function of this.
* ` -> 'Eelco Dolstra2016-05-031-32/+32
|
* Improve "cannot find section" error messageEelco Dolstra2016-05-031-1/+1
| | | | Issue #66
* Fix bug in walking .gnu.version_r linked listNathaniel J. Smith2016-04-021-1/+1
| | | | | | | | | | | | | | | | | | | When writing the code to teach --replace-needed to modify the .gnu.version_r section (gh-85), I misunderstood how the ->vn_next pointers in the Elf_Verneed structs are supposed to be interpreted: I thought they gave an offset from the beginning of the section, but in fact they give an offset relative to the current struct. The resulting bug was very odd: generally, patchelf would complete without signalling an error, but it would only successfully replace filenames that occurred as either the first or second entries in the .gnu.version_r section, while the third or later entries would be left untouched. This commit fixes the interpretation of the ->vn_next pointers, so that now --replace-needed should work correctly even on ELF files with more than two version needed structs. Thanks to @matthew-brett for finding the bug / providing a test case, and to @rmcgibbo for helping me diagnose it.
* Small cleanups to replaceNeededNathaniel J. Smith2016-04-011-14/+37
| | | | | | No semantic changes, but I noticed some small errors in the DT_NEEDED handling loop while I was adding the .gnu.version_r handling, so might as well fix them while I'm here.
* Teach --replace-needed to update .gnu.version_r tableNathaniel J. Smith2016-04-011-4/+34
| | | | | | | | | | | | | | | | | | If the ELF binary that we're patching 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. Previously, patchelf --replace-needed would update DT_NEEDED entry, but fail to update the .gnu.version_r table. This resulted in completely broken binaries -- trying to load them would trigger 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! This commit teaches --replace-needed to update the .gnu.version_r table. Fixes: gh-84
* rewriteHeaders(): Don't assume PT_PHDR is the first program headerTuomas Tynkkynen2016-02-221-5/+8
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Because this assumption doesn't seem to be valid either in theory or practice: the spec (http://refspecs.linuxbase.org/elf/elf.pdf) only places these requirements on PT_PHDR: "This segment type may not occur more than once in a file. Moreover, it may occur only if the program header table is part of the memory image of the program. If it is present, it must precede any loadable segment entry." And on ARM, binaries generated by GNU GCC / binutils almost never have PT_PHDR as the first entry, e.g. the coreutils 'ls' has this: Program Headers: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align EXIDX 0x0169b4 0x0001e9b4 0x0001e9b4 0x00008 0x00008 R 0x4 PHDR 0x000034 0x00008034 0x00008034 0x00120 0x00120 R E 0x4 INTERP 0x000154 0x00008154 0x00008154 0x0004f 0x0004f R 0x1 [Requesting program interpreter: /nix/store/whcad4dnkp5pnhbv4p0f9k8srv0kmcjk-glibc-2.21/lib/ld-linux-armhf.so.3] LOAD 0x000000 0x00008000 0x00008000 0x169c0 0x169c0 R E 0x8000 LOAD 0x0169c0 0x000269c0 0x000269c0 0x003f4 0x01088 RW 0x8000 DYNAMIC 0x0169cc 0x000269cc 0x000269cc 0x000f8 0x000f8 RW 0x4 NOTE 0x0001a4 0x000081a4 0x000081a4 0x00020 0x00020 R 0x4 GNU_STACK 0x000000 0x00000000 0x00000000 0x00000 0x00000 RW 0x4 PAX_FLAGS 0x000000 0x00000000 0x00000000 0x00000 0x00000 0x4 This problem has existed for quite a long time on ARM and often results in patchelf'd programs segfaulting inside the glibc dynamic linker, which relies on PT_PHDR containing valid contents. This has been worked around in Nixpkgs in various creative ways, like: https://github.com/NixOS/nixpkgs/blob/5c20877d40726b6973d222f71fa6e306428c19cf/nixos/modules/system/boot/stage-1.nix#L109 Applying patchelf twice did actually work in practice due to the fact that patchelf sorts the program headers, causing the first round of patchelf to rewrite an invalid PT_PHDR to appear first, and then the second round of patchelf fixing that PT_PHDR.
* Merge branch 'pagesize' of https://github.com/fsateler/patchelfEelco Dolstra2016-02-221-8/+8
|\
| * Allow overriding pagesize at runtime via a command-line argumentFelipe Sateler2016-01-151-2/+8
| |
| * Allow specifying page size at configure timeFelipe Sateler2016-01-151-7/+1
| |
* | Add a license headerdarealshinji2016-02-221-0/+18
|/ | | | Because why not?
* Don't use dynamic page sizeEelco Dolstra2016-01-081-3/+4
| | | | | | | | | | This mostly reverts 08050dd5e3701b29e5628e1ec7d37c1cd6529c57 (#54) because the page size of the host is not necessarily the same as the page size of the binary. For a proper fix, we'll need some way to determine the page size of the binary, but ELF doesn't readily provide this information. Fixes #69.