Re: bin-x86_64/diet segfaults in findtlsdata()

[email protected] Mon, 6 Aug 2018 14:28:48 +0200 (CEST)
Newsgroups gmane.linux.lib.dietlibc
Message-ID <[email protected]>
> On August 6, 2018 at 1:54 PM [email protected] wrote:
> 
> 
> Hi,
> 
> I'm getting a new segfault while building the current dietlibc cvs:
> 
> ...
> make: Entering directory '/tmp/dietlibc-cvs'
> bin-x86_64/diet gcc -D__dietlibc__ -g -O0 -march=native -Wall -fno-stack-protector -std=gnu99 -W -Wall -Wextra -Wchar-subscripts -Wmissing-prototypes -Wmissing-declarations -Wno-switch -Wno-unused -Wredundant-decls -Wshadow -o bin-x86_64/elftrunc contrib/elftrunc.c
> make: *** [Makefile:346: bin-x86_64/elftrunc] Segmentation fault
> 
> 
> After a bit of gdbugging here is the segfault context:
> 
> inside the function findtlsdata(long* auxvec) in lib/stackgap-common.h:
> 
> ...
> static void findtlsdata(long* auxvec) {
> #if (__WORDSIZE == 64)
> Elf64_Phdr* x=0;
> #else
> Elf32_Phdr* x=0;
> #endif
> size_t i,n=0;
> while (*auxvec) {
> if (auxvec[0]==3) { /* AT_PHDR */
> x=(void*)auxvec[1];
> if (n) break;
> } else if (auxvec[0]==5) { /* AT_PHNUM */
> n=auxvec[1];
> if (x) break;
> }
> auxvec+=2;
> } /* if we don't find the entry, the kernel let us down */
> if (!x || !n) return; /* a kernel this old does not support thread local storage anyway */
> for (i=0; i<n; ++i)
> if (x[i].p_type==PT_TLS) {
> __tdataptr=(void*)x[i].p_vaddr;
> __tdatasize=x[i].p_filesz;
> __tmemsize=x[i].p_memsz;
> if (__tmemsize&15)
> __tmemsize=(__tmemsize+15)&~15;
> break;
> }
> /* if there is no PT_TLS section, there is no thread-local data, and
> * we just leave the __t* variables zero */
> }
> ...
> 
> it searches the auxvec table for the PHDR address and the PHNUM and it actually finds something:
> here is a memory dump of the auxvec in gdb:
> 
> (gdb) x/40ug auxvec
> 0x7fffffffe1e8: 33 140737354125312
> 0x7fffffffe1f8: 16 3219913727
> 0x7fffffffe208: 6 4096
> 0x7fffffffe218: 17 100
> 0x7fffffffe228: 3 4194368
> 0x7fffffffe238: 4 56
> 0x7fffffffe248: 5 6
> 0x7fffffffe258: 7 0
> 0x7fffffffe268: 8 0
> 0x7fffffffe278: 9 4198400
> 0x7fffffffe288: 11 1000
> 0x7fffffffe298: 12 1000
> 0x7fffffffe2a8: 13 999
> 0x7fffffffe2b8: 14 999
> 0x7fffffffe2c8: 23 0
> 0x7fffffffe2d8: 25 140737488347945
> 0x7fffffffe2e8: 26 0
> 0x7fffffffe2f8: 31 140737488351118
> 0x7fffffffe308: 15 140737488347961
> 0x7fffffffe318: 0 0
> (gdb) x/40xg auxvec
> 0x7fffffffe1e8: 0x0000000000000021 0x00007ffff7ffd000
> 0x7fffffffe1f8: 0x0000000000000010 0x00000000bfebfbff
> 0x7fffffffe208: 0x0000000000000006 0x0000000000001000
> 0x7fffffffe218: 0x0000000000000011 0x0000000000000064
> 0x7fffffffe228: 0x0000000000000003 0x0000000000400040
> 0x7fffffffe238: 0x0000000000000004 0x0000000000000038
> 0x7fffffffe248: 0x0000000000000005 0x0000000000000006
> 0x7fffffffe258: 0x0000000000000007 0x0000000000000000
> 0x7fffffffe268: 0x0000000000000008 0x0000000000000000
> 0x7fffffffe278: 0x0000000000000009 0x0000000000401000
> 0x7fffffffe288: 0x000000000000000b 0x00000000000003e8
> 0x7fffffffe298: 0x000000000000000c 0x00000000000003e8
> 0x7fffffffe2a8: 0x000000000000000d 0x00000000000003e7
> 0x7fffffffe2b8: 0x000000000000000e 0x00000000000003e7
> 0x7fffffffe2c8: 0x0000000000000017 0x0000000000000000
> 0x7fffffffe2d8: 0x0000000000000019 0x00007fffffffe329
> 0x7fffffffe2e8: 0x000000000000001a 0x0000000000000000
> 0x7fffffffe2f8: 0x000000000000001f 0x00007fffffffef8e
> 0x7fffffffe308: 0x000000000000000f 0x00007fffffffe339
> 0x7fffffffe318: 0x0000000000000000 0x0000000000000000
> (gdb)
> 
> The pointer 'x' gets the value 0x400040 and the program segfaults as soon as 'x'
> is dereferenced in:
> 
> if (x[i].p_type==PT_TLS) {
> 
> with i==0.
> 
> Can someone recognize something stange in this ? Is the address 0x400040 'plausible'
> or is it obviously wrong.
> 
> I'm compiling natively with gcc 8.2 on linux 4.17.11.
> 
> giorgio


I suspect this is a bug in recent versions of binutils (2.30 ~ 2.31),
see:

  https://sourceware.org/bugzilla/show_bug.cgi?id=23428

and

  http://www.openwall.com/lists/musl/2018/07/18/5

giorgio