ARM32(ARMv7)平台对应x86 CR0寄存器WP位的写保护机制查询
ARMv7(ARM32)平台内核空间写保护控制方案
与x86 CR0.WP位的等效机制说明
ARMv7架构没有和x86 CR0.WP功能完全对等的全局写保护控制位,它的内核空间写保护是通过两级机制实现的:
- 页表项(PTE)的权限控制位:ARMv7的页表项中包含AP(访问权限)位、XN(可执行禁止)位等,默认内核态下映射系统调用表等核心数据的页表会被配置为
AP=011(仅内核态只读,用户态无访问权限),直接写入的话会触发数据中止异常,这是和x86 CR0.WP控制效果最接近的核心机制。 - 系统控制寄存器SCTLR的W位(第19位):很多开发者容易混淆该位和x86 CR0.WP的功能,实际上两者完全不同:SCTLR.W=0时会全局禁止所有内存写入操作,和内核态只读页的写保护没有关系,不要尝试修改该位实现需求。
关闭写保护修改系统调用表的实现方案
方案1:临时修改目标页的PTE权限(推荐)
该方案无需修改全局配置,风险最低,实现逻辑如下:
- 找到系统调用表虚拟地址对应的页表项
- 修改PTE的权限位为内核态可读写
- 刷新TLB确保权限修改生效
- 修改系统调用表内容后,将PTE权限恢复为原始值,再次刷新TLB
核心C代码示例(仅可在内核模块环境下运行):
#include <linux/mm.h> #include <linux/pgtable.h> #include <asm/tlbflush.h> void modify_syscall_entry(unsigned long *sys_call_table, int syscall_num, unsigned long new_func_addr) { pte_t *target_pte; unsigned long target_addr = (unsigned long)&sys_call_table[syscall_num]; // 查询目标地址对应的PTE项 target_pte = lookup_address(target_addr, NULL); if (!target_pte) return; // 给PTE添加可写权限并刷新TLB set_pte(target_pte, pte_mkwrite(pte_mkdirty(*target_pte))); flush_tlb_all(); // 修改系统调用表项 sys_call_table[syscall_num] = new_func_addr; // 恢复PTE只读权限并刷新TLB set_pte(target_pte, pte_wrprotect(*target_pte)); flush_tlb_all(); }
方案2:临时屏蔽写权限异常(仅调试场景可用)
如果不想修改页表,也可以在修改系统调用表前后,临时屏蔽写权限错误触发的异常处理,该方案风险极高,修改过程中出现任何意外写错误都会直接导致内核崩溃,不建议生产环境使用。
注意事项
- 所有操作都必须在内核态下执行,一般通过编写内核模块实现,用户态没有权限修改页表或核心寄存器
- 部分开启了内核硬保护的定制ROM会额外加锁保护页表修改,这种场景需要先解除对应锁才能修改PTE
- 上述实现仅适配ARMv7 32位架构,ARMv8/ARM64的页表结构差异较大,不可直接迁移使用
内容的提问来源于stack exchange,提问作者portarm
相关产品推荐
相关产品推荐

