patchelf
patchelf copied to clipboard
`make check` fails when configured `--with-asan`
Describe the bug
Tests fail when patchelf is built with AddressSanitizer instrumentation.
Steps To Reproduce
Working on Ubuntu 18.04.5 LTS,
./bootstrap.sh
./configure --with-asan
make
make check
We see many failures not present without asan, eg:
PASS: plain-fail.sh
PASS: plain-run.sh
PASS: shrink-rpath.sh
PASS: set-interpreter-short.sh
PASS: set-interpreter-long.sh
PASS: set-rpath.sh
PASS: no-rpath.sh
PASS: big-dynstr.sh
PASS: set-rpath-library.sh
PASS: soname.sh
PASS: shrink-rpath-with-allowed-prefixes.sh
PASS: force-rpath.sh
PASS: plain-needed.sh
PASS: output-flag.sh
PASS: no-rpath-pie-powerpc.sh
PASS: build-id.sh
PASS: invalid-elf.sh
FAIL: no-rpath-amd64.sh
FAIL: no-rpath-armel.sh
FAIL: no-rpath-armhf.sh
FAIL: no-rpath-hurd-i386.sh
FAIL: no-rpath-i386.sh
FAIL: no-rpath-ia64.sh
FAIL: no-rpath-kfreebsd-amd64.sh
FAIL: no-rpath-kfreebsd-i386.sh
PASS: no-rpath-mips.sh
PASS: no-rpath-mipsel.sh
FAIL: no-rpath-powerpc.sh
FAIL: no-rpath-s390.sh
PASS: no-rpath-sh4.sh
PASS: no-rpath-sparc.sh
============================================================================
Testsuite summary for patchelf 0.12
============================================================================
# TOTAL: 31
# PASS: 21
# SKIP: 0
# XFAIL: 0
# FAIL: 10
# XPASS: 0
# ERROR: 0
============================================================================
See tests/test-suite.log
============================================================================
I didn't look at all the logs, but they seem to be memory corruption issues. Eg, tests/no-rpath-amd64.sh.log shows
=================================================================
==19393==ERROR: AddressSanitizer: heap-use-after-free on address 0x614000000190 at pc 0x558b4ac8da24 bp 0x7ffd0f898130 sp 0x7ffd0f898120
READ of size 4 at 0x614000000190 thread T0
#0 0x558b4ac8da23 in ElfFile<Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr, unsigned long, unsigned long, Elf64_Dyn, Elf64_Sym, Elf64_Verneed, unsigned short>::normalizeNoteSegments() /home/tom/projects/patchelf/src/patchelf.cc:991
#1 0x558b4accdea3 in ElfFile<Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr, unsigned long, unsigned long, Elf64_Dyn, Elf64_Sym, Elf64_Verneed, unsigned short>::rewriteSectionsExecutable() /home/tom/projects/patchelf/src/patchelf.cc:931
#2 0x558b4accec5a in ElfFile<Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr, unsigned long, unsigned long, Elf64_Dyn, Elf64_Sym, Elf64_Verneed, unsigned short>::rewriteSections() /home/tom/projects/patchelf/src/patchelf.cc:1048
#3 0x558b4ac6456f in patchElf2<ElfFile<Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr, long unsigned int, long unsigned int, Elf64_Dyn, Elf64_Sym, Elf64_Verneed, short unsigned int> > /home/tom/projects/patchelf/src/patchelf.cc:1770
#4 0x558b4ac6456f in patchElf /home/tom/projects/patchelf/src/patchelf.cc:1791
#5 0x558b4ac6456f in mainWrapped(int, char**) /home/tom/projects/patchelf/src/patchelf.cc:1937
#6 0x558b4ac5c9ad in main /home/tom/projects/patchelf/src/patchelf.cc:1945
#7 0x7fb13e3b9bf6 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21bf6)
#8 0x558b4ac5d439 in _start (/home/tom/projects/patchelf/src/patchelf+0x7439)
0x614000000190 is located 336 bytes inside of 448-byte region [0x614000000040,0x614000000200)
freed by thread T0 here:
#0 0x7fb13ee0b2c0 in operator delete(void*) (/usr/lib/x86_64-linux-gnu/libasan.so.4+0xe12c0)
#1 0x558b4ac72efb in __gnu_cxx::new_allocator<Elf64_Phdr>::deallocate(Elf64_Phdr*, unsigned long) /usr/include/c++/7/ext/new_allocator.h:125
#2 0x558b4ac72efb in std::allocator_traits<std::allocator<Elf64_Phdr> >::deallocate(std::allocator<Elf64_Phdr>&, Elf64_Phdr*, unsigned long) /usr/include/c++/7/bits/alloc_traits.h:462
#3 0x558b4ac72efb in std::_Vector_base<Elf64_Phdr, std::allocator<Elf64_Phdr> >::_M_deallocate(Elf64_Phdr*, unsigned long) /usr/include/c++/7/bits/stl_vector.h:180
#4 0x558b4ac72efb in void std::vector<Elf64_Phdr, std::allocator<Elf64_Phdr> >::_M_realloc_insert<Elf64_Phdr const&>(__gnu_cxx::__normal_iterator<Elf64_Phdr*, std::vector<Elf64_Phdr, std::allocator<Elf64_Phdr> > >, Elf64_Phdr const&)
/usr/include/c++/7/bits/vector.tcc:448
#5 0x558b4ac8d665 in std::vector<Elf64_Phdr, std::allocator<Elf64_Phdr> >::push_back(Elf64_Phdr const&) /usr/include/c++/7/bits/stl_vector.h:948
#6 0x558b4ac8d665 in ElfFile<Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr, unsigned long, unsigned long, Elf64_Dyn, Elf64_Sym, Elf64_Verneed, unsigned short>::normalizeNoteSegments() /home/tom/projects/patchelf/src/patchelf.cc:1025
#7 0x558b4accdea3 in ElfFile<Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr, unsigned long, unsigned long, Elf64_Dyn, Elf64_Sym, Elf64_Verneed, unsigned short>::rewriteSectionsExecutable() /home/tom/projects/patchelf/src/patchelf.cc:931
#8 0x558b4accec5a in ElfFile<Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr, unsigned long, unsigned long, Elf64_Dyn, Elf64_Sym, Elf64_Verneed, unsigned short>::rewriteSections() /home/tom/projects/patchelf/src/patchelf.cc:1048
#9 0x558b4ac6456f in patchElf2<ElfFile<Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr, long unsigned int, long unsigned int, Elf64_Dyn, Elf64_Sym, Elf64_Verneed, short unsigned int> > /home/tom/projects/patchelf/src/patchelf.cc:1770
#10 0x558b4ac6456f in patchElf /home/tom/projects/patchelf/src/patchelf.cc:1791
#11 0x558b4ac6456f in mainWrapped(int, char**) /home/tom/projects/patchelf/src/patchelf.cc:1937
#12 0x558b4ac5c9ad in main /home/tom/projects/patchelf/src/patchelf.cc:1945
#13 0x7fb13e3b9bf6 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21bf6)
previously allocated by thread T0 here:
#0 0x7fb13ee0a448 in operator new(unsigned long) (/usr/lib/x86_64-linux-gnu/libasan.so.4+0xe0448)
#1 0x558b4ac72ce5 in __gnu_cxx::new_allocator<Elf64_Phdr>::allocate(unsigned long, void const*) /usr/include/c++/7/ext/new_allocator.h:111
#2 0x558b4ac72ce5 in std::allocator_traits<std::allocator<Elf64_Phdr> >::allocate(std::allocator<Elf64_Phdr>&, unsigned long) /usr/include/c++/7/bits/alloc_traits.h:436
#3 0x558b4ac72ce5 in std::_Vector_base<Elf64_Phdr, std::allocator<Elf64_Phdr> >::_M_allocate(unsigned long) /usr/include/c++/7/bits/stl_vector.h:172
#4 0x558b4ac72ce5 in void std::vector<Elf64_Phdr, std::allocator<Elf64_Phdr> >::_M_realloc_insert<Elf64_Phdr const&>(__gnu_cxx::__normal_iterator<Elf64_Phdr*, std::vector<Elf64_Phdr, std::allocator<Elf64_Phdr> > >, Elf64_Phdr const&)
/usr/include/c++/7/bits/vector.tcc:406
#5 0x558b4ac74f67 in std::vector<Elf64_Phdr, std::allocator<Elf64_Phdr> >::push_back(Elf64_Phdr const&) /usr/include/c++/7/bits/stl_vector.h:948
#6 0x558b4ac74f67 in ElfFile<Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr, unsigned long, unsigned long, Elf64_Dyn, Elf64_Sym, Elf64_Verneed, unsigned short>::ElfFile(std::shared_ptr<std::vector<unsigned char, std::allocator<unsigned char> > >)
/home/tom/projects/patchelf/src/patchelf.cc:417
#7 0x558b4ac63533 in patchElf /home/tom/projects/patchelf/src/patchelf.cc:1791
#8 0x558b4ac63533 in mainWrapped(int, char**) /home/tom/projects/patchelf/src/patchelf.cc:1937
#9 0x558b4ac5c9ad in main /home/tom/projects/patchelf/src/patchelf.cc:1945
#10 0x7fb13e3b9bf6 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21bf6)
Expected behavior
ASAN-instrumented tests should be clean and pass without error.
patchelf --version output
patchelf 0.12
Additional context
I was working on the approach outlined here to rework readFile to not have a fixed capacity. I used a more standard approach of reading a file to a string (without pre-reservation of a std::vector), but tests failed unless I reserved some extra scratch space on the vector. This got me suspicious of possible memory-corruption shenanigans in this source, so I built with address sanitizer (fortunately supported by configure!) and hit all this stuff.
If I get a little time, I may try to address these issues myself.
Thanks for your efforts on this library!
I think it would be best if we do build with asan and ubsan by default in non-release builds
Can you still reproduce these issues on master? I can't.