Linux高級調試與優化——Address Sanitizer


Address Sanitizer

  ASAN最早可以追溯到 LLVM 的 sanitizers項目(https://github.com/google/sanitizers),這個項目包含了AddressSanitizer,MemorySanitizer,ThreadSanitizer 和 LeakSanitizer等工具。這些工具可以檢測用戶空間的內存問題。通過在編譯時加入指定的選項,就可以給用戶程序加入 Address Sanitizer 功能。

  其中Address Sanitizer(ASAN)工具是一個內存錯誤檢測器,可以檢測以下問題:

  1)Out-of-bounds accesses to heap, stack and globals 堆、棧以及全局變量越界

  2)Use-after-free 即訪問dangling pointer,已經free的指針

  3)Use-after-return (to some extent)

  4)Double-free, invalid free

  5)Memory leaks (experimental)

  ASan基於shadow memory實現,目前已經集成到Clang 3.1和GCC 4.8以上版本。

 

編譯選項

  -fsanitize=address 使能Address Sanitizer工具

   -fsanitize=leak 只使能Leak Sanitizer,檢測內存泄漏問題

  -fno-omit-frame-pointer 檢測到內存錯誤時打印函數調用棧

  -O1 代碼優化選項,可以打印更清晰的函數調用棧

 

實例演示

1)棧溢出

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char **argv)
{
    int stack[100] = {0};

    stack[100] = 0xdeadbeef;

    return 0;
}

首先使用gcc stack-overflow.c -o stack-overflow編譯,然后用./stack-overflow執行
linyao@chgao-virtual-machine:~/debugging/asan$ gcc stack-overflow.c -o stack-overflow
linyao@chgao-virtual-machine:~/debugging/asan$ ./stack-overflow
linyao@chgao-virtual-machine:~/debugging/asan$

程序沒有任何報錯,沒有檢測到棧越界。

接下來集成ASAN編譯並執行,發現棧越界錯誤:

linyao@chgao-virtual-machine:~/debugging/asan$ gcc -fsanitize=address -fno-omit-frame-pointer stack-overflow.c -o stack-overflow
linyao@chgao-virtual-machine:~/debugging/asan$ ./stack-overflow =================================================================
==29781==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7ffc6c0f67a0 at pc 0x0000004008fb bp 0x7ffc6c0f65d0 sp 0x7ffc6c0f65c0
WRITE of size 4 at 0x7ffc6c0f67a0 thread T0
    #0 0x4008fa in main (/media/new/linyao/debugging/asan/stack-overflow+0x4008fa)
    #1 0x7fc449f7082f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)
    #2 0x400748 in _start (/media/new/linyao/debugging/asan/stack-overflow+0x400748)

Address 0x7ffc6c0f67a0 is located in stack of thread T0 at offset 432 in frame
    #0 0x400825 in main (/media/new/linyao/debugging/asan/stack-overflow+0x400825)

  This frame has 1 object(s):
    [32, 432) 'stack' <== Memory access at offset 432 overflows this variable
HINT: this may be a false positive if your program uses some custom stack unwind mechanism or swapcontext
      (longjmp and C++ exceptions *are* supported)
SUMMARY: AddressSanitizer: stack-buffer-overflow ??:0 main
Shadow bytes around the buggy address:
  0x10000d816ca0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x10000d816cb0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 f1 f1
  0x10000d816cc0: f1 f1 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x10000d816cd0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x10000d816ce0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x10000d816cf0: 00 00 00 00[f4]f4 f3 f3 f3 f3 00 00 00 00 00 00
  0x10000d816d00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x10000d816d10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x10000d816d20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x10000d816d30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x10000d816d40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
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
==29781==ABORTING

 

2)堆溢出

#include <stdio.h>
#include <stdlib.h>

#define HEAP_SIZE (100)

int main(int argc, char **argv)
{
    int *heap = NULL;

    heap = (int *)malloc(HEAP_SIZE * sizeof(int));
    if (NULL == heap)
      return -1;

    *(heap + HEAP_SIZE) = 0xdeadbeef;

    return 0;
}

編譯並執行:

linyao@chgao-virtual-machine:~/debugging/asan$ gcc -fsanitize=address -fno-omit-frame-pointer heap-overflow.c -o heap-overflow
linyao@chgao-virtual-machine:~/debugging/asan$ ./heap-overflow =================================================================
==31287==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x61400000ffd0 at pc 0x0000004007ab bp 0x7fffa2f87bd0 sp 0x7fffa2f87bc0
WRITE of size 4 at 0x61400000ffd0 thread T0
    #0 0x4007aa in main (/media/new/linyao/debugging/asan/heap-overflow+0x4007aa)
    #1 0x7fc8239b682f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)
    #2 0x400668 in _start (/media/new/linyao/debugging/asan/heap-overflow+0x400668)

0x61400000ffd0 is located 0 bytes to the right of 400-byte region [0x61400000fe40,0x61400000ffd0)
allocated by thread T0 here:
    #0 0x7fc823df8602 in malloc (/usr/lib/x86_64-linux-gnu/libasan.so.2+0x98602)
    #1 0x400756 in main (/media/new/linyao/debugging/asan/heap-overflow+0x400756)
    #2 0x7fc8239b682f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)

SUMMARY: AddressSanitizer: heap-buffer-overflow ??:0 main
Shadow bytes around the buggy address:
  0x0c287fff9fa0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c287fff9fb0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c287fff9fc0: fa fa fa fa fa fa fa fa 00 00 00 00 00 00 00 00
  0x0c287fff9fd0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c287fff9fe0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x0c287fff9ff0: 00 00 00 00 00 00 00 00 00 00[fa]fa fa fa fa fa
  0x0c287fffa000: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c287fffa010: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c287fffa020: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c287fffa030: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c287fffa040: 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
==31287==ABORTING

 

KASAN(Kernel Address Sanitizer)

  Andrey Ryabinin 借鑒了 AddressSanitizer 的思想,並在 Linux 內核中實現了 Kernel Address Sanitizer。所以 Kasan 也可以看成是用於內核空間的 Address Sanitizer。

  Kasan 是內核的一部分,使用時需要重新配置、編譯並安裝內核。Kasan 在 Linux 內核 4.0 版本時被引入內核,所以選擇的內核代碼需要高於 4.0 版本。另外,最基本的 Kasan 功能需要 GCC4.9.2 支持,更多的支持則需要 GCC5.0 及以上版本。

  Linux內核內存檢查工具還有kmemcheck。另外,也可以通過使能SLAB_DEBUG/SLUB_DEBUG/DEBUG_SLAB/DEBUG_PAGEALLOC等內核配置選項監控內存使用情況。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM