人生像是在跑马拉松,能够完赛的都是不断地坚持向前迈进;人生就是像在跑马拉松,不断调整步伐,把握好分分秒秒;人生还是像在跑马拉松,能力决定了能跑短程、半程还是全程。人生其实就是一场马拉松,坚持不懈,珍惜时间。
分类: LINUX
2016-12-23 14:10:53
前面分析了kmemcheck的实现,那么现在就针对其功能进行试验,鉴于kmemcheck支持KMEMCHECK_SHADOW_UNALLOCATED、KMEMCHECK_SHADOW_UNINITIALIZED及KMEMCHECK_SHADOW_FREED的检测且检测上报信息大同小异,本文中的实验主要针对于未初始化的内存进行。
如果需要使能kmemcheck,需要进行一系列的内核参数设置,具体的配置项可以参考内核源码Document目录下的kmemcheck.txt文档描述(不过文档更新的节奏似乎跟不上源码的更新速度,有部分存在偏差)。至于修改配置项make menuconfig,内核编译的设置选项中设置即可。
主要的配置项有:
CONFIG_CC_OPTIMIZE_FOR_SIZE=n
——该项修改为关闭, 设置路径:"General setup" / "Optimize for size"。如果没有关闭该项,Gcc编译器将会进行优化,这将会导致错误地触发kmemcheck上报非问题。比如代码中访问16bit的数据,Gcc则会先加载32bit的数据,然后丢弃高16bit的信息,而kmemcheck只会看到操作了32bit的数据,并且高16bit可能未初始化,那么将会触发问题上报;
CONFIG_SLAB=y or CONFIG_SLUB=y
——选择了slub算法,设置路径:"General setup" / "Choose SLAB Allocator"。
CONFIG_FUNCTION_TRACER=n
——该选项设置为关闭,设置路径:"Kernel hacking" / "Tracers" / "Kernel Function Tracer”。当函数轨迹编译进去的时候,在每个函数调用之前,Gcc都将会向其他函数发出一个调用。这将导致缺页异常处理被调用的时候,ftrace的框架将会在kmemcheck之前调动并获得机会去处理该异常。如果ftrace修改了kmemcheck所依赖的内存信息,将会导致无限的缺页异常循环。
CONFIG_DEBUG_PAGEALLOC= n
——配置项设置为关闭,似乎不太影响。文档路径: "Kernel hacking" / "Debug page memory allocations"。实际设置路径:"Kernel hacking"/”Memory Debugging”/"Debug page memory allocations"。
CONFIG_DEBUG_INFO=y
——该配置项设置为开启,设置路径:"Kernel hacking"/”Compile-time checks and compiler options”/”Compile the kernel with debug info”。
经过前面的设置,将可以看到kmemcheck调试功能开启选项。具体路径:"Kernel hacking" / "Memory Debugging" / "kmemcheck: trap use of uninitialized memory")。在该设置路径里面有详细的子选项可供设置。
具体子选项有:
CONFIG_KMEMCHECK_[DISABLED | ENABLED | ONESHOT]_BY_DEFAULT
——该设置选项,用于设置Kmemcheck的状态,其中DISABLED表示kmemcheck功能关闭(值为0),而ENABLED表示系统引导之初就使能kmemcheck功能(其值为1),最后的是ONESHOT表示kmemcheck功能仅捕获一次而后自动关闭(其值为2)。如果把握不准的话,可以默认设置功能关闭,因为在系统启动后通过修改/proc/sys/kernel/kmemcheck的值来进行动态调整的,将文件中的修改为对应的状态值即可。该配置项建议修改为DISABLED,后期系统运行后再修改配置文件进行开启,否则系统启动的时候会很慢很慢。
CONFIG_KMEMCHECK_QUEUE_SIZE
——在设置选项中描述为 “kmemcheck: error queue size”。
CONFIG_KMEMCHECK_SHADOW_COPY_SHIFT
——在设置选项中描述为 “kmemcheck: shadow copy size (5 => 32 bytes, 6 => 64 bytes)”。
CONFIG_KMEMCHECK_PARTIAL_OK
——在设置选项中描述为“kmemcheck: allow partially uninitialized memory”。
CONFIG_KMEMCHECK_BITOPS_OK
——在设置选项中描述为“kmemcheck: allow bit-field manipulation”。
本文中的示例此几项的配置为:
其实这些配置项信息都无需记住路径在何处,只需要在make menuconfig的时候,使用右上至左下的斜杠 “/”进入搜索界面,直接搜索上面的配置项即可得到详细的路径信息,无需在乎内核版本如何更新。
将上述的配置项进行配置后,重新编译内核以及安装后,即可进行kmemcheck的测试实验了(由于pc的发展,32位环境已经无法接近于绝迹了,只好找了个64位的环境作为演示示例了)。具体的内核模块如何编写,这里就不赘述了,后期有机会再进行补充。示例实验测试代码:
Makefile编译脚本:
通过Makefile编译出kmemcheck_test.ko后,通过insmod命令即可将该模块加载到环境中,然后通过dmesg即可看到执行结果:
详细的错误信息解析如下:
根据错误信息可以看到此处报出来的告警在kmemchk_access_uninitialized(),位于偏移0x1c的指令访问了未被初始化的内存空间。继而将编译生成的kmemcheck_test.ko进行反汇编,找到kmemchk_access_uninitialized()的该指令。
即cmpb $0x61,0x17(%rbx)指令,可以分析得出该比较指令对应的即为函数中的if (*(addr + offset) == 'a')该条件判断操作。
由此一来便可以定位此类对未初始化内存进行访问的不合法的信息。