Previously when running `patchelf --set-rpath "/usr/sbin" my_bin` on a
PIE ppc32 binary that had no RPATH a few issues were encountered.
This commit fixes:
1. The PT_PHDR being sorted improperly due to the type being read in
incorrect endianness
2. The aligment being set to default 0x1000 due to the machine arch
being read in incorrect endianness
3. The interpreter being clobbered due to the replace sections routine
reading sh_offset and sh_size in incorrect endianness
4. The PHDR segment having an incorrect virt and phys address due to
reading the e_phoff in the incorrect endianness
This also fixes a read of the shdr.sh_type in writeReplacedSections but
this was not encountered during testing.
When checking for already replaced libs, the check against the size must
be done using the section header offset, not the section file address.
This was not crashing in many situations because normally sh_address and
sh_offset have the same value but these two may differ and using the
sh_address value instead can cause library corruption in these
situations.
This commit modifies the way fields are written in the dynamic
section in order to account the architecture of the target ELF
file. Instead of copying the raw data, use the helper functions
to convert endianness.
Signed-off-by: Bryce Ferguson <bryce.ferguson@rockwellcollins.com>
SHT_NOTE sections can be mapped in memory by PT_NOTE segments. When
rewriting an SHT_NOTE, attempt to also rewrite a matching segment if it
exists.
Note that an ELF can contain multiple SHT_NOTE sections, and a given
PT_NOTE segment can theoretically map multiple contiguous sections.
There are multiple ways this could be handled, the one picked here is to
pre-normalize PT_NOTE segments so that a multi-section segment gets
broken up into multiple separate segments instead.
Also fix (or more like hack around) alignment issues with note sections.
Keeping the original alignment value when possible is important because
it determines how the data within the section needs to be parsed.
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.
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>
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.
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>
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.
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
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>