Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ASan misses use after free #652

Closed
kostyaorkostya opened this issue Feb 2, 2016 · 5 comments
Closed

ASan misses use after free #652

kostyaorkostya opened this issue Feb 2, 2016 · 5 comments

Comments

@kostyaorkostya
Copy link

ASan can't catch use after free in the following case:

#include <string>
#include <cstdio>

int main() {
    const char* c = nullptr;

    {
        std::string s1("Hello world!");
        c = s1.c_str();
    }

    printf("%s\n", c);
    return 0;
}

Compilation command:

clang++ -O0 -g -fsanitize=address -fno-omit-frame-pointer main.cpp

I'm using Mac OS 10.10.5, Clang version info:

$ clang++ --version
Apple LLVM version 7.0.2 (clang-700.1.81)
Target: x86_64-apple-darwin14.5.0
Thread model: posix

otool -vtV output on produced binary:

./a.out:
(__TEXT,__text) section
_main:
0000000100000870    pushq   %rbp
0000000100000871    movq    %rsp, %rbp
0000000100000874    pushq   %rbx
0000000100000875    andq    $-0x20, %rsp
0000000100000879    subq    $0x1a0, %rsp            ## imm = 0x1A0
0000000100000880    movq    %rsp, %rbx
0000000100000883    xorl    %eax, %eax
0000000100000885    movl    %eax, %ecx
0000000100000887    movq    0x772(%rip), %rdx       ## literal pool symbol address: ___asan_option_detect_stack_use_after_return
000000010000088e    movq    0x773(%rip), %rsi       ## literal pool symbol address: ___stack_chk_guard
0000000100000895    movq    (%rsi), %rsi
0000000100000898    movq    %rsi, 0x180(%rbx)
000000010000089f    cmpl    $0x0, (%rdx)
00000001000008a5    movq    %rcx, 0x88(%rbx)
00000001000008ac    je  0x1000008c5
00000001000008b2    movl    $0xa0, %eax
00000001000008b7    movl    %eax, %edi
00000001000008b9    callq   0x100000dfc             ## symbol stub for: ___asan_stack_malloc_2
00000001000008be    movq    %rax, 0x88(%rbx)
00000001000008c5    movq    0x88(%rbx), %rax
00000001000008cc    cmpq    $0x0, %rax
00000001000008d2    movq    %rax, %rcx
00000001000008d5    movq    %rax, 0x80(%rbx)
00000001000008dc    movq    %rcx, 0x78(%rbx)
00000001000008e0    jne 0x1000008fa
00000001000008e6    movq    %rsp, %rax
00000001000008e9    addq    $-0xa0, %rax
00000001000008ef    andq    $-0x20, %rax
00000001000008f3    movq    %rax, %rsp
00000001000008f6    movq    %rax, 0x78(%rbx)
00000001000008fa    movq    0x78(%rbx), %rax
00000001000008fe    movabsq $-0xcffffff0d0d0e00, %rcx ## imm = 0xF3000000F2F2F200
0000000100000908    movabsq $-0xd0d0dff0e0e0e0f, %rdx ## imm = 0xF2F2F200F1F1F1F1
0000000100000912    leaq    _main(%rip), %rsi
0000000100000919    leaq    0x629(%rip), %rdi       ## literal pool for: "3 32 8 0  64 8 0  96 24 2 s1"
0000000100000920    movq    %rax, %r8
0000000100000923    addq    $0x20, %r8
000000010000092a    movq    %rax, %r9
000000010000092d    addq    $0x40, %r9
0000000100000934    movq    %rax, %r10
0000000100000937    addq    $0x60, %r10
000000010000093e    movq    $0x41b58ab3, (%rax)     ## imm = 0x41B58AB3
0000000100000945    movq    %rdi, 0x8(%rax)
0000000100000949    movq    %rsi, 0x10(%rax)
000000010000094d    movq    %rax, %rsi
0000000100000950    shrq    $0x3, %rsi
0000000100000954    movabsq $0x100000000000, %rdi   ## imm = 0x100000000000
000000010000095e    orq %rdi, %rsi
0000000100000961    movq    %rdx, (%rsi)
0000000100000964    movq    %rcx, 0x8(%rsi)
0000000100000968    movl    $0xf3f3f3f3, 0x10(%rsi) ## imm = 0xF3F3F3F3
000000010000096f    movl    $0x0, 0x9c(%rbx)
0000000100000979    movq    %r8, 0xa8(%rbx)
0000000100000980    movq    $-0x1, 0xa0(%rbx)
000000010000098b    movq    0xa8(%rbx), %rcx
0000000100000992    movq    0xa0(%rbx), %rdx
0000000100000999    movq    %rcx, 0xb8(%rbx)
00000001000009a0    movq    %rdx, 0xb0(%rbx)
00000001000009a7    movq    0xb8(%rbx), %rcx
00000001000009ae    movq    %rcx, %rdx
00000001000009b1    shrq    $0x3, %rdx
00000001000009b5    movabsq $0x100000000000, %rdi   ## imm = 0x100000000000
00000001000009bf    orq %rdi, %rdx
00000001000009c2    movb    (%rdx), %r11b
00000001000009c5    cmpb    $0x0, %r11b
00000001000009c9    movq    %rax, 0x70(%rbx)
00000001000009cd    movq    %r8, 0x68(%rbx)
00000001000009d1    movq    %rsi, 0x60(%rbx)
00000001000009d5    movq    %r9, 0x58(%rbx)
00000001000009d9    movq    %r10, 0x50(%rbx)
00000001000009dd    movq    %rcx, 0x48(%rbx)
00000001000009e1    je  0x1000009f0
00000001000009e7    movq    0x48(%rbx), %rdi
00000001000009eb    callq   0x100000df6             ## symbol stub for: ___asan_report_store8
00000001000009f0    movq    0x48(%rbx), %rax
00000001000009f4    movq    $0x0, (%rax)
00000001000009fb    movq    0x68(%rbx), %rcx
00000001000009ff    shrq    $0x3, %rcx
0000000100000a03    movabsq $0x100000000000, %rdx   ## imm = 0x100000000000
0000000100000a0d    orq %rdx, %rcx
0000000100000a10    cmpb    $0x0, (%rcx)
0000000100000a13    je  0x100000a22
0000000100000a19    movq    0x68(%rbx), %rdi
0000000100000a1d    callq   0x100000df0             ## symbol stub for: ___asan_report_load8
0000000100000a22    movq    0x68(%rbx), %rax
0000000100000a26    movq    (%rax), %rcx
0000000100000a29    movq    0x58(%rbx), %rdx
0000000100000a2d    shrq    $0x3, %rdx
0000000100000a31    movabsq $0x100000000000, %rsi   ## imm = 0x100000000000
0000000100000a3b    orq %rsi, %rdx
0000000100000a3e    cmpb    $0x0, (%rdx)
0000000100000a41    movq    %rcx, 0x40(%rbx)
0000000100000a45    je  0x100000a54
0000000100000a4b    movq    0x58(%rbx), %rdi
0000000100000a4f    callq   0x100000df6             ## symbol stub for: ___asan_report_store8
0000000100000a54    leaq    _.str(%rip), %rax
0000000100000a5b    movq    0x58(%rbx), %rcx
0000000100000a5f    movq    0x40(%rbx), %rdx
0000000100000a63    movq    %rdx, (%rcx)
0000000100000a66    movq    %rcx, 0x178(%rbx)
0000000100000a6d    movq    $0x0, 0x90(%rbx)
0000000100000a78    movq    0x50(%rbx), %rsi
0000000100000a7c    movq    %rsi, 0x140(%rbx)
0000000100000a83    movq    %rax, 0x138(%rbx)
0000000100000a8a    movq    0x140(%rbx), %rax
0000000100000a91    movq    0x138(%rbx), %rdi
0000000100000a98    movq    %rax, 0x150(%rbx)
0000000100000a9f    movq    %rdi, 0x148(%rbx)
0000000100000aa6    movq    0x150(%rbx), %rax
0000000100000aad    movq    %rax, 0x158(%rbx)
0000000100000ab4    movq    0x158(%rbx), %rdi
0000000100000abb    movq    %rdi, 0x160(%rbx)
0000000100000ac2    movq    0x160(%rbx), %rdi
0000000100000ac9    movq    %rdi, 0x168(%rbx)
0000000100000ad0    movq    0x168(%rbx), %rdi
0000000100000ad7    movq    %rdi, 0x170(%rbx)
0000000100000ade    movq    0x148(%rbx), %rsi
0000000100000ae5    movq    0x148(%rbx), %rdi
0000000100000aec    movq    %rsi, 0x38(%rbx)
0000000100000af0    movq    %rax, 0x30(%rbx)
0000000100000af4    callq   0x100000dcc             ## symbol stub for: __ZNSt3__111char_traitsIcE6lengthEPKc
0000000100000af9    movq    0x30(%rbx), %rdi
0000000100000afd    movq    0x38(%rbx), %rsi
0000000100000b01    movq    %rax, %rdx
0000000100000b04    callq   0x100000dd2             ## symbol stub for: __ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE6__initEPKcm
0000000100000b09    movq    0x50(%rbx), %rax
0000000100000b0d    movq    %rax, 0xc0(%rbx)
0000000100000b14    movq    0xc0(%rbx), %rcx
0000000100000b1b    movq    %rcx, 0xc8(%rbx)
0000000100000b22    movq    0xc8(%rbx), %rcx
0000000100000b29    movq    %rcx, 0xd0(%rbx)
0000000100000b30    movq    0xd0(%rbx), %rcx
0000000100000b37    movq    %rcx, 0xd8(%rbx)
0000000100000b3e    movq    0xd8(%rbx), %rdx
0000000100000b45    movq    %rdx, 0xe0(%rbx)
0000000100000b4c    movq    0xe0(%rbx), %rdx
0000000100000b53    movq    %rdx, 0xe8(%rbx)
0000000100000b5a    movq    0xe8(%rbx), %rdx
0000000100000b61    movq    %rdx, %rsi
0000000100000b64    shrq    $0x3, %rsi
0000000100000b68    movabsq $0x100000000000, %rdi   ## imm = 0x100000000000
0000000100000b72    orq %rdi, %rsi
0000000100000b75    movb    (%rsi), %r8b
0000000100000b78    cmpb    $0x0, %r8b
0000000100000b7c    movq    %rcx, 0x28(%rbx)
0000000100000b80    movq    %rdx, 0x20(%rbx)
0000000100000b84    movb    %r8b, 0x1f(%rbx)
0000000100000b88    je  0x100000bae
0000000100000b8e    movq    0x20(%rbx), %rax
0000000100000b92    andq    $0x7, %rax
0000000100000b98    movb    %al, %cl
0000000100000b9a    movb    0x1f(%rbx), %dl
0000000100000b9d    cmpb    %dl, %cl
0000000100000b9f    jl  0x100000bae
0000000100000ba5    movq    0x20(%rbx), %rdi
0000000100000ba9    callq   0x100000dea             ## symbol stub for: ___asan_report_load1
0000000100000bae    movq    0x20(%rbx), %rax
0000000100000bb2    movzbl  (%rax), %ecx
0000000100000bb5    andl    $0x1, %ecx
0000000100000bbb    cmpl    $0x0, %ecx
0000000100000bc1    je  0x100000c36
0000000100000bc7    movq    0x28(%rbx), %rax
0000000100000bcb    movq    %rax, 0x118(%rbx)
0000000100000bd2    movq    0x118(%rbx), %rcx
0000000100000bd9    movq    %rcx, 0x120(%rbx)
0000000100000be0    movq    0x120(%rbx), %rcx
0000000100000be7    movq    %rcx, 0x128(%rbx)
0000000100000bee    movq    0x128(%rbx), %rcx
0000000100000bf5    addq    $0x10, %rcx
0000000100000bfc    movq    %rcx, %rdx
0000000100000bff    shrq    $0x3, %rdx
0000000100000c03    movabsq $0x100000000000, %rsi   ## imm = 0x100000000000
0000000100000c0d    orq %rsi, %rdx
0000000100000c10    cmpb    $0x0, (%rdx)
0000000100000c13    movq    %rcx, 0x10(%rbx)
0000000100000c17    je  0x100000c26
0000000100000c1d    movq    0x10(%rbx), %rdi
0000000100000c21    callq   0x100000df0             ## symbol stub for: ___asan_report_load8
0000000100000c26    movq    0x10(%rbx), %rax
0000000100000c2a    movq    (%rax), %rcx
0000000100000c2d    movq    %rcx, 0x8(%rbx)
0000000100000c31    jmp 0x100000c8b
0000000100000c36    movq    0x28(%rbx), %rax
0000000100000c3a    movq    %rax, 0xf0(%rbx)
0000000100000c41    movq    0xf0(%rbx), %rcx
0000000100000c48    movq    %rcx, 0xf8(%rbx)
0000000100000c4f    movq    0xf8(%rbx), %rcx
0000000100000c56    movq    %rcx, 0x100(%rbx)
0000000100000c5d    movq    0x100(%rbx), %rcx
0000000100000c64    addq    $0x1, %rcx
0000000100000c6b    movq    %rcx, 0x108(%rbx)
0000000100000c72    movq    0x108(%rbx), %rcx
0000000100000c79    movq    %rcx, 0x110(%rbx)
0000000100000c80    movq    0x110(%rbx), %rcx
0000000100000c87    movq    %rcx, 0x8(%rbx)
0000000100000c8b    movq    0x8(%rbx), %rax
0000000100000c8f    movq    %rax, 0x130(%rbx)
0000000100000c96    movq    0x130(%rbx), %rax
0000000100000c9d    movq    %rax, 0x90(%rbx)
0000000100000ca4    movq    0x50(%rbx), %rdi
0000000100000ca8    callq   0x100000dd8             ## symbol stub for: __ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEED1Ev
0000000100000cad    leaq    _.str1(%rip), %rdi
0000000100000cb4    movq    0x90(%rbx), %rsi
0000000100000cbb    movb    $0x0, %al
0000000100000cbd    callq   0x100000e14             ## symbol stub for: _printf
0000000100000cc2    movq    0x70(%rbx), %rsi
0000000100000cc6    movq    $0x45e0360e, (%rsi)     ## imm = 0x45E0360E
0000000100000ccd    movq    0x80(%rbx), %rdi
0000000100000cd4    cmpq    $0x0, %rdi
0000000100000cdb    movl    %eax, 0x4(%rbx)
0000000100000cde    je  0x100000d17
0000000100000ce4    movabsq $-0xa0a0a0a0a0a0a0b, %rax ## imm = 0xF5F5F5F5F5F5F5F5
0000000100000cee    movq    0x60(%rbx), %rcx
0000000100000cf2    movq    %rax, (%rcx)
0000000100000cf5    movq    %rax, 0x8(%rcx)
0000000100000cf9    movq    %rax, 0x10(%rcx)
0000000100000cfd    movq    %rax, 0x18(%rcx)
0000000100000d01    movq    0x80(%rbx), %rax
0000000100000d08    movq    0xf8(%rax), %rdx
0000000100000d0f    movb    $0x0, (%rdx)
0000000100000d12    jmp 0x100000d31
0000000100000d17    movq    0x60(%rbx), %rax
0000000100000d1b    movq    $0x0, (%rax)
0000000100000d22    movq    $0x0, 0x8(%rax)
0000000100000d2a    movl    $0x0, 0x10(%rax)
0000000100000d31    movq    0x2d0(%rip), %rax       ## literal pool symbol address: ___stack_chk_guard
0000000100000d38    movq    (%rax), %rax
0000000100000d3b    cmpq    0x180(%rbx), %rax
0000000100000d42    jne 0x100000d51
0000000100000d48    xorl    %eax, %eax
0000000100000d4a    leaq    -0x8(%rbp), %rsp
0000000100000d4e    popq    %rbx
0000000100000d4f    popq    %rbp
0000000100000d50    retq
0000000100000d51    callq   0x100000e0e             ## symbol stub for: ___stack_chk_fail
0000000100000d56    nopw    %cs:(%rax,%rax)
_asan.module_ctor:
0000000100000d60    pushq   %rbp
0000000100000d61    movq    %rsp, %rbp
0000000100000d64    callq   0x100000dde             ## symbol stub for: ___asan_init
0000000100000d69    callq   0x100000e08             ## symbol stub for: ___asan_version_mismatch_check_v6
0000000100000d6e    leaq    ___unnamed_1(%rip), %rdi
0000000100000d75    movl    $0x2, %eax
0000000100000d7a    movl    %eax, %esi
0000000100000d7c    callq   0x100000de4             ## symbol stub for: ___asan_register_globals
0000000100000d81    popq    %rbp
0000000100000d82    retq
0000000100000d83    nopw    %cs:(%rax,%rax)
_asan.module_dtor:
0000000100000d90    pushq   %rbp
0000000100000d91    movq    %rsp, %rbp
0000000100000d94    leaq    ___unnamed_1(%rip), %rdi
0000000100000d9b    movl    $0x2, %eax
0000000100000da0    movl    %eax, %esi
0000000100000da2    callq   0x100000e02             ## symbol stub for: ___asan_unregister_globals
0000000100000da7    popq    %rbp
0000000100000da8    retq
0000000100000da9    nop
0000000100000daa    nop
0000000100000dab    nop
0000000100000dac    nop
0000000100000dad    nop
0000000100000dae    nop
0000000100000daf    nop
__ZNSt3__111char_traitsIcE6lengthEPKc:
0000000100000db0    pushq   %rbp
0000000100000db1    movq    %rsp, %rbp
0000000100000db4    subq    $0x10, %rsp
0000000100000db8    movq    %rdi, -0x8(%rbp)
0000000100000dbc    movq    -0x8(%rbp), %rdi
0000000100000dc0    callq   0x100000e1a             ## symbol stub for: _strlen
0000000100000dc5    addq    $0x10, %rsp
0000000100000dc9    popq    %rbp
0000000100000dca    retq
@chefmax
Copy link

