_ASM_EXTABLE仅虚拟机生效,宿主机无法捕获页故障求排查
问题分析与调试方案
核心差异原因
页故障(#PF)和除零异常在内核中的处理路径存在本质区别:
- 除零异常属于可修复的同步异常,内核会直接检查异常表(extable)并跳转至修复代码执行。
- 页故障的处理逻辑更复杂:内核首先尝试常规修复(如缺页分配、写时复制),仅当修复失败时才会检查异常表。而你访问的
0x0地址属于内核保留地址空间,部分内核配置会将这类地址的页故障直接判定为不可修复,跳过异常表检查,直接触发Oops。
Fedora与Debian内核的配置差异是关键:
- Fedora默认启用了更严格的内存保护配置(如
CONFIG_NULL_POINTER_DETECTION),对NULL指针这类非法访问直接触发崩溃,不允许通过异常表绕过。 - Debian内核配置相对宽松,允许异常表处理这类页故障。
调试步骤
1. 核对内核配置差异
分别在虚拟机和宿主机执行以下命令,对比关键配置项:
cat /boot/config-$(uname -r) | grep -E "DEBUG_VM|CONFIG_PAGE_POISONING|CONFIG_NULL_POINTER_DETECTION"
重点关注CONFIG_NULL_POINTER_DETECTION,若Fedora开启该选项,访问NULL指针会直接触发Oops,不走异常表流程。
2. 验证异常表是否正确生成
检查编译后的模块是否包含正确的异常表项:
objdump -s --section=.extable reproducer.ko
若输出中能找到inc_non_present_page函数内1b(故障指令地址)和3b(修复代码地址)的对应条目,说明异常表生成正常,问题出在内核处理逻辑。
3. 修改测试地址,避开保留空间
避免使用0x0这类内核保留地址,改用未映射但不属于保留区域的虚拟地址,比如0xffff000000000000(x86_64非规范地址),修改代码如下:
void inc_non_present_page(void) { asm volatile("mov $0xffff000000000000, %%rax;" "1: inc (%%rax);" "2:nop\t\n" "\t.section .fixup,\"ax\"\n" "3:\tnop\n" "\tjmp\t2b\n" "\t.previous\n" _ASM_EXTABLE(1b, 3b) : : : "%rax"); pr_warn("Init done\n"); }
测试修改后的模块,确认是否能在宿主机正常执行,排除保留地址的特殊处理逻辑影响。
4. 跟踪内核页故障处理流程
若需深入调试,可在宿主机启用内核调试(需开启CONFIG_DEBUG_INFO和CONFIG_KALLSYMS):
- 使用
gdb连接运行中的内核 - 在
do_page_fault函数设置断点,检查error_code、访问地址,以及是否调用了search_exception_tables函数,确认异常表是否被正常检索。
总结
问题根源是不同发行版内核的配置差异:Fedora内核对NULL指针这类非法访问做了严格限制,跳过了异常表的处理环节。通过核对内核配置、修改测试地址、跟踪内核处理流程,可定位并解决该问题。
内容的提问来源于stack exchange,提问作者cryptobeginner
相关产品推荐
相关产品推荐

