Bug 25413 - VDSO not setup before `_dl_non_dynamic_init`
Summary: VDSO not setup before `_dl_non_dynamic_init`
Status: RESOLVED DUPLICATE of bug 24967
Alias: None
Product: glibc
Classification: Unclassified
Component: libc (show other bugs)
Version: 2.29
: P2 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2020-01-17 16:06 UTC by Erick Ochoa
Modified: 2020-01-21 08:07 UTC (History)
4 users (show)

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


Attachments
Possible fix (329 bytes, text/plain)
2020-01-17 16:06 UTC, Erick Ochoa
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Erick Ochoa 2020-01-17 16:06:38 UTC
Created attachment 12217 [details]
Possible fix

Hello,

jemalloc [0] is a malloc alternative that makes calls to `clock_gettime` in order to do memory profiling (and possibly other reasons). This means that uses of malloc [1] which happen before VDSO is setup will access invalid memory.

[0] https://github.com/jemalloc/jemalloc
[1] such as the ones in _dl_get_origin and _dl_new_object

### Minimal error

```bash
[eochoa@osprey1 temp]$ cat a.c
#include <stdlib.h>

int main( int argc, char **argv )
{
  malloc(0);
}
[eochoa@osprey1 temp]$ gcc -O0 -g a.c -ljemalloc -lpthread -static
[eochoa@osprey1 temp]$ ./a.out
Bus error (core dumped)
```

Please make sure 
* you are running on an aarch64 machine
* and that either glibc 2.29 is installed or you are linking against glibc 2.29 like so:

```
[eochoa@osprey1 temp]$ gcc -O0 -g a.c -ljemalloc -lpthread -static /path/to/libc.a
```

### Stack trace

Using gdb, I found the stack trace when SIGBUS was sent. Two interesting things to note is that the error is triggered when `__clock_gettime` is called and very early during the program, during `__libc_init_first` . 

```
#0  0x5efaf6adad3c47c6 in ?? ()
#1  0x00000000004cb914 in __clock_gettime (clock_id=6, tp=0xffffffffc400) at ../sysdeps/unix/sysv/linux/clock_gettime.c:33
#2  0x0000000000470b6c in nstime_get (time=0xffff80006b80) at src/nstime.c:119
#3  0x0000000000470bb8 in nstime_update_impl (time=0xffff80006b80) at src/nstime.c:160
#4  0x000000000042238c in arena_decay_reinit (decay=0xffff80006ab8, decay_ms=10000) at src/arena.c:672
#5  0x00000000004224b0 in arena_decay_init (decay=0xffff80006ab8, decay_ms=10000, stats=0xffff80000df0) at src/arena.c:693
#6  0x0000000000426298 in je_arena_new (tsdn=0x0, ind=0, extent_hooks=0x508200 <je_extent_hooks_default>) at src/arena.c:2043
#7  0x0000000000409fec in arena_init_locked (tsdn=0x0, ind=0, extent_hooks=0x508200 <je_extent_hooks_default>) at src/jemalloc.c:340      #8  0x000000000040a0b0 in je_arena_init (tsdn=0x0, ind=0, extent_hooks=0x508200 <je_extent_hooks_default>) at src/jemalloc.c:368
#9  0x000000000040f3a8 in malloc_init_hard_a0_locked () at src/jemalloc.c:1553
#10 0x000000000040fb04 in malloc_init_hard () at src/jemalloc.c:1750
#11 0x0000000000409b90 in malloc_init () at src/jemalloc.c:223
#12 0x0000000000410a88 in imalloc_init_check (sopts=0xffffffffe128, dopts=0xffffffffe0f0) at src/jemalloc.c:2229
#13 0x0000000000410bf4 in imalloc (sopts=0xffffffffe128, dopts=0xffffffffe0f0) at src/jemalloc.c:2260
#14 0x0000000000410d58 in je_malloc_default (size=19) at src/jemalloc.c:2289
#15 0x0000000000410ff8 in malloc (size=19) at src/jemalloc.c:2332
#16 0x00000000004f221c in _dl_get_origin () at ../sysdeps/unix/sysv/linux/generic/dl-origin.c:51
#17 0x00000000004ce6a4 in _dl_non_dynamic_init () at dl-support.c:308
#18 0x00000000004cf528 in __libc_init_first (argc=argc@entry=2, argv=argv@entry=0xfffffffff438, envp=0xfffffffff450)
    at ../csu/init-first.c:74
#19 0x00000000004b03ac in __libc_start_main (main=0x4006c4 <main>, argc=2, argv=0xfffffffff438, init=0x4b0840 <__libc_csu_init>,
    fini=0x4b0920 <__libc_csu_fini>, rtld_fini=0x0, stack_end=<optimized out>) at ../csu/libc-start.c:244
#20 0x000000000040058c in _start () at ../sysdeps/aarch64/start.S:92
```

### Bisecting glibc

I did a git bisect from glibc 2.28 to glibc 2.29 and found [the offending commit](https://sourceware.org/git/?p=glibc.git;a=commitdiff;h=979cfed05d0ee5a9d81d310ea1eb2d590739e36b;hp=ce035c6e909ad20ef2fe13c92eab4e69f6495b61)

Which enables VDSO for static linking. Since `clock_gettime` is part of VDSO this means that `clock_gettime` should be able to link statically as well.

### The problem

However, [`_dl_non_dynamic_init`](https://code.woboq.org/userspace/glibc/csu/init-first.c.html#74) which has a run time path to malloc is called before [VDSO](https://code.woboq.org/userspace/glibc/csu/init-first.c.html#78) has been setup.
Because malloc is now jemalloc, it will attempt to use `clock_gettime` which has not been setup properly.

### The possible solution

I'm filing a bug in glibc tracker to apply this patch. This makes the sample program run, however there is another [`setup_vdso`](https://code.woboq.org/userspace/glibc/elf/setup-vdso.h.html#20) function which (without the patch applied) is called before `VDSO_SETUP` and I am unsure about the interactions between them. Can you please clarify/review? Thanks!

```
diff --git a/csu/init-first.c b/csu/init-first.c
index 289373f9d8..330cc7d36c 100644
--- a/csu/init-first.c
+++ b/csu/init-first.c
@@ -68,16 +68,16 @@ _init (int argc, char **argv, char **envp)
   __libc_argv = argv;
   __environ = envp;

+#ifdef VDSO_SETUP
+  VDSO_SETUP ();
+#endif
+
 #ifndef SHARED
   /* First the initialization which normally would be done by the
      dynamic linker.  */
   _dl_non_dynamic_init ();
 #endif

-#ifdef VDSO_SETUP
-  VDSO_SETUP ();
-#endif
-
   __init_misc (argc, argv, envp);

   /* Initialize ctype data.  */
```
Comment 1 Adhemerval Zanella 2020-01-17 19:05:54 UTC
It will be fixed on 2.31 (1bdda52fe92fd01b424cd6fbb63e3df96a95015c).

*** This bug has been marked as a duplicate of bug 24967 ***