嵌入式Linux中文站

Kasan - Linux 内核的内存检测工具


Kernel address sanitizer (Kasan) 是一款随 Linux 内核代码一同发布和维护的内存检测工具,由内核社区维护和发展。本文简要介绍 Kasan 的原理及使用方法。

引言

Kasan 是 Kernel Address Sanitizer 的缩写,它是一个动态检测内存错误的工具,主要功能是检查内存越界访问和使用已释放的内存等问题。Kasan 集成在 Linux 内核中,随 Linux 内核代码一起发布,并由内核社区维护和发展。

背景

Kasan 可以追溯到 LLVM 的 sanitizers 项目(https://github.com/google/sanitizers),这个项目包含了 AddressSanitizer,MemorySanitizer,ThreadSanitizer 和 LeakSanitizer 等工具。但这些工具只能检测用户空间的内存问题。通过在编译时加入指定的选项,就可以给用户程序加入 Address Sanitizer 功能。

清单 1. 用户空间内存错误代码实例
 // To compile: g++ -O -g -fsanitize=address use-after-free.c 
 int main(int argc, char **argv) { 
  int *array = new int[10]; 
  delete [] array; 
  return array[argc];  // BOOM 
 }

当运行以上有内存使用错误的程序时,加入 Address Sanitizer 功能的的版本会报告如下的错误信息,而没有任何选项的版本则会正常结束程序。

清单 2. Address Sanitizer 运行结果
 tengrui@virtualbox:~/workspace/cc$ g++ -O -g -fsanitize=address use-after-free.cc 
 tengrui@virtualbox:~/workspace/cc$ ./a.out 
 ================================================================= 
 ==4206==ERROR: AddressSanitizer: heap-use-after-free on address 
 0x60400000dfd4 at pc 0x0000004007d4 bp 0x7ffdfdd414f0 sp 0x7ffdfdd414e0 
 READ of size 4 at 0x60400000dfd4 thread T0 
    #0 0x4007d3 in main /home/tengrui/workspace/cc/use-after-free.cc:4 
    #1 0x7f8aa150882f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f) 
    #2 0x4006b8 in _start (/home/tengrui/workspace/cc/a.out+0x4006b8) 

 0x60400000dfd4 is located 4 bytes inside of 40-byte region 
 [0x60400000dfd0,0x60400000dff8) 
 freed by thread T0 here: 
    #0 0x7f8aa194abca in operator delete[](void*) 
     (/usr/lib/x86_64-linux-gnu/libasan.so.2+0x99bca) 
    #1 0x4007a7 in main /home/tengrui/workspace/cc/use-after-free.cc:3 

 previously allocated by thread T0 here: 
    #0 0x7f8aa194a5d2 in operator new[](unsigned long) 
     (/usr/lib/x86_64-linux-gnu/libasan.so.2+0x995d2) 
    #1 0x400797 in main /home/tengrui/workspace/cc/use-after-free.cc:2 

 SUMMARY: AddressSanitizer: 
 heap-use-after-free /home/tengrui/workspace/cc/use-after-free.cc:4 main 
 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 
 ==4206==ABORTING

Andrey Ryabinin 借鉴了 AddressSanitizer 的思想,并在 Linux 内核中实现了 Kernel Address Sanitizer。所以 Kasan 也可以看成是用于内核空间的 Address Sanitizer。

原理

Kasan 的原理是利用“额外”的内存来标记那些可以被使用的内存的状态。这些做标记的区域被称为影子区域(shadow region)。了解 Linux 内存管理的读者知道,内存中的每个物理页在内存中都会有一个 struct page 这样的结构体来表示,即每 4KB 的页需要 40B 的结构体,大约 1% 的内存用来表示内存本身。Kasan 与其类似但“浪费”更为严重,影子区域的比例是 1:8,即总内存的九分之一会被“浪费”。用官方文档中的例子,如果有 128TB 的可用内存,需要有额外 16TB 的内存用来做标记。

做标记的方法比较简单,将可用内存按照 8 子节的大小分组,如果每组中所有 8 个字节都可以访问,则影子内存中相应的地方用全零(0x00)表示;如果可用内存的前 N(1 到 7 范围之间)个字节可用,则影子内存中响应的位置用 N 表示;其它情况影子内存用负数表示该内存不可用。

图 1. Kasan 内存布局原理

Kasan 内存布局原理

使用

Kasan 是内核的一部分,使用时需要重新配置、编译并安装内核。Kasan 在 Linux 内核 4.0 版本时被引入内核,所以选择的内核代码需要高于 4.0 版本。另外,最基本的 Kasan 功能需要 GCC4.9.2 支持,更多的支持则需要 GCC5.0 及以上版本。

首先是配置和编译内核。

运行如下命令启动图形配置界面:

清单 3. Linux 图形配置命令
 make menuconfig
图 2. Kasan 内核选项配置界面

Kasan 内核选项配置界面

图 3. Kasan 模式选项

Kasan 模式选项

然后重新编译并安装内核即可,除了通用的编译和安装命令,在 Fedora 这种发行版本中,还需要更新 grub。

清单 4. Linux 内核编译、安装命令
 make menuconfig 
 make 
 sudo make modules_install 
 sudo make install
清单 5. Grub 配置命令
 sudo grub2mkconfig – o /boot/grub/grub.cfg

其它发行版本请参考相关文档。

本文永久更新链接:http://embeddedlinux.org.cn/emb-linux/entry-level/201612/24-6018.html



分享:

评论