google / sanitizers

AddressSanitizer, ThreadSanitizer, MemorySanitizer
Other
11.01k stars 998 forks source link

Asan can't detect memory use after free error in dynamic shared library with LD_PRELOAD method #1743

Closed nope8 closed 2 months ago

nope8 commented 2 months ago

test environment: Ubuntu 22.04.1 LTS

AddressSanitizer FAQ: Q: I've built my shared library with ASan. Can I run it with unsanitized executable? A: Yes! You'll need to build your library with dynamic version of ASan and then run executable with LD_PRELOAD=path/to/asan/runtime/lib.

as show below I do test according to FAQ description, the result show that only print memory error when set compile/link option: -fsanitize=address on both dynamic so and excutable . please help to solve the issue, or point out where I'm wrong.

source code file: test.cpp:

int *get_ptr()
{
    int *ptr = new int[1024];
    return ptr;
}
void free_ptr(int *ptr)
{
    delete[] ptr;
}
void use_after_delete(int *ptr)
{
    ptr[8] = 42;
}

main.cpp:

#include <iostream>

int *get_ptr();
void free_ptr(int *ptr);
void use_after_delete(int *ptr);

int main()
{
    int *ptr = get_ptr();
    free_ptr(ptr);
    use_after_delete(ptr); 

    return 0;
}

build and run command

#command1:
g++ -c -fPIC test.cpp -o test.o -fsanitize=address -O1 -fno-omit-frame-pointer -g
g++ -shared -o libtest.so test.o -fsanitize=address -O1 -fno-omit-frame-pointer -g
g++ -o main main.cpp -L. -ltest 
./main LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libasan.so.6.0.0

output nothing

#command2:
g++ -c -fPIC test.cpp -o test.o -fsanitize=address -O1 -fno-omit-frame-pointer -g
g++ -shared -o libtest.so test.o -fsanitize=address -O1 -fno-omit-frame-pointer -g
g++ -o main main.cpp -L. -ltest -fsanitize=address -O1 -fno-omit-frame-pointer -g
./main

output:
=================================================================
==29456==ERROR: AddressSanitizer: heap-use-after-free on address 0x621000000120 at pc 0x7f406412b1fd bp 0x7fff3ceb1640 sp 0x7fff3ceb1630
WRITE of size 4 at 0x621000000120 thread T0
    #0 0x7f406412b1fc in use_after_delete(int*) /home/xlu/work/abc/test.cpp:15
    #1 0x563b2abd52ad in main /home/xlu/work/abc/main.cpp:11
    #2 0x7f4063bf8d8f in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58
    #3 0x7f4063bf8e3f in __libc_start_main_impl ../csu/libc-start.c:392
    #4 0x563b2abd51c4 in _start (/home/xlu/work/abc/main+0x11c4)

0x621000000120 is located 32 bytes inside of 4096-byte region [0x621000000100,0x621000001100)
freed by thread T0 here:
    #0 0x7f40641e5e37 in operator delete[](void*) ../../../../src/libsanitizer/asan/asan_new_delete.cpp:163
    #1 0x7f406412b1be in free_ptr(int*) /home/xlu/work/abc/test.cpp:11
    #2 0x563b2abd52a5 in main /home/xlu/work/abc/main.cpp:10
    #3 0x7f4063bf8d8f in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58

previously allocated by thread T0 here:
    #0 0x7f40641e5337 in operator new[](unsigned long) ../../../../src/libsanitizer/asan/asan_new_delete.cpp:102
    #1 0x7f406412b1aa in get_ptr() /home/xlu/work/abc/test.cpp:5
    #2 0x563b2abd529a in main /home/xlu/work/abc/main.cpp:9
    #3 0x7f4063bf8d8f in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58

SUMMARY: AddressSanitizer: heap-use-after-free /home/xlu/work/abc/test.cpp:15 in use_after_delete(int*)
Shadow bytes around the buggy address:
  0x0c427fff7fd0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c427fff7fe0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c427fff7ff0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c427fff8000: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c427fff8010: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
