Skip to content

Commit d0ceea6

Browse files
dwmw2Ingo Molnar
authored andcommitted
x86/mm: Add _PAGE_NOPTISHADOW bit to avoid updating userspace page tables
The set_p4d() and set_pgd() functions (in 4-level or 5-level page table setups respectively) assume that the root page table is actually a 8KiB allocation, with the userspace root immediately after the kernel root page table (so that the former can enforce NX on on all the subordinate page tables, which are actually shared). However, users of the kernel_ident_mapping_init() code do not give it an 8KiB allocation for its PGD. Both swsusp_arch_resume() and acpi_mp_setup_reset() allocate only a single 4KiB page. The kexec code on x86_64 currently gets away with it purely by chance, because it allocates 8KiB for its "control code page" and then actually uses the first half for the PGD, then copies the actual trampoline code into the second half only after the identmap code has finished scribbling over it. Fix this by defining a _PAGE_NOPTISHADOW bit (which can use the same bit as _PAGE_SAVED_DIRTY since one is only for the PGD/P4D root and the other is exclusively for leaf PTEs.). This instructs __pti_set_user_pgtbl() not to write to the userspace 'shadow' PGD. Strictly, the _PAGE_NOPTISHADOW bit doesn't need to be written out to the actual page tables; since __pti_set_user_pgtbl() returns the value to be written to the kernel page table, it could be filtered out. But there seems to be no benefit to actually doing so. Suggested-by: Dave Hansen <[email protected]> Signed-off-by: David Woodhouse <[email protected]> Signed-off-by: Ingo Molnar <[email protected]> Link: https://lore.kernel.org/r/[email protected] Cc: [email protected] Cc: Linus Torvalds <[email protected]> Cc: Andy Lutomirski <[email protected]> Cc: Peter Zijlstra <[email protected]> Cc: Rik van Riel <[email protected]>
1 parent c9a4b55 commit d0ceea6

File tree

3 files changed

+10
-6
lines changed

3 files changed

+10
-6
lines changed

arch/x86/include/asm/pgtable_types.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,12 @@
3636
#define _PAGE_BIT_DEVMAP _PAGE_BIT_SOFTW4
3737

3838
#ifdef CONFIG_X86_64
39-
#define _PAGE_BIT_SAVED_DIRTY _PAGE_BIT_SOFTW5 /* Saved Dirty bit */
39+
#define _PAGE_BIT_SAVED_DIRTY _PAGE_BIT_SOFTW5 /* Saved Dirty bit (leaf) */
40+
#define _PAGE_BIT_NOPTISHADOW _PAGE_BIT_SOFTW5 /* No PTI shadow (root PGD) */
4041
#else
4142
/* Shared with _PAGE_BIT_UFFD_WP which is not supported on 32 bit */
42-
#define _PAGE_BIT_SAVED_DIRTY _PAGE_BIT_SOFTW2 /* Saved Dirty bit */
43+
#define _PAGE_BIT_SAVED_DIRTY _PAGE_BIT_SOFTW2 /* Saved Dirty bit (leaf) */
44+
#define _PAGE_BIT_NOPTISHADOW _PAGE_BIT_SOFTW2 /* No PTI shadow (root PGD) */
4345
#endif
4446

4547
/* If _PAGE_BIT_PRESENT is clear, we use these: */
@@ -139,6 +141,8 @@
139141

140142
#define _PAGE_PROTNONE (_AT(pteval_t, 1) << _PAGE_BIT_PROTNONE)
141143

144+
#define _PAGE_NOPTISHADOW (_AT(pteval_t, 1) << _PAGE_BIT_NOPTISHADOW)
145+
142146
/*
143147
* Set of bits not changed in pte_modify. The pte's
144148
* protection key is treated like _PAGE_RW, for

arch/x86/mm/ident_map.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ static int ident_p4d_init(struct x86_mapping_info *info, p4d_t *p4d_page,
174174
if (result)
175175
return result;
176176

177-
set_p4d(p4d, __p4d(__pa(pud) | info->kernpg_flag));
177+
set_p4d(p4d, __p4d(__pa(pud) | info->kernpg_flag | _PAGE_NOPTISHADOW));
178178
}
179179

180180
return 0;
@@ -218,14 +218,14 @@ int kernel_ident_mapping_init(struct x86_mapping_info *info, pgd_t *pgd_page,
218218
if (result)
219219
return result;
220220
if (pgtable_l5_enabled()) {
221-
set_pgd(pgd, __pgd(__pa(p4d) | info->kernpg_flag));
221+
set_pgd(pgd, __pgd(__pa(p4d) | info->kernpg_flag | _PAGE_NOPTISHADOW));
222222
} else {
223223
/*
224224
* With p4d folded, pgd is equal to p4d.
225225
* The pgd entry has to point to the pud page table in this case.
226226
*/
227227
pud_t *pud = pud_offset(p4d, 0);
228-
set_pgd(pgd, __pgd(__pa(pud) | info->kernpg_flag));
228+
set_pgd(pgd, __pgd(__pa(pud) | info->kernpg_flag | _PAGE_NOPTISHADOW));
229229
}
230230
}
231231

arch/x86/mm/pti.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ pgd_t __pti_set_user_pgtbl(pgd_t *pgdp, pgd_t pgd)
132132
* Top-level entries added to init_mm's usermode pgd after boot
133133
* will not be automatically propagated to other mms.
134134
*/
135-
if (!pgdp_maps_userspace(pgdp))
135+
if (!pgdp_maps_userspace(pgdp) || (pgd.pgd & _PAGE_NOPTISHADOW))
136136
return pgd;
137137

138138
/*

0 commit comments

Comments
 (0)