原图

一般的内存访问错误如下。

  • 越界访问(out-of-bounds)
  • 访问已经被释放的内存(use after free)
  • 重复释放(double free)
  • 内存泄漏(memory leak)
  • 栈溢出(stack overflow)

本节主要介绍 Linux 内核中常用的内存检测的工具和方法。

slub_debug

在 Linux 内核中,对于小块内存分配,大量使用 slab/slub 分配器。slab/slub 分配器提供了一个内存检测功能,很方便在产品开发阶段进行内存检查。内存访问中比较容易出现错误的地方如下。

  • 访问己经被释放的内存
  • 越界访问
  • 释放己经释放过的内存

配置和编译内核

首先,需要重新配置内核选项,打开 CONFIG_SLUB、CONFIG_SLUB_DEBUG_ON 以及 CONFIG_SLUB_STATS 选项。

1
2
3
4
# CONFIG_SLAB is not set
CONFIG_SLUB=y
CONFIG_SLUB_DEBUG_ON=y
CONFIG_SLUB_STATS=y

修改了上述配置文件之后,需要重新编译内核并更新根文件系统。

添加 slub_debug 选项

在内核 commandline 中添加 slub_debug 字符串来打开该功能。

1
-append "nointrd root=/dev/vda rootfstype=ext4 rw loglevel=8 slub_debug=UFPZ" \

编译 slabinfo 工具

在 Linux-5.0 内核的 tools/vm 目录下编译 slabinfo 工具。

1
# gcc slabinfo.c -o slabinfo

运行

加载驱动或运行程序,启动 slabinfo:

1
$ slabinfo -v

之后如果有内存越界访问就会有异常 log 输出。

KASAN 内存检测

KASAN 在 Linux4.0 内核中被合并到官方 Linux 内核,他是一个动态检测内存错误的工具,可以检查内存越界访问和使用已经被释放的内存等问题。Linux 内核早期有一个类似的工具 kmemcheck,KASAN 比 kmemeheck 的检测速度更快。要使用 KASAN,必须打开 CONFIG_KASAN 等选项。

1
2
3
4
5
6
<arch/arm64/configs/debian_defconfig>
CONFIG_HAVE_ARCH_KASAN=y
CONFIG_KASAN=y
CONFIG_KASAN_OUTLINE=y
CONFIG_KASAN_INLINE=y
CONFIG_TEST_KASAN=m

使用起来比较简单,不需要像 slab_debug 一样还有单独运行 slabinfo 程序。KASAN 启动后会动态监测内存访问,如果出错会打印相关 log 信息。

KASAN 总体效率比 slub_debug 要高得多,并且支持的内存错误访问类型更多。缺点是 KASAN 需要较新的内核(Linx4.4 内核才支持 ARM64 版本的 KASAN)和较新的 GCC 编译 器(GCC-4.9.2 以上)。

参考文献

《奔跑吧 Linux 内核》