一般的内存访问错误如下:
- 越界访问;
- 访问已经被释放的内存;
- 重复释放;
- 内存泄漏;
- 栈溢出;
slub_debug 工具
在 Linux 内核中,对于小块内存的分配,大量使用 slab/slub 分配器,slab/slub 分配器提供了一个内存检测功能,很方便在产品开发阶段进行内存检查。
1. 配置和编译内核
重新配置内核选项:
shell
CONFIG_SLUB=y
CONFIG_SLUB_DEBUG_ON=y
CONFIG_SLUB_STATS=y
重新编译内核并更新文件系统,注意文件系统安装需要 root 用户。
2. 添加 slub_debug 选项
在内核 commandline 中添加 slub_debug 字符串打开 slub_debug 功能。
追加:slub_debug=UFPZ
3. 编译 slabinfo 工具
该工具在 tools/vm/slabinfo.c 目录下。
4. 编写一个slub测试内核模块
slub_test.c
c
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
static char *buf;
static void create_slub_error(void)
{
buf = kmalloc(32, GFP_KERNEL);
if (buf) {
memset(buf, 0x55, 130);
}
}
static int __init my_test_init(void)
{
printk("benshushu: my module init\n");
create_slub_error();
return 0;
}
static void __exit my_test_exit(void)
{
printk("goodbye\n");
kfree(buf);
}
MODULE_LICENSE("GPL");
module_init(my_test_init);
module_exit(my_test_exit);
Makefile
Makefile
BASEINCLUDE ?= /lib/modules/$(shell uname -r)/build
slub-objs := slub_test.o
obj-m := slub.o
all :
$(MAKE) -C $(BASEINCLUDE) SUBDIRS=$(PWD) modules;
clean:
$(MAKE) -C $(BASEINCLUDE) SUBDIRS=$(PWD) clean;
rm -f *.ko;
make 编译内核模块 slub.ko:

加载 slub 测试的内核模块:

运行 slabinfo 工具查看内存分配后的结果。
shell
benshushu:~# /mnt/slabinfo -v
[ 671.388357] =============================================================================
[ 671.393422] BUG kmalloc-128 (Tainted: G OE ): Redzone overwritten
[ 671.393965] -----------------------------------------------------------------------------
[ 671.393965]
[ 671.394793] Disabling lock debugging due to kernel taint
[ 671.396280] INFO: 0x000000002320e91b-0x00000000ec1b97ed. First byte 0x55 instead of 0xcc
[ 671.398522] INFO: Allocated in create_slub_error+0x30/0x78 [slub] age=17178 cpu=1 pid=4380
[ 671.400878] __slab_alloc+0x64/0xb0
[ 671.401178] __kmalloc+0x560/0xf0c
[ 671.401322] create_slub_error+0x30/0x78 [slub]
[ 671.401661] 0xffff0000098f5020
[ 671.401766] do_one_initcall+0x494/0xad8
[ 671.401865] do_init_module+0xb4/0x2f8
[ 671.402251] load_module+0x940/0xc50
[ 671.402364] __se_sys_finit_module+0x148/0x184
[ 671.402484] __arm64_sys_finit_module+0x40/0x48
[ 671.402606] __invoke_syscall+0x24/0x2c
[ 671.402714] invoke_syscall+0xa4/0xd8
[ 671.402878] el0_svc_common+0x100/0x1e4
[ 671.403012] el0_svc_handler+0x418/0x444
[ 671.403140] el0_svc+0x8/0xc
[ 671.403291] INFO: Freed in free_modprobe_argv+0x28/0x40 age=17240 cpu=2 pid=589
[ 671.403494] kfree+0xd84/0xdc8
[ 671.403603] free_modprobe_argv+0x28/0x40
[ 671.403732] call_usermodehelper_freeinfo+0x34/0x48
[ 671.403849] call_usermodehelper_exec+0x2f4/0x33c
[ 671.403956] call_modprobe+0x110/0x144
[ 671.404046] __request_module+0x114c/0x11d0
[ 671.404147] dev_load+0x80/0xc4
[ 671.404228] dev_ioctl+0xc0/0x2e4
[ 671.404314] sock_do_ioctl+0x730/0x96c
[ 671.404403] sock_ioctl+0xa08/0xa5c
[ 671.404490] vfs_ioctl+0x54/0x88
[ 671.404571] do_vfs_ioctl+0x654/0x690
[ 671.404661] ksys_ioctl+0xb4/0xec
[ 671.404744] __se_sys_ioctl+0x4c/0x60
[ 671.404963] __arm64_sys_ioctl+0x40/0x48
[ 671.405089] __invoke_syscall+0x24/0x2c
[ 671.405439] INFO: Slab 0x00000000d2d49de4 objects=25 used=25 fp=0x (null) flags=0xffff00000010201
[ 671.406208] INFO: Object 0x00000000c052bc65 @offset=14848 fp=0x (null)
[ 671.406208]
[ 671.407056] Redzone 000000000becbf55: cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc ................
[ 671.407871] Redzone 00000000e6fc236b: cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc ................
[ 671.408835] Redzone 00000000d0bb8058: cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc ................
[ 671.409898] Redzone 000000008534dc07: cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc ................
[ 671.410555] Redzone 000000009b9c45b6: cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc ................
[ 671.411406] Redzone 00000000cbb54c78: cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc ................
[ 671.412205] Redzone 00000000f95c8135: cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc ................
[ 671.412996] Redzone 00000000bed0bde2: cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc ................
[ 671.413825] Object 00000000c052bc65: 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 UUUUUUUUUUUUUUUU
[ 671.414904] Object 0000000030ffab7e: 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 UUUUUUUUUUUUUUUU
[ 671.415570] Object 00000000a609489d: 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 UUUUUUUUUUUUUUUU
[ 671.416345] Object 00000000f66b0715: 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 UUUUUUUUUUUUUUUU
[ 671.417812] Object 00000000afd73ae0: 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 UUUUUUUUUUUUUUUU
[ 671.418196] Object 00000000b6209964: 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 UUUUUUUUUUUUUUUU
[ 671.418477] Object 0000000070d14a83: 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 UUUUUUUUUUUUUUUU
[ 671.418750] Object 00000000484fdfe2: 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 UUUUUUUUUUUUUUUU
[ 671.419125] Redzone 000000002320e91b: 55 55 cc cc cc cc cc cc UU......
[ 671.420348] Padding 00000000d774902d: 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a ZZZZZZZZZZZZZZZZ
[ 671.421066] Padding 00000000148dff6b: 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a ZZZZZZZZZZZZZZZZ
[ 671.421754] Padding 00000000a30f7e51: 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a ZZZZZZZZZZZZZZZZ
[ 671.422500] Padding 00000000ce303c9a: 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a ZZZZZZZZZZZZZZZZ
[ 671.423682] CPU: 0 PID: 4805 Comm: slabinfo Kdump: loaded Tainted: G B OE 5.0.0+ #2
[ 671.424297] Hardware name: linux,dummy-virt (DT)
[ 671.425095] Call trace:
[ 671.425339] dump_backtrace+0x0/0x528
[ 671.425483] show_stack+0x24/0x30
[ 671.425650] __dump_stack+0x20/0x2c
[ 671.425990] dump_stack+0x25c/0x388
[ 671.426092] print_trailer+0x340/0x34c
[ 671.426184] check_bytes_and_report+0x108/0x134
[ 671.426286] check_object+0xe8/0x4bc
[ 671.426374] validate_slab+0x2a0/0x30c
[ 671.426466] validate_slab_slab+0x264/0x418
[ 671.426608] validate_slab_node+0x390/0x6a0
[ 671.426721] validate_slab_cache+0xa8/0xf0
[ 671.426828] validate_store+0x3c/0x60
[ 671.426924] slab_attr_store+0x74/0x16c
[ 671.427038] sysfs_kf_write+0x80/0x88
[ 671.427161] kernfs_fop_write+0x3bc/0x448
[ 671.427291] __vfs_write+0x54/0x90
[ 671.427407] vfs_write+0x16c/0x2f4
[ 671.427736] ksys_write+0xb4/0x164
[ 671.427892] __se_sys_write+0x48/0x58
[ 671.428019] __arm64_sys_write+0x40/0x48
[ 671.428317] __invoke_syscall+0x24/0x2c
[ 671.428463] invoke_syscall+0xa4/0xd8
[ 671.428571] el0_svc_common+0x100/0x1e4
[ 671.428674] el0_svc_handler+0x418/0x444
[ 671.428776] el0_svc+0x8/0xc
[ 671.429183] FIX kmalloc-128: Restoring 0x000000002320e91b-0x00000000ec1b97ed=0xcc
[ 671.429183]
上述 slabinfo 信息显示这是一个 Redzone overwritten 错误,内存访问越界了。