=>0x0c427fff8020: fd fd fd fd[fd]fd fd fd fd fd fd fd fd fd fd fd
  0x0c427fff8030: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x0c427fff8040: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x0c427fff8050: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x0c427fff8060: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x0c427fff8070: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
  Shadow gap:              cc
==29456==ABORTING
Enna1 commented 2 months ago
LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libasan.so.6.0.0 ./main
nope8 commented 2 months ago

Still can not print memory error: $ g++ -c -fPIC test.cpp -o test.o g++ -shared -o libtest.so test.o g++ -o main main.cpp -L. -ltest -O1 -fno-omit-frame-pointer -g LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libasan.so.6.0.0 ./main $

Enna1 commented 2 months ago

Sorry, I mean:

#command1:
g++ -c -fPIC test.cpp -o test.o -fsanitize=address -O1 -fno-omit-frame-pointer -g
g++ -shared -o libtest.so test.o -fsanitize=address -O1 -fno-omit-frame-pointer -g
g++ -o main main.cpp -L. -ltest 
LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libasan.so.6.0.0 ./main
nope8 commented 2 months ago

OK, successed, thank you very much.

nope8 commented 2 months ago

update clang++ compile progress command sample:

export LD_LIBRARY_PATH=/usr/lib/llvm-14/lib/clang/14.0.0/lib/linux/:./:$LD_LIBRARY_PATH
clang++ -c -fPIC test.cpp -o test.o -fsanitize=address -shared-libasan -O1 -fno-omit-frame-pointer -g
clang++ -shared -o libtest.so test.o -fsanitize=address -shared-libasan -O1 -fno-omit-frame-pointer -g
clang++ -o main main.cpp -L. -ltest 
LD_PRELOAD=/usr/lib/llvm-14/lib/clang/14.0.0/lib/linux/libclang_rt.asan-x86_64.so ./main
nope8 commented 2 months ago

FAQ: Q: Can I mix code instrumented by Clang with code instrumented by GCC? Or can I at least compile code with Clang and link against GCC ASan runtime and vice versa?

A: No, you cannot, Clang and GCC have completely incompatible ASan implementations, you cannot mix them in any way.

@Enna1 Can you help me to check if asan support below two scenario:

  1. g++ build to generate libtest.so with asan enable, then clang++ build main link with libtest.so
  2. clang++ build to generate libtest.so with asan enable, then g++ build main excutable link with libtest.so

Althogh I have tested they can work on libtest.so, but not sure if it will work on other complex sdk so instead of libtest.so.

# use g++ build libtest.so with asan enable,  then g++ build main link with libtest.so
g++ -c -fPIC test.cpp -o test.o -fsanitize=address -O1 -fno-omit-frame-pointer -g
g++ -shared -o libtest.so test.o -fsanitize=address -O1 -fno-omit-frame-pointer -g
clang++ -o main main.cpp -L. -ltest
LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libasan.so.6.0.0 ./main
# 
export LD_LIBRARY_PATH=/usr/lib/llvm-14/lib/clang/14.0.0/lib/linux/:./:$LD_LIBRARY_PATH
clang++ -c -fPIC test.cpp -o test.o -fsanitize=address -shared-libasan -O1 -fno-omit-frame-pointer -g
clang++ -shared -o libtest.so test.o -fsanitize=address -shared-libasan -O1 -fno-omit-frame-pointer -g
g++ -o main main.cpp -L. -ltest 
LD_PRELOAD=/usr/lib/llvm-14/lib/clang/14.0.0/lib/linux/libclang_rt.asan-x86_64.so ./main
Enna1 commented 2 months ago

@Enna1 Can you help me to check if asan support below two scenario:

  1. g++ build to generate libtest.so with asan enable, then clang++ build main link with libtest.so
  2. clang++ build to generate libtest.so with asan enable, then g++ build main excutable link with libtest.so

The short answer is NO, don't do this.

nope8 commented 2 months ago

Got it, thank you.