在内核模式下执行时,启用页表隔离(PTI)时是否有任何方法可以获取用户空间CR3值?
答案 0 :(得分:3)
在当前的Linux中,请参见arch/x86/entry/calling.h
中的asm .macro SWITCH_TO_USER_CR3_NOSTACK
和其他内容,以了解Linux如何在内核和用户CR3之间切换。以及之前对其使用的常量的注释:
/*
* PAGE_TABLE_ISOLATION PGDs are 8k. Flip bit 12 to switch between the two
* halves:
*/
#define PTI_USER_PGTABLE_BIT PAGE_SHIFT
#define PTI_USER_PGTABLE_MASK (1 << PTI_USER_PGTABLE_BIT)
#define PTI_USER_PCID_BIT X86_CR3_PTI_PCID_USER_BIT
#define PTI_USER_PCID_MASK (1 << PTI_USER_PCID_BIT)
#define PTI_USER_PGTABLE_AND_PCID_MASK (PTI_USER_PCID_MASK | PTI_USER_PGTABLE_MASK)
看起来内核CR3始终是较低的内核,因此在当前CR3中设置位12总是使其指向用户空间页面目录。(如果当前任务具有用户空间,并且如果启用了PTI,则这些asm宏仅用于将要返回到用户空间的代码路径中。)
.macro SWITCH_TO_USER_CR3_NOSTACK scratch_reg:req scratch_reg2:req
...
mov %cr3, \scratch_reg
...
.Lwrcr3_\@:
/* Flip the PGD to the user version */
orq $(PTI_USER_PGTABLE_MASK), \scratch_reg
mov \scratch_reg, %cr3
这些宏在返回用户空间的路径中的entry_64.S
,entry_64_compat.S
和entry_32.S
中使用。
大概是一种从C访问用户空间页表的更简洁的方法。
您最好的选择是查看页面错误处理程序,以了解它如何访问进程的页面表。 (或mmap
的{{1}}实现)。