Bug 20857 - ldd and ld.so --verify is unreliable for position-dependent executables
Summary: ldd and ld.so --verify is unreliable for position-dependent executables
Status: NEW
Alias: None
Product: glibc
Classification: Unclassified
Component: dynamic-link (show other bugs)
Version: unspecified
: P2 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2016-11-23 10:25 UTC by Florian Weimer
Modified: 2020-02-12 03:14 UTC (History)
2 users (show)

See Also:
Host:
Target:
Build:
Last reconfirmed:
fweimer: security-


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Florian Weimer 2016-11-23 10:25:15 UTC
ld.so --verify on this program crashes (when compiled on x86_64):

char buffer[3ULL << 45];

int main (void)
{
}

Before running the following command, enable unlimited memory overcommit with vm.overcommit_memory=1.

$ gdb --args /lib64/ld-linux-x86-64.so.2 ./a.out 
…
(gdb) r
Starting program: /usr/lib64/ld-linux-x86-64.so.2 ./a.out

Program received signal SIGSEGV, Segmentation fault.
0x000055555556d4ba in mmap64 () at ../sysdeps/unix/syscall-template.S:84
84	T_PSEUDO (SYSCALL_SYMBOL, SYSCALL_NAME, SYSCALL_NARGS)
(gdb) disas
Dump of assembler code for function mmap64:
   0x000055555556d4b0 <+0>:	add    %al,(%rax)
   0x000055555556d4b2 <+2>:	add    %al,(%rax)
   0x000055555556d4b4 <+4>:	add    %al,(%rax)
   0x000055555556d4b6 <+6>:	add    %al,(%rax)
   0x000055555556d4b8 <+8>:	add    %al,(%rax)
=> 0x000055555556d4ba <+10>:	add    %al,(%rax)
   0x000055555556d4bc <+12>:	add    %al,(%rax)
   0x000055555556d4be <+14>:	add    %al,(%rax)
   0x000055555556d4c0 <+16>:	add    %al,(%rax)
   0x000055555556d4c2 <+18>:	add    %al,(%rax)
   0x000055555556d4c4 <+20>:	add    %al,(%rax)
   0x000055555556d4c6 <+22>:	add    %al,(%rax)
   0x000055555556d4c8 <+24>:	add    %al,(%rax)
   0x000055555556d4ca <+26>:	add    %al,(%rax)
   0x000055555556d4cc <+28>:	add    %al,(%rax)
   0x000055555556d4ce <+30>:	add    %al,(%rax)
   0x000055555556d4d0 <+32>:	add    %al,(%rax)
   0x000055555556d4d2 <+34>:	add    %al,(%rax)
End of assembler dump.
(gdb) 

The opcodes correspond to NUL bytes, so the mmap system call stub itself has been over-mapped.

Due to ASLR, this can happen randomly with much smaller executables.
Comment 1 Florian Weimer 2016-11-23 11:29:53 UTC
Reportedly, this affects ldd as well.
Comment 2 rschiron 2019-12-02 10:20:43 UTC
I cannot reproduce this with ldd.

Could you provide more details on how to compile the binary to reproduce the issue? I used `gcc -pie -ggdb ./test.c` but although it crashes when I execute the program, it does not crash when I run `ldd`.
Comment 3 Florian Weimer 2019-12-18 16:14:15 UTC
It looks like the kernel has changed the address space layout since I posted this.

Try this with vm.overcommit_memory=1:

char buffer[(128ULL << 40) - 0x500000];

int main (void)
{
}

I get:

openat(AT_FDCWD, "./a.out", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\2\0>\0\1\0\0\0 \20@\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0775, st_size=21760, ...}) = 0
getcwd("/tmp", 128)                     = 5
mmap(0x400000, 4096, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0) = 0x400000
mmap(0x401000, 4096, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1000) = 0x401000
mmap(0x402000, 4096, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x2000) = 0x402000
mmap(0x403000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x2000) = 0x403000
mmap(0x405000, 140737483108416, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x405000
--- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_ACCERR, si_addr=0x7f01bd2e2086} ---
+++ killed by SIGSEGV (core dumped) +++