You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

_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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 10:55:20