chefmax commented Feb 2, 2016

Works for me on current trunk on x86_64-unknown-linux-gnu:

max@max:/tmp$ clang++ -O0 -g -fsanitize=address -fno-omit-frame-pointer -std=c++11  test.cc 
max@max:/tmp$ ./a.out 
=================================================================
==25612==ERROR: AddressSanitizer: heap-use-after-free on address 0x60400000dfe8 at pc 0x000000433b31 bp 0x7ffdeb404bd0 sp 0x7ffdeb404390
READ of size 13 at 0x60400000dfe8 thread T0
    #0 0x433b30 in printf_common(void*, char const*, __va_list_tag*) /home/max/src/llvm/projects/compiler-rt/lib/asan/../sanitizer_common/sanitizer_common_interceptors_format.inc:545:9
    #1 0x4354ce in __interceptor_vprintf /home/max/src/llvm/projects/compiler-rt/lib/asan/../sanitizer_common/sanitizer_common_interceptors.inc:1115:1
    #2 0x4354ce in __interceptor_printf /home/max/src/llvm/projects/compiler-rt/lib/asan/../sanitizer_common/sanitizer_common_interceptors.inc:1161
    #3 0x4dcc9e in main /tmp/test.cc:12:5
    #4 0x7f4394690ec4 in __libc_start_main /build/buildd/eglibc-2.19/csu/libc-start.c:287
    #5 0x418c35 in _start (/tmp/a.out+0x418c35)

0x60400000dfe8 is located 24 bytes inside of 37-byte region [0x60400000dfd0,0x60400000dff5)
freed by thread T0 here:
    #0 0x4db1db in operator delete(void*) /home/max/src/llvm/projects/compiler-rt/lib/asan/asan_new_delete.cc:94:3
    #1 0x7f439563432e in std::string::_Rep::_M_dispose(std::allocator<char> const&) /build/buildd/gcc-4.8-4.8.4/build/x86_64-linux-gnu/libstdc++-v3/include/bits/basic_string.h:538
    #2 0x7f439563432e in std::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string() /build/buildd/gcc-4.8-4.8.4/build/x86_64-linux-gnu/libstdc++-v3/include/bits/basic_string.h:539
    #3 0x7f4394690ec4 in __libc_start_main /build/buildd/eglibc-2.19/csu/libc-start.c:287

previously allocated by thread T0 here:
    #0 0x4dac1b in operator new(unsigned long) /home/max/src/llvm/projects/compiler-rt/lib/asan/asan_new_delete.cc:62:35
    #1 0x7f4395634208 in __gnu_cxx::new_allocator<char>::allocate(unsigned long, void const*) /build/buildd/gcc-4.8-4.8.4/build/x86_64-linux-gnu/libstdc++-v3/include/ext/new_allocator.h:104
    #2 0x7f4395634208 in std::string::_Rep::_S_create(unsigned long, unsigned long, std::allocator<char> const&) /build/buildd/gcc-4.8-4.8.4/build/x86_64-linux-gnu/libstdc++-v3/include/bits/basic_string.tcc:607

