Skip to content

Crash in patch_on_linkactivity when l_name not long enough for last_orig_name #227

Closed

Description

@nchaimov

The adios2 E4S test failure is triggered by Spack's padding of library paths with a large number of slashes. libadios2_core.so.2.12.1 has, among other dependencies,

NEEDED  //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////spack/opt/spack/linux-x86_64_v3/sqlite-3.53.1-zijikuhr4e5fgqqrd23672jmlpvsxya7/lib/libsqlite3.so

The conditions for the crash seem to be both that a library has a long name and that libc is loaded ahead of it. This can be reproduced with a simple example in the serial CI container:

spindleuser@spindlenode:~$ cat libfoo.c
int get_foo(void) {
   return 42;
}

spindleuser@spindlenode:~$ cat test.c
#include <stdio.h>

int get_foo(void);

int main(void) {
   int x = get_foo();
   printf("x = %d\n", x);
   return 0;
}
spindleuser@spindlenode:~$ gcc -g -o libfoo.so libfoo.c -shared -fPIC
spindleuser@spindlenode:~$ gcc -g -o test test.c -Wl,--no-as-needed -lc "$(printf '/%.0s' {1..200})"${PWD}/libfoo.so
spindleuser@spindlenode:~$ readelf -d ./test | grep NEEDED
 0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]
 0x0000000000000001 (NEEDED)             Shared library: [/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////home/spindleuser/libfoo.so]

spindleuser@spindlenode:~$ ./test
x = 42
spindleuser@spindlenode:~$ spindle --level=off ./test
x = 42
spindleuser@spindlenode:~$ spindle --level=low ./test
x = 42
spindleuser@spindlenode:~$ spindle --level=medium ./test
spindleuser@spindlenode:~$ ls core.*
core.test.333

libc has to come before the library to reproduce the problem. If it comes after, there is no crash:

spindleuser@spindlenode:~$ gcc -g -o test_libc_after test.c -Wl,--no-as-needed  "$(printf '/%.0s' {1..200})"${PWD}/libfoo.so -lc
spindleuser@spindlenode:~$ spindle --level=medium  ./test_libc_after
x = 42
spindleuser@spindlenode:~$ spindle --level=high  ./test_libc_after
x = 42

The backtrace is:

#0  0x0000000000028330 in ?? ()
#1  0x000076ea6b80ff59 in ptmalloc_init () at ./malloc/arena.c:300
#2  0x000076ea6b813965 in ptmalloc_init () at ./malloc/arena.c:264
#3  __GI___libc_malloc (bytes=bytes@entry=229) at ./malloc/malloc.c:3302
#4  0x000076ea6bc99f38 in patch_on_linkactivity (lmap=lmap@entry=0x76ea6b979580) at /home/spindleuser/Spindle/src/client/subaudit/../auditclient/patch_linkmap.c:69
#5  0x000076ea6bc98fc7 in spindle_la_objopen (map=0x76ea6b979580, lmid=<optimized out>, cookie=<optimized out>) at /home/spindleuser/Spindle/src/client/auditclient/auditclient.c:58
#6  0x000076ea6bcf3c0c in _dl_audit_objopen (l=l@entry=0x76ea6b979580, nsid=nsid@entry=0) at ./elf/dl-audit.c:87
#7  0x000076ea6bce1988 in _dl_map_object_from_fd (name=name@entry=0x76ea6b97fe20 "/tmp/commpath/cachepath/spindle.201730c4a8acde67/home/spindleuser/1-spindlens-file-libfoo.so", origname=origname@entry=0x62106851a518 '/' <repeats 200 times>..., fd=-1,
    fbp=fbp@entry=0x7ffc1d6dfe90, realname=<optimized out>, loader=loader@entry=0x76ea6bd122e0, l_type=<optimized out>, mode=<optimized out>, stack_endp=<optimized out>, nsid=<optimized out>) at ./elf/dl-load.c:1515
#8  0x000076ea6bce2529 in _dl_map_object (loader=<optimized out>, name=0x76ea6b97fe20 "/tmp/commpath/cachepath/spindle.201730c4a8acde67/home/spindleuser/1-spindlens-file-libfoo.so", type=1, trace_mode=<optimized out>, mode=0, nsid=<optimized out>)
    at ./elf/dl-load.c:2268
#9  0x000076ea6bcdba2d in openaux (a=a@entry=0x7ffc1d6e0460) at ./elf/dl-deps.c:64
#10 0x000076ea6bcda51c in __GI__dl_catch_exception (exception=exception@entry=0x7ffc1d6e0440, operate=operate@entry=0x76ea6bcdb9f0 <openaux>, args=args@entry=0x7ffc1d6e0460) at ./elf/dl-catch.c:237
#11 0x000076ea6bcdbe67 in _dl_map_object_deps (map=map@entry=0x76ea6bd122e0, preloads=preloads@entry=0x0, npreloads=<optimized out>, trace_mode=<optimized out>, open_mode=open_mode@entry=0) at ./elf/dl-deps.c:232
#12 0x000076ea6bcfb41c in dl_main (phdr=<optimized out>, phnum=<optimized out>, user_entry=<optimized out>, auxv=<optimized out>) at ./elf/rtld.c:1965
#13 0x000076ea6bcf7f46 in _dl_sysdep_start (start_argptr=start_argptr@entry=0x7ffc1d6e0ca0, dl_main=dl_main@entry=0x76ea6bcf9af0 <dl_main>) at ../sysdeps/unix/sysv/linux/dl-sysdep.c:140
#14 0x000076ea6bcf975e in _dl_start_final (arg=0x7ffc1d6e0ca0) at ./elf/rtld.c:494
#15 _dl_start (arg=0x7ffc1d6e0ca0) at ./elf/rtld.c:581
#16 0x000076ea6bcf8548 in _start () from /lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
#17 0x0000000000000001 in ?? ()
#18 0x00007ffc1d6e261c in ?? ()
#19 0x0000000000000000 in ?? ()

The relevant code is:

void patch_on_linkactivity(struct link_map *lmap)
{
size_t len;
char *oname;
if (!last_rewritten_name || !last_orig_name)
return;
if (lmap->l_name == last_rewritten_name ||
lmap->l_name == ldso_path ||
strcmp(lmap->l_name, last_rewritten_name) == 0 ||
strcmp(lmap->l_name, ldso_path) == 0)
{
debug_printf3("Replacing name %s with name %s\n", lmap->l_name, last_orig_name);
if (strlen(lmap->l_name) >= strlen(last_orig_name)) {
strcpy(lmap->l_name, last_orig_name);
}
else {
malloc_sig_t app_malloc = get_libc_malloc();
if (app_malloc) {
len = strlen(last_orig_name) + 2;
oname = (char *) app_malloc(len);
if (oname) {
strncpy(oname, last_orig_name, len);
lmap->l_name = oname;
}
}
}
}
else {
debug_printf3("Did not replace name %s with name %s\n", lmap->l_name ? : "NULL", last_orig_name ? : "NULL");
}
spindle_free(last_orig_name);
last_rewritten_name = NULL;
last_orig_name = NULL;
}

For the non-crashing case where libc comes after the long-name library, get_libc_malloc() returns NULL and the malloc is skipped. Where libc comes before the long-name library get_libc_malloc() returns the address to libc's malloc and new memory for a copy of last_orig_name is allocated, and there is a crash inside malloc.

While this also involves using the libc malloc, this is different than what is seen in #226 as no alternate malloc implementation is used here — both Spindle and the application are using the libc malloc.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions