构架:ARMv8
内核版本:5.14.0-rc5
1显存检查机制简介
显存问题是c语言编程中出现机率最高,同时也最难定位的,因为内核线性映射区中连续的数学地址会被映射到连续的虚拟地址中,因而显存越界写操作很难被及时发觉。比如某个模块通过kmalloc分配了一块显存,当其执行写操作越界时,就可能会篡改另一个模块的数据。更糟糕的是此时系统并不会检查到这一情况,直至另一个模块访问到被篡改的数据后,问题才能曝露下来。
像以上这些问题会十分奇特,比如它可能使被篡改模块挂死,也可能使其功能异常。而当我们去检测这个被害模块的代码时,却完全找不到问题的诱因。若能通过一定的手段,及时便捷地找到肇事者,能够很容易地定位这类问题。
因此内核提供了多种不同的显存问题检查机制,包括slub_debug、kasan、kfence、vmalloc的guardpage、栈的canary保护、以及kmemleak等。它们的适用场景不一,但不仅kmemleak以外linux c 内存泄漏检测工具,它们的主要功能都是为了测量显存如下问题:
(1)显存访问越界
(2)访问释放后的显存
(3)重复释放显存
下边将分别简单介绍它们的使用方法
2slubdebug使用2.1打开如下内核选项
CONFIG_SLUB=y
CONFIG_SLUB_DEBUG=y
CONFIG_SLUB_DEBUG_ON=y
2.2添加命令行选项
在命令行选项中添加slub_debug=UFPZ,以使能相关检查功能,其涵义如下:
(1)U:跟踪该slab显存的相关属性,如其创建时所属的cpu、进程、时间
(2)F:开启sanity检测功能。该功能用于在slab的个别操作中(如slab分配和释放时),检查是否有对该slab的非法显存访问操作
(3)P:开启poisoning功能,它可被用于测量再度访问释放后的显存问题。当slab被释放后,slabobject本身显存将被填充为特定值。因而一旦其释放后再度访问该slablinux培训学校,则通过检测slab显存中的值是否被更改,即可检查到
(4)Z:开启redzoning功能,它可被用于测量显存越界访问问题。其会在slabobject的上面和旁边分别添加redzone,并在其被分配和被释放时,分别用不同的值填充。当发生访问越界时,就可以通过检测redzone的值测量到
2.3slubdebug检查
slubdebug在发生slab显存非法操作时,不能立刻测量下来。而须要自动通过sysfs的validate属性触发测量操作。如要检查128字节kmalloc对象,则可使用以下命令:
echo 1 > /sys/kernel/slab/kmalloc-128/validate
因为内核中的slab对象诸多,为了便捷操作系统中的所有slab对象,内核提供了一个slabinfo工具。该工具坐落tools/vm中,在arm64下可借助以下命令编译该工具:
aarch64-linux-gnu-gcc -o slabinfo slabinfo.c
若须要捕获slab显存访问错误问题,则可使用以下命令触发:
slabinfo –v
2.4slubdebug的缺点
由前面的剖析可知,slubdebug主要通过redzone和显存poison的形式,实现对显存越界、多次释放和释放后访问等问题的检查,但其也具有以下缺点:
(1)只能测量slab显存的问题,而未能测量全局变量、栈等显存的问题
(2)对于显存非法访问,不能立刻测量到,而是须要依赖于自动触发检查功能
3kasan的使用
鉴于slubdebug的问题,内核还支持了愈发全面的显存检查机制kasan。它是一个动态显存测量工具,通过编译时插桩的方法,在load、store中插入检查代码,实现了显存问题的即时监测。并且不仅slab显存之外,它还可以测量例如栈、全局变量和vamlloc显存问题
3.1打开如下内核选项
CONFIG_SLUB_DEBUG=y
CONFIG_SLUB_DEBUG_ON=y
CONFIG_KASAN=y
3.2工具链要求
为了支持no_sanitize_address功能,因而若要在5.14内核中支持KASAN,则gcc的版本必需要低于8.03,否则会造成内核编译失败。
以下为其相关定义(lib/Kconfig.kasan):
# This option is only required for software KASAN modes.
# Old GCC versions don't have proper support for no_sanitize_address.
# See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=89124 for details.
config CC_HAS_WORKING_NOSANITIZE_ADDRESS
def_bool !CC_IS_GCC || GCC_VERSION >= 80300
3.3kasan的异同点
kasan几乎能检查内核中所有的显存问题,是不折不扣的大杀器,然而这是以性能损失为代价的。如为了能测量到显存的违法访问问题,kasan会借助shadowmemory跟踪系统中的显存。它使用1个字节的空间来维护8个字节显存的状态,因而会有1/8的显存浪费。同时,因为在每位load/store操作中都加入了kasan检测代码,故也会影响cpu的执行效率。
因而kasan通常被用于开发阶段或产品发布前的测试,而不太适宜在实际生产环境中布署。其实因为kasan的强悍功能,若能在开发阶段较好地使用,应当就能否拦截大部份的显存问题。
4kfence的使用
因为kasan的资源开支太大,因而造成在生产环境下布署困难,因而内核又引入了一种低开支的显存检查机制kfence。它的原理很简单,kfence本身维护一个显存池,该显存池中的每位page都包含一个guardpage,即可用显存page和guardpage是交替分布的。
因为kfence显存池的容量有限,因而它对显存推行抽样检查。即kfence会启动一个timer,并把自己hook到内核的显存分配函数(如slab分配插口)中。在一个timer周期内,当其它模块调用显存分配插口时,其最多可从kfence池中分配一次显存。而这个从kfence池中分配的显存就被用于抽样检查,当其访问超过了page边界时,才能被kfence检查到。
4.1kfence的配置
CONFIG_KFENCE=y
CONFIG_KFENCE_SAMPLE_INTERVAL=xxx
KFENCE_NUM_OBJECTS=xxx
其中:
(1)CONFIG_KFENCE_SAMPLE_INTERVAL用于指定kfence的取样周期,其单位为ms
(2)KFENCE_NUM_OBJECTS用于指定kfence池中的object数目,其取值范围为1–65535
4.2kfence的异同点
kfence的优点为资源消耗小,可用于生产环境,缺点是使用了抽样检查机制,且测量细度为pagesize,因而测量结果只能碰运气。
5kmemleak使用
kmemleak主要用于检查内核的显存泄露问题,其基本原理是跟踪kmalloc、vmalloc以及kmem_cache_alloc等显存分配插口。将其所分配显存相关的表针、size等信息保存到kmemleak的黑红树中,当显存被释放后,就从黑红树中删掉其对应的节点。
即黑红树中的所有表针都是未被释放的,因而系统若要在将来释放那些显存,则其必需要保存该表针的值。因而kmemleak的检查机制十分简单,它会扫描系统中所有显存的值,并将其与自身黑红树中的表针比较。若某个表针在整个显存中都不存在linux rar,则表明系统早已未能释放它,相应地这块显存早已被泄露了。
5.1内核配置
CONFIG_SLUB_DEBUG=y
CONFIG_DEBUG_KMEMLEAK=y
CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF=n
CONFIG_DEBUG_KMEMLEAK_EARLY_LOG_SIZE=40000
5.2怎么触发kmemleak
(1)内核默认会周期性地执行扫描操作linux c 内存泄漏检测工具,其默认时间为10分钟
(2)通过debugfs自动触发扫描
(a)挂载debugfs
mount -t debugfs nodev /sys/kernel/debug/
(b)执行以下命令触发扫描
echo scan > /sys/kernel/debug/kmemleak
(3)查看显存泄露信息
cat /sys/kernel/debug/kmemleak
5.3kmemleak的异同点
与其它显存非法操作相关检查机制不同,kmemleak主要用于对显存泄露的测量。它的优点是能测量到绝大部份的显存泄露问题,但也有部份问题并不能测量到,比如当系统显存中正好富含与被泄露显存表针相等的显存值时,则难以测量出该显存块的泄露情况。同时,因为它的测量方法会扫描显存,因而会对系统性能导致较大影响,因而一般在生产环境下也不适用