Stack overflow in dlopen (dlfcn/dlopen.c) ###### Glibc revision version : <= 2.34 ###### Build platform Ubuntu 18.10 LTS (Linux ubuntu 4.18.0-25-generic x86_64) ldd (Ubuntu GLIBC 2.28-0ubuntu1) 2.28 Ubuntu 20.04.1 LTS (Linux ubuntu 5.4.0-42-generic #46-Ubuntu x86_64) ldd (Ubuntu GLIBC 2.31-0ubuntu9) 2.31 ###### Build steps ``` gcc poc.c -ldl ``` ###### Test case poc.c ``` #include <stdio.h> #include <dlfcn.h> #include <string.h> char file[10000000]; int main() { memset(file,'A',10000000); void* handle = dlopen(file, 0x2); return 0; } ``` ###### Execution steps ``` $ ldd --version ldd (Ubuntu GLIBC 2.28-0ubuntu1) 2.28 Copyright (C) 2018 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Written by Roland McGrath and Ulrich Drepper. $ uname -a Linux ubuntu 4.18.0-25-generic #26-Ubuntu SMP Mon Jun 24 09:32:08 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux $ cat /etc/issue Ubuntu 18.10 \n \l $ lsb_release -a No LSB modules are available. Distributor ID: Ubuntu Description: Ubuntu 18.10 Release: 18.10 Codename: cosmic $ gcc poc.c -ldl $ ./a.out Segmentation fault (core dumped) $ gdb -q ./a.out Reading symbols from ./a.out...(no debugging symbols found)...done. (gdb) r Starting program: /home/test/Lua/a.out Program received signal SIGSEGV, Segmentation fault. 0x00007ffff7fdacf7 in open_path (name=name@entry=0x555555558040 <file> 'A' <repeats 200 times>..., namelen=namelen@entry=10000001, mode=mode@entry=-1879048190, sps=sps@entry=0x7ffff7ffc8d0 <rtld_search_dirs>, realname=realname@entry=0x7fffffffd780, fbp=fbp@entry=0x7fffffffd790, loader=0x7ffff7ffe190, whatcode=64, found_other_class=0x7fffffffd77f) at dl-load.c:2041 2041 dl-load.c: No such file or directory. (gdb) bt #0 0x00007ffff7fdacf7 in open_path (name=name@entry=0x555555558040 <file> 'A' <repeats 200 times>..., namelen=namelen@entry=10000001, mode=mode@entry=-1879048190, sps=sps@entry=0x7ffff7ffc8d0 <rtld_search_dirs>, realname=realname@entry=0x7fffffffd780, fbp=fbp@entry=0x7fffffffd790, loader=0x7ffff7ffe190, whatcode=64, found_other_class=0x7fffffffd77f) at dl-load.c:2041 #1 0x00007ffff7fdcd4e in _dl_map_object (loader=loader@entry=0x7ffff7ffe190, name=name@entry=0x555555558040 <file> 'A' <repeats 200 times>..., type=type@entry=2, trace_mode=trace_mode@entry=0, mode=mode@entry=-1879048190, nsid=<optimized out>) at dl-load.c:2388 #2 0x00007ffff7fe79c4 in dl_open_worker (a=a@entry=0x7fffffffdd00) at dl-open.c:228 #3 0x00007ffff7f1f48f in __GI__dl_catch_exception (exception=<optimized out>, operate=<optimized out>, args=<optimized out>) at dl-error-skeleton.c:196 #4 0x00007ffff7fe72c6 in _dl_open (file=0x555555558040 <file> 'A' <repeats 200 times>..., mode=-2147483646, caller_dlopen=0x555555555174 <main+47>, nsid=<optimized out>, argc=1, argv=0x7fffffffe058, env=0x7fffffffe068) at dl-open.c:599 #5 0x00007ffff7fae256 in dlopen_doit (a=a@entry=0x7fffffffdf20) at dlopen.c:66 #6 0x00007ffff7f1f48f in __GI__dl_catch_exception (exception=exception@entry=0x7fffffffdec0, operate=<optimized out>, args=<optimized out>) at dl-error-skeleton.c:196 #7 0x00007ffff7f1f51f in __GI__dl_catch_error (objname=0x7ffff7fb20f0 <last_result+16>, errstring=0x7ffff7fb20f8 <last_result+24>, mallocedp=0x7ffff7fb20e8 <last_result+8>, operate=<optimized out>, args=<optimized out>) at dl-error-skeleton.c:215 #8 0x00007ffff7faea25 in _dlerror_run (operate=operate@entry=0x7ffff7fae200 <dlopen_doit>, args=args@entry=0x7fffffffdf20) at dlerror.c:163 #9 0x00007ffff7fae2e6 in __dlopen (file=<optimized out>, mode=<optimized out>) at dlopen.c:87 #10 0x0000555555555174 in main () (gdb) x/3i $rip => 0x7ffff7fdacf7 <open_path+215>: callq 0x7ffff7ff3900 <mempcpy> 0x7ffff7fdacfc <open_path+220>: mov %rax,%r14 0x7ffff7fdacff <open_path+223>: lea -0xc0(%rbp),%rax (gdb) ``` ``` $ ldd --version ldd (Ubuntu GLIBC 2.31-0ubuntu9) 2.31 Copyright (C) 2020 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Written by Roland McGrath and Ulrich Drepper. $ uname -a Linux ubuntu 5.4.0-42-generic #46-Ubuntu SMP Fri Jul 10 00:24:02 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux $ cat /etc/issue Ubuntu 20.04.1 LTS \n \l $ lsb_release -a No LSB modules are available. Distributor ID: Ubuntu Description: Ubuntu 20.04.1 LTS Release: 20.04 Codename: focal $ gcc poc.c -ldl $ ./a.out Segmentation fault (core dumped) $ gdb -q ./a.out pwndbg> r Starting program: /home/test/Desktop/a.out Program received signal SIGSEGV, Segmentation fault. pwndbg> bt #0 0x00007ffff7fd7ac3 in ?? () from /lib64/ld-linux-x86-64.so.2 #1 0x00007ffff7fd9ae2 in ?? () from /lib64/ld-linux-x86-64.so.2 #2 0x00007ffff7fe4d37 in ?? () from /lib64/ld-linux-x86-64.so.2 #3 0x00007ffff7f22728 in __GI__dl_catch_exception (exception=<optimized out>, operate=<optimized out>, args=<optimized out>) at dl-error-skeleton.c:208 #4 0x00007ffff7fe45fa in ?? () from /lib64/ld-linux-x86-64.so.2 #5 0x00007ffff7fb234c in dlopen_doit (a=a@entry=0x7fffffffdf60) at dlopen.c:66 #6 0x00007ffff7f22728 in __GI__dl_catch_exception (exception=exception@entry=0x7fffffffdf00, operate=<optimized out>, args=<optimized out>) at dl-error-skeleton.c:208 #7 0x00007ffff7f227f3 in __GI__dl_catch_error (objname=0x7ffff7fb60f0 <last_result+16>, errstring=0x7ffff7fb60f8 <last_result+24>, mallocedp=0x7ffff7fb60e8 <last_result+8>, operate=<optimized out>, args=<optimized out>) at dl-error-skeleton.c:227 #8 0x00007ffff7fb2b59 in _dlerror_run (operate=operate@entry=0x7ffff7fb22f0 <dlopen_doit>, args=args@entry=0x7fffffffdf60) at dlerror.c:170 #9 0x00007ffff7fb23da in __dlopen (file=<optimized out>, mode=<optimized out>) at dlopen.c:87 #10 0x000055555555519c in main () #11 0x00007ffff7de60b3 in __libc_start_main (main=0x555555555169 <main>, argc=1, argv=0x7fffffffe0a8, init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>, stack_end=0x7fffffffe098) at ../csu/libc-start.c:308 #12 0x00005555555550ae in _start () pwndbg> x/3i $rip => 0x7ffff7fd7ac3: or QWORD PTR [rsp+0xff8],0x0 0x7ffff7fd7acc: cmp rsp,rax 0x7ffff7fd7acf: jne 0x7ffff7fd7abc ```
This is caused by the alloca in dl-load.c during pathname construction. We cannot trivially replace this with malloc because this allocation would leak most of the time because of the way free works for the dl-minimal.c malloc. I'm setting security- (no security impact) because the dlopen argument does not cross a trust boundary. -- Red Hat GmbH, https://de.redhat.com/ , Registered seat: Grasbrunn, Commercial register: Amtsgericht Muenchen, HRB 153243, Managing Directors: Charles Cachera, Brian Klemm, Laurie Krebs, Michael O'Neill
(In reply to Florian Weimer from comment #1) > This is caused by the alloca in dl-load.c during pathname construction. We > cannot trivially replace this with malloc because this allocation would leak > most of the time because of the way free works for the dl-minimal.c malloc. > > I'm setting security- (no security impact) because the dlopen argument does > not cross a trust boundary. > > -- > Red Hat GmbH, https://de.redhat.com/ , Registered seat: Grasbrunn, > Commercial register: Amtsgericht Muenchen, HRB 153243, > Managing Directors: Charles Cachera, Brian Klemm, Laurie Krebs, Michael > O'Neill I analyzed the availability of the problem and concluded that it would only cause a crash. I think it's a safety issue.
The dlopen path is definitely trusted, since arbitrary code will be executed from any library you dlopen (ELF constructors even if you never call any functions from the library). So this is an ordinary, non-security bug.