Issue 181388
Summary Sanitizer interception of deprecated symbols is incompatible with dlopen (plugins)
Labels new issue
Assignees
Reporter kirelagin
    _(I am focusing on ASAN in the description but, I believe, all sanitizers are affected the same way.)_

At the core is a fundamental limitation of how interception interacts with loading objects via dlopen (e.g. plugins).  
Here is a simplified reproducer:

```c
// plugin.c:

#include <rpc/xdr.h>
#include <stdio.h>

void foo() {
  XDR xdrs;
  xdrstdio_create(&xdrs, stdin, XDR_ENCODE);
  xdr_destroy(&xdrs);
 printf("OK\n");
}
```

```c
// main.c:

#include <assert.h>
#include <dlfcn.h>

typedef void*(*foo_t)();

int main() {
 void *handle = dlopen("./plugin.so", RTLD_LAZY);
  assert(handle);
  void *foo = dlsym(handle, "foo");
  assert(foo);
  ((foo_t)foo)();
  return 0;
}
```

(This requires the `libtirpc` package, which is where the deprecated symbol has been moved to.)

```shell_session
$ clang -ltirpc -fpic -shared plugin.c -o plugin.so
$ clang main.c -o main
$ ./main
OK
$ clang -fsanitize=address main.c -o main
$ ./main
AddressSanitizer:DEADLYSIGNAL
=================================================================
==2735207==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000000 (pc 0x000000000000 bp 0x7fffffffb570 sp 0x7fffffffad38 T0)
==2735207==Hint: pc points to the zero page.
==2735207==The signal is caused by a READ memory access.
==2735207==Hint: address points to the zero page.
    #0 0x000000000000  (<unknown module>)
    #1 0x7ffff78b013c (plugin.so+0x113c)
    #2 0x5555556bbd46  (/tmp/main+0x167d46)
    #3 0x7ffff7cc127d (/nix/store/<hash>-glibc-2.40-36/lib/libc.so.6+0x2a27d)

==2735207==Register values:
rax = 0x0000000000000001  rbx = 0x00007fffffffb580  rcx = 0x0000000000000000  rdx = 0x0000000000000000  
rdi = 0x00007fffffffb580  rsi = 0x00007ffff7e818e0  rbp = 0x00007fffffffb570  rsp = 0x00007fffffffad38  
 r8 = 0x0000000000000000   r9 = 0x0000000000000000  r10 = 0x0000000000000000 r11 = 0x000055555559cd31  
r12 = 0x0000000000000000  r13 = 0x00007fffffffb708  r14 = 0x00007ffff7ffd000  r15 = 0x00005555556f8790 
AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV (<unknown module>) 
==2735207==ABORTING
```

Here is why this is happening:

1. On startup, `libclang_rt.asan` resolves the corresponding real functions for its interceptors.
2. The `xdrstdio_create` function has been deprecated in glibc, so `dlsym` returns nullptr.
3. `plugin.so` is loaded using `dlopen`; among its dependencies is `libtirpc.so`, which provides the symbol now.
4. The function in the plugin tries to call `xdrstdio_create`, the call is intercepted, and `___interceptor_xdrstdio_create` crashes calling nullptr.

_(Note: This only crashes with glibc >= 2.36. In earlier versions, `dlsym` in step 2 was returning the deprecated symbol, which is, arguably, even worse than a crash: #133338)._

This is Clang 19.1.6, but, judging by the code, I believe this should be reproducible in `main` as well.

One possible short-term solution would be to resolve the exact versions of the deprecated functions.
This would work as expected for legacy binaries, however new binaries (e.g. libnss_nis/libnsl) will end up with their calls being dispatched to unexpected versions of the symbols under sanitizers.

Probably a better quick solution is to remove the interceptors and accept potential false positive as a result.

Looking at the whole picture, this appears to be a fundamental limitation of how interceptors currently work.
I see two possible radical fixes:

1. Intercept `dlopen` and re-scan the symbols for any new real symbols to dispatch to (tricky).
2. Instead of eagerly resolving all real call targets on startup, postpone the `dlsym` invocation until the first actual call for each symbol (slower?).

Or, maybe, as a middle ground, keep resolving symbols at startup, but re-resolve if it is nullptr at the time it is about to be called.
_______________________________________________
llvm-bugs mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-bugs

Reply via email to