Linux x86内核lookup_address在特定页错误场景返回NULL的疑问
问题描述
我在通用v6.1版本Linux内核的arch/x86/mm/fault.c中实现了一个简单的钩子函数is_read_only,该函数通过lookup_address获取虚拟地址对应的页表项(PTE)并判断页面属性。我将此函数调用置于__bad_area_nosemaphore函数内show_signal_msg调用的下方,传入页错误的虚拟地址作为参数。
测试时使用经典Linux页错误/段错误场景:在用户态程序中修改只读字符串,触发错误码为7的页错误,系统日志显示对应信息。根据Intel手册,错误码7表示页存在、处于用户态、操作是写入,但此时lookup_address却返回NULL,明明错误码指示页存在,为何无法正确返回页表项?
原因与解决方案
核心问题:lookup_address的作用范围
lookup_address是专门用于查找内核虚拟地址页表项的函数,它默认遍历的是内核全局页表(init_mm对应的页表),而你传入的是用户态虚拟地址,该地址属于当前进程的用户地址空间,不在内核页表的映射范围内,因此函数返回NULL。
正确的用户态地址页表项查找方式
要获取用户态虚拟地址对应的PTE,需要针对当前进程的用户地址空间操作:
- 使用
get_user_pages_fast:该函数可以快速获取用户虚拟地址对应的物理页,调用成功则说明页表项存在,同时可通过返回的struct page判断页面属性。 - 手动遍历用户页表:通过
current->mm获取当前进程的地址空间结构,从PGD开始逐层解析到PTE,注意操作时需要持有mmap_sem锁,避免页表被并发修改。
补充说明
错误码7是CPU硬件给出的判断,针对的是当前进程用户地址空间中的页表项;而lookup_address不处理用户地址空间,所以两者的判断不存在矛盾。在__bad_area_nosemaphore函数中,当前处于进程上下文,可以安全访问current->mm来操作用户页表。
内容的提问来源于stack exchange,提问作者Vinicius
相关产品推荐
相关产品推荐

