zoukankan      html  css  js  c++  java
  • 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等内核配置选项监控内存使用情况。

  • 相关阅读:
    1-Java基础回顾整理_06_数组
    1-Java基础回顾整理_05_方法
    1-Java基础回顾整理_04_交互、循环、关键字
    1-Java基础回顾整理_03_类型、变量、运算符
    1-Java基础回顾整理_02_java介绍
    1-Java基础回顾整理_01_计算机发展史
    整合SSM
    Spring整合Mybatis--xml配置文件方式
    java设计模式之动态代理
    Mybatis之动态sql
  • 原文地址:https://www.cnblogs.com/justin-y-lin/p/11314059.html
Copyright © 2011-2022 走看看