Public bug reported:
libelf from elfutils 0.196-1 corrupts an ELF file when it rewrites it
with elf_update(ELF_C_WRITE) in ELF_C_RDWR (non-mmap) mode with
ELF_F_LAYOUT set, if the section header table is not at the end of the
file. All section headers in the output end up zeroed (readelf shows
<no-strings>/NULL for every section, "no .dynamic section in the dynamic
segment"), and objcopy then fails with "has a corrupt string table
index".
patchelf always produces that layout: e.g. after "patchelf --set-
soname", the moved .note.gnu.build-id/.gnu.hash/.dynstr/.dynamic
sections are placed in a new segment after the section header table.
debugedit opens files with ELF_C_RDWR and sets ELF_F_LAYOUT
(tools/debugedit.c), so "debugedit --build-id --build-id-seed=X" (which
rewrites the build-id note, forcing a write) corrupts any patchelf-
modified file. Without a seed debugedit does not write and nothing
happens. The same write with ELF_C_RDWR_MMAP works fine, and so does
debugedit on a copy rewritten by objcopy (which puts the section header
table at the end).
Reproducer (stonking, libelf1t64 0.196-1, debugedit 1:5.3-4, patchelf
0.18.0-1.4build1), with any shared library that has a build-id:
patchelf --set-soname libx.so.0 --output p.so libfoo.so
cp p.so r.so; debugedit --build-id --build-id-seed=x r.so
readelf -SW r.so # all section headers are NULL/<no-strings>
objcopy --only-keep-debug r.so r.dbg # "corrupt string table index"
Minimal libelf reproducer (flip a byte of the build-id note and write
back):
#include <libelf.h>
#include <gelf.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
int main(int c,char**v){ int mm=c>2; elf_version(EV_CURRENT); int
fd=open(v[1],O_RDWR);
Elf*e=elf_begin(fd, mm?ELF_C_RDWR_MMAP:ELF_C_RDWR,NULL);
elf_flagelf(e,ELF_C_SET,ELF_F_LAYOUT);
size_t shstr; elf_getshdrstrndx(e,&shstr); Elf_Scn*s=NULL;
while((s=elf_nextscn(e,s))){GElf_Shdr h;gelf_getshdr(s,&h);
if(!strcmp(elf_strptr(e,shstr,h.sh_name),".note.gnu.build-id")){Elf_Data*d=elf_getdata(s,NULL);((char*)d->d_buf)[20]^=1;elf_flagdata(d,ELF_C_SET,ELF_F_DIRTY);}}
if(elf_update(e,ELF_C_WRITE)<0)printf("err %s\n",elf_errmsg(-1)); elf_end(e);
close(fd); return 0;}
gcc t.c -lelf -o t
cp p.so u.so; ./t u.so -> 39 NULL section headers
cp p.so u.so; ./t u.so mmap -> file is fine
In Ubuntu this matters because debhelper's Ubuntu delta runs "debugedit
--build-id --build-id-seed=..." on every ELF file in dh_strip, so
packages shipping patchelf-modified files fail to build (see the
debhelper bug cross-referenced in a comment). Debian is not affected in
practice because its dh_strip does not call debugedit.
Not checked: whether elfutils upstream already fixed this (sourceware
git was not reachable from here), or whether debugedit should rather
open with ELF_C_RDWR_MMAP.
** Affects: debugedit (Ubuntu)
Importance: Undecided
Status: New
** Affects: elfutils (Ubuntu)
Importance: Undecided
Status: New
--
You received this bug notification because you are a member of Ubuntu
Bugs, which is subscribed to Ubuntu.
https://bugs.launchpad.net/bugs/2169676
Title:
libelf elf_update(ELF_C_WRITE) with ELF_F_LAYOUT corrupts section
headers when the section header table is not at the end of the file
(patchelf output); breaks debugedit
To manage notifications about this bug go to:
https://bugs.launchpad.net/ubuntu/+source/debugedit/+bug/2169676/+subscriptions
--
ubuntu-bugs mailing list
[email protected]
https://lists.ubuntu.com/mailman/listinfo/ubuntu-bugs