-
-
Notifications
You must be signed in to change notification settings - Fork 520
patchelf --set-rpath outputs a binary with broken .dynsym/.dynstr #244
Description
Describe the bug
This seems to be one of the root causes behind NixOS/nixpkgs#97407
When running a certain combination of patchelf + strip + patchelf on the upstream released stage2 ghc 8.6.5 binary, the last patchelf invocation (--set-rpath with a long rpath value) ends up generating a broken ELF file which segfaults the dynamic linker.
(gdb) target remote localhost:9000
Remote debugging using localhost:9000
warning: Loadable section ".dynsym" outside of ELF segments
warning: Loadable section ".dynstr" outside of ELF segments
warning: remote target does not support file transfer, attempting to access files from local filesystem.
Reading symbols from /nix/store/yfa0b4pyywvnspwnlk2nw9id6h6f874x-glibc-2.31/lib/ld-linux-aarch64.so.1...
(No debugging symbols found in /nix/store/yfa0b4pyywvnspwnlk2nw9id6h6f874x-glibc-2.31/lib/ld-linux-aarch64.so.1)
0x00000055008020c0 in _start ()
from /nix/store/yfa0b4pyywvnspwnlk2nw9id6h6f874x-glibc-2.31/lib/ld-linux-aarch64.so.1
(gdb) c
Continuing.
Program received signal SIGSEGV, Segmentation fault.
0x0000005500808cf4 in decompose_rpath.isra ()
from /nix/store/yfa0b4pyywvnspwnlk2nw9id6h6f874x-glibc-2.31/lib/ld-linux-aarch64.so.1
(gdb) bt
#0 0x0000005500808cf4 in decompose_rpath.isra ()
from /nix/store/yfa0b4pyywvnspwnlk2nw9id6h6f874x-glibc-2.31/lib/ld-linux-aarch64.so.1
#1 0x000000550080901c in _dl_init_paths ()
from /nix/store/yfa0b4pyywvnspwnlk2nw9id6h6f874x-glibc-2.31/lib/ld-linux-aarch64.so.1
#2 0x0000005500804898 in dl_main ()
from /nix/store/yfa0b4pyywvnspwnlk2nw9id6h6f874x-glibc-2.31/lib/ld-linux-aarch64.so.1
#3 0x00000055008165b4 in _dl_sysdep_start ()
from /nix/store/yfa0b4pyywvnspwnlk2nw9id6h6f874x-glibc-2.31/lib/ld-linux-aarch64.so.1
#4 0x00000055008029d4 in _dl_start_final ()
from /nix/store/yfa0b4pyywvnspwnlk2nw9id6h6f874x-glibc-2.31/lib/ld-linux-aarch64.so.1
#5 0x0000005500802cf0 in _dl_start ()
from /nix/store/yfa0b4pyywvnspwnlk2nw9id6h6f874x-glibc-2.31/lib/ld-linux-aarch64.so.1
#6 0x00000055008020c8 in _start ()
from /nix/store/yfa0b4pyywvnspwnlk2nw9id6h6f874x-glibc-2.31/lib/ld-linux-aarch64.so.1
Note that gdb seems to already point to a problem with the binary before execution:
warning: Loadable section ".dynsym" outside of ELF segments
warning: Loadable section ".dynstr" outside of ELF segments
And indeed, readelf seems to agree:
Before:
[Nr] Name Type Address Offset
Size EntSize Flags Link Info Align
[ 4] .dynsym DYNSYM 0000000000400298 00010298
0000000000007560 0000000000000018 A 5 1 8
[ 5] .dynstr STRTAB 00000000004077f8 000177f8
000000000000c5e1 0000000000000000 A 0 0 1
Type Offset VirtAddr PhysAddr
FileSiz MemSiz Flags Align
LOAD 0x0000000000010000 0x0000000000400000 0x0000000000400000
0x00000000001ab134 0x00000000001ab134 R E 0x10000
After:
[Nr] Name Type Address Offset
Size EntSize Flags Link Info Align
[ 1] .dynstr STRTAB 00000000003f0270 00000270
000000000000c915 0000000000000000 A 0 0 8
[ 2] .dynsym DYNSYM 00000000003fcb88 0000cb88
0000000000007560 0000000000000018 A 1 1 8
Program Headers:
Type Offset VirtAddr PhysAddr
FileSiz MemSiz Flags Align
LOAD 0x0000000000010000 0x0000000000400000 0x0000000000400000
0x00000000001ab134 0x00000000001ab134 R E 0x10000
Steps To Reproduce
I attached the input binary, gzipped to make github happy: repro.gz
. To reproduce, run:
src/patchelf --set-rpath '/nix/store/mbd1w6i6b98wbh5pf0ikghs1fz5p24j7-ncurses-6.2-abi5-compat/lib:/nix/store/qsxgr8vk6y8m95r7jf3qxrkz648g8p91-gmp-6.2.0/lib:$ORIGIN/../haskeline-0.7.4.3:$ORIGIN/../stm-2.5.0.0:$ORIGIN/../ghc-8.6.5:$ORIGIN/../terminfo-0.4.1.2:$ORIGIN/../process-1.6.5.0:$ORIGIN/../hpc-0.6.0.3:$ORIGIN/../ghci-8.6.5:$ORIGIN/../transformers-0.5.6.2:$ORIGIN/../template-haskell-2.14.0.0:$ORIGIN/../pretty-1.1.3.6:$ORIGIN/../ghc-heap-8.6.5:$ORIGIN/../ghc-boot-8.6.5:$ORIGIN/../ghc-boot-th-8.6.5:$ORIGIN/../directory-1.3.3.0:$ORIGIN/../unix-2.7.2.2:$ORIGIN/../time-1.8.0.2:$ORIGIN/../filepath-1.4.2.1:$ORIGIN/../binary-0.8.6.0:$ORIGIN/../containers-0.6.0.1:$ORIGIN/../bytestring-0.10.8.2:$ORIGIN/../deepseq-1.4.4.0:$ORIGIN/../array-0.5.3.0:$ORIGIN/../base-4.12.0.0:$ORIGIN/../integer-gmp-1.0.2.0:$ORIGIN/../ghc-prim-0.5.3:$ORIGIN/../rts' repro
Expected behavior
A clear and concise description of what you expected to happen.
patchelf --version output
HEAD
Additional context
For some reason the binaries in question don't crash on a 64k page size system. I suspect this is because there is another tiny LOAD segment (< 0x1000 bytes) which if rounded to 64k does end up mapping the two sections by accident (but not if rounded to 4k). That's pure luck though.