diff options
author | Ivan A. Melnikov <iv@altlinux.org> | 2019-08-22 15:30:11 +0400 |
---|---|---|
committer | Ivan A. Melnikov <iv@altlinux.org> | 2021-08-11 17:49:41 +0400 |
commit | b240bb8dcfb7bdce32df12d13c2829516a02ead7 (patch) | |
tree | 9869adba66b1239a8e930a021e1be6918392c7a6 /tests | |
parent | 374c92ad4e4d85684c35637ca70c8a7449d39397 (diff) | |
download | patchelf-b240bb8dcfb7bdce32df12d13c2829516a02ead7.tar.gz |
Adjust DT_MIPS_RLD_MAP_REL dynamic section entry if present
`patchelf --set-rpath` corrupted executables on mips32el: the dynamic
liker crushed with Segmentation fault when loading any executable with
RPATH added that way.
The problem was around the MIPS-specific mechanism of setting up the
debug map pointer. When DT_MIPS_RLD_MAP_REL entry in the dynamic section
is present, it holds the relative address of __RLD_MAP -- an offset
relative to this dynamic section entry. Dynamic linker puts the
pointer to the `r_debug` structure there.
When patchelf updates the executable RPATH, it moves the .dynamic
section both in the binary and in memory, while __RLD_MAP is not moved
in memory, since it belongs to special .rld_map section that has type
PROGBITS. So, the offset stored in DT_MIPS_RLD_MAP_REL entry is not
valid anymore and should be updated.
This commit adds the necessary update.
In the corner case when DT_MIPS_RLD_MAP_REL is present, but
.rld_map section is not, the dynamic loader writes the debug
pointer to some arbitrary bytes in memory. To avoid crushes
on otherwise "working" binaries, we set offset to zero
so that the dynamic loader would just overwrite the dynamic
section.
Here we also import DT_MIPS_RLD_MAP_REL definition in elf.h form
glibc commit a2057c984e4314c3740f04cf54e36c824e4c8f32.
Refs: #82
Signed-off-by: Ivan A. Melnikov <iv@altlinux.org>
Diffstat (limited to 'tests')
-rw-r--r-- | tests/Makefile.am | 1 | ||||
-rwxr-xr-x | tests/set-rpath-rel-map.sh | 37 |
2 files changed, 38 insertions, 0 deletions
diff --git a/tests/Makefile.am b/tests/Makefile.am index 91a28ae..2196401 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -22,6 +22,7 @@ src_TESTS = \ plain-fail.sh plain-run.sh shrink-rpath.sh set-interpreter-short.sh \ set-interpreter-long.sh set-rpath.sh add-rpath.sh no-rpath.sh big-dynstr.sh \ set-rpath-library.sh soname.sh shrink-rpath-with-allowed-prefixes.sh \ + set-rpath-rel-map.sh \ force-rpath.sh \ plain-needed.sh \ output-flag.sh \ diff --git a/tests/set-rpath-rel-map.sh b/tests/set-rpath-rel-map.sh new file mode 100755 index 0000000..efc0943 --- /dev/null +++ b/tests/set-rpath-rel-map.sh @@ -0,0 +1,37 @@ +#! /bin/sh -e + +if ! objdump -p main | grep -q MIPS_RLD_MAP_REL; then + echo "No MIPS_RLD_MAP_REL dynamic section entry, skipping" + exit 0 +fi + +SCRATCH=scratch/$(basename $0 .sh) + +rm -rf ${SCRATCH} +mkdir -p ${SCRATCH} +mkdir -p ${SCRATCH}/libsA +mkdir -p ${SCRATCH}/libsB + +cp main ${SCRATCH}/ +cp libfoo.so ${SCRATCH}/libsA/ +cp libbar.so ${SCRATCH}/libsB/ + +# break the main executable by removing .rld_map section +objcopy --remove-section .rld_map ${SCRATCH}/main + +oldRPath=$(../src/patchelf --print-rpath ${SCRATCH}/main) +if test -z "$oldRPath"; then oldRPath="/oops"; fi +../src/patchelf --force-rpath --set-rpath $oldRPath:$(pwd)/${SCRATCH}/libsA:$(pwd)/${SCRATCH}/libsB ${SCRATCH}/main + +if test "$(uname)" = FreeBSD; then + export LD_LIBRARY_PATH=$(pwd)/${SCRATCH}/libsB +fi + +exitCode=0 + +(cd ${SCRATCH} && ./main) || exitCode=$? + +if test "$exitCode" != 46; then + echo "bad exit code!" + exit 1 +fi |