Bug#749122: ld.so crashes when sections are placed at different addresses
On Mon, May 26, 2014 at 10:42:54AM +0200, Goswin von Brederlow wrote:
> On Sat, May 24, 2014 at 03:17:25PM +0200, Aurelien Jarno wrote:
> > On Sat, May 24, 2014 at 12:23:23PM +0200, Goswin von Brederlow wrote:
> > > Package: libc6
> > > Version: 2.18-7
> > > Severity: normal
> > > File: /lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
> > >
> > > Hi,
> > >
> > > I want to mmap a large file to 0x10000 because the data contains
> > > pointers and was originally at that offset. Mapping somewhere else and
> > > relocating all the pointers is impossible. Unfortunately on amd64
> > > binaries are normaly mapped at 0x00400000 and 0x0060a000 onwards,
> > > conflicting with mapping the file. So I tried to link my binary to be
> > > at a different address. But that makes ld.so crash with SIGSEGV or
> > > SIGILL.
> > >
> > > ----------------------------------------------------------------------
> > > echo 'int main() { return 0; }' | gcc-4.8 -Wl,--section-start=.interp=0x70000000 -x c -
> > > gdb ./a.out
> > >
> > > Program received signal SIGSEGV, Segmentation fault.
> > > dl_main (phdr=phdr@entry=0x6fe00040, phnum=phnum@entry=8,
> > > user_entry=user_entry@entry=0x7fffffffe3c8, auxv=<optimized out>)
> > > at rtld.c:1169
> >
> > The kernel maps the PHDR entry at address 0x6fe00040 (this can also be
> > seen using LD_SHOW_AUXV=1), but in practice nothing is mapped at this
> > address, so ld.so crashes on the first access at this address.
> >
> > This is likely due to a non conform ELF file format, anyway it's clearly
> > not a bug in libc. Please dig more about the issue and report the bug
> > against the correct package. Closing the bug.
>
> Looking more closely at what is mapped there seems indeed be something
> missing, which would be the kernels fault I guess.
>
> But something is wrong with ld.so too. readelf shows this:
>
> Type Offset VirtAddr PhysAddr
> FileSiz MemSiz Flags Align
> PHDR 0x0000000000000040 0x0000000000200040 0x0000000000000000
> 0x00000000000001c0 0x00000000000001c0 R E 8
> INTERP 0x0000000000200000 0x0000000070000000 0x0000000070000000
> 0x000000000000001c 0x000000000000001c R 1
> [Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
> LOAD 0x0000000000200000 0x0000000070000000 0x0000000070000000
> 0x00000000000004cc 0x00000000000004cc R E 200000
> LOAD 0x00000000002004d0 0x00000000702004d0 0x00000000702004d0
> 0x0000000000000230 0x0000000000000238 RW 200000
> DYNAMIC 0x00000000002004e8 0x00000000702004e8 0x00000000702004e8
> 0x00000000000001d0 0x00000000000001d0 RW 8
> NOTE 0x000000000020001c 0x000000007000001c 0x000000007000001c
> 0x0000000000000044 0x0000000000000044 R 4
> GNU_EH_FRAME 0x00000000002003a4 0x00000000700003a4 0x00000000700003a4
> 0x0000000000000034 0x0000000000000034 R 4
> GNU_STACK 0x0000000000000000 0x0000000000000000 0x0000000000000000
> 0x0000000000000000 0x0000000000000000 RW 10
>
> But ld.so says:
> % LD_SHOW_AUXV=1 ./a.out
> AT_SYSINFO_EHDR: 0x7fff0bb76000
> AT_HWCAP: bfe9fbff
> AT_PAGESZ: 4096
> AT_CLKTCK: 100
> AT_PHDR: 0x6fe00040
> AT_PHENT: 56
> AT_PHNUM: 8
> AT_BASE: 0x7fc226189000
> AT_FLAGS: 0x0
> AT_ENTRY: 0x70000210
> AT_UID: 1000
> AT_EUID: 1000
> AT_GID: 1000
> AT_EGID: 1000
> AT_SECURE: 0
> AT_RANDOM: 0x7fff0bb12ab9
> AT_EXECFN: ./a.out
> AT_PLATFORM: x86_64
>
> 0x6fe00040 != 0x0000000000200040
>
> So is readelf wrong or ld.so?
As said previously, the AT_PHDR address is provided by the kernel in
the aux vector. ld.so just uses this address and hasn't parsed the ELF
header at that point.
--
Aurelien Jarno GPG: 4096R/1DDD8C9B
aurelien@aurel32.net http://www.aurel32.net
Reply to: