'User space CR3 value when PTI is enabled

While executing in the kernel mode, is there any way to get the userspace CR3 value when Page Table Isolation(PTI) is enabled?



Solution 1:[1]

In current Linux, see arch/x86/entry/calling.h for asm .macro SWITCH_TO_USER_CR3_NOSTACK and other stuff to see how Linux flips between kernel vs. user CR3. And the earlier comment on the constants it uses:

/*
 * 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)

It looks like the kernel CR3 is always the lower one, so setting bit 12 in the current CR3 always makes it point to the user-space page directory. (If the current task has a user-space, and if PTI is enabled. These asm macros are only used in code-paths that are about to return to user-space.)

.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

These macros are used in entry_64.S, entry_64_compat.S, and entry_32.S in paths that returns to user-space.


There's presumably a cleaner way to access user-space page tables from C.

Your best bet might be to look at the page-fault handler to find out how it accesses the process's page table. (Or mmap's implementation of MAP_POPULATE).

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Marco Bonelli