SUMMARY: AddressSanitizer: heap-use-after-free /home/max/src/llvm/projects/compiler-rt/lib/asan/../sanitizer_common/sanitizer_common_interceptors_format.inc:545:9 in printf_common(void*, char const*, __va_list_tag*)
Shadow bytes around the buggy address:
  0x0c087fff9ba0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c087fff9bb0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c087fff9bc0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c087fff9bd0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c087fff9be0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
=>0x0c087fff9bf0: fa fa fa fa fa fa fa fa fa fa fd fd fd[fd]fd fa
  0x0c087fff9c00: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c087fff9c10: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c087fff9c20: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c087fff9c30: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c087fff9c40: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
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
  Heap right redzone:      fb
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack partial redzone:   f4
  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
==25612==ABORTING

@kostyaorkostya
Copy link
Author

How can I try to reproduce it with trunk? Would it be enough to build latest Clang?
Could ASan work different with libc++ and libstdc++?

@chefmax
Copy link

chefmax commented Feb 2, 2016

How can I try to reproduce it with trunk? Would it be enough to build latest Clang?

You'll need to build trunk LLVM, Clang and Compiler-rt. Please refer this page for more detailed instructions:
https://github.com/google/sanitizers/wiki/AddressSanitizerHowToBuild

@rnk
Copy link
Contributor

rnk commented Feb 2, 2016

My theory is that Mac libc++ is configured to use the "small string optimization", so the memory for the std::string is stored on the stack. ASan's use after scope functionality is not working currently, so ASan cannot detect this bug on Mac.

You can try to validate the theory by retrying the test with std::vector and see if ASan finds the bug.

@kcc
Copy link
Contributor

kcc commented Feb 2, 2016

In case of small string optimization we won't find a heap-use-after-free because there will be no such bug. Instead we'll have stack-use-after-scope which asan currently can not detect, see #83

@kcc kcc closed this as completed Feb 2, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants