Skip to content

Commit 8211ca6

Browse files
Matthew Wilcox (Oracle)jfvogel
authored andcommitted
x86/mm: Clear _PAGE_DIRTY for kernel mappings when we clear _PAGE_RW
[ Upstream commit c1fcf41cf37f7a3fd3bbf6f0c04aba3ea4258888 ] The bit pattern of _PAGE_DIRTY set and _PAGE_RW clear is used to mark shadow stacks. This is currently checked for in mk_pte() but not pfn_pte(). If we add the check to pfn_pte(), it catches vfree() calling set_direct_map_invalid_noflush() which calls __change_page_attr() which loads the old protection bits from the PTE, clears the specified bits and uses pfn_pte() to construct the new PTE. We should, therefore, for kernel mappings, clear the _PAGE_DIRTY bit consistently whenever we clear _PAGE_RW. I opted to do it in the callers in case we want to use __change_page_attr() to create shadow stacks inside the kernel at some point in the future. Arguably, we might also want to clear _PAGE_ACCESSED here. Note that the 3 functions involved: __set_pages_np() kernel_map_pages_in_pgd() kernel_unmap_pages_in_pgd() Only ever manipulate non-swappable kernel mappings, so maintaining the DIRTY:1|RW:0 special pattern for shadow stacks and DIRTY:0 pattern for non-shadow-stack entries can be maintained consistently and doesn't result in the unintended clearing of a live dirty bit that could corrupt (destroy) dirty bit information for user mappings. Reported-by: kernel test robot <[email protected]> Signed-off-by: Matthew Wilcox (Oracle) <[email protected]> Signed-off-by: Ingo Molnar <[email protected]> Acked-by: Linus Torvalds <[email protected]> Link: https://lore.kernel.org/r/174051422675.10177.13226545170101706336.tip-bot2@tip-bot2 Closes: https://lore.kernel.org/oe-lkp/[email protected] Signed-off-by: Sasha Levin <[email protected]> (cherry picked from commit 837f5cb7be9a5a67d1a983ab2f72f7488628fc17) Signed-off-by: Jack Vogel <[email protected]>
1 parent d9bcff4 commit 8211ca6

File tree

1 file changed

+3
-3
lines changed

1 file changed

+3
-3
lines changed

arch/x86/mm/pat/set_memory.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2422,7 +2422,7 @@ static int __set_pages_np(struct page *page, int numpages)
24222422
.pgd = NULL,
24232423
.numpages = numpages,
24242424
.mask_set = __pgprot(0),
2425-
.mask_clr = __pgprot(_PAGE_PRESENT | _PAGE_RW),
2425+
.mask_clr = __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY),
24262426
.flags = CPA_NO_CHECK_ALIAS };
24272427

24282428
/*
@@ -2501,7 +2501,7 @@ int __init kernel_map_pages_in_pgd(pgd_t *pgd, u64 pfn, unsigned long address,
25012501
.pgd = pgd,
25022502
.numpages = numpages,
25032503
.mask_set = __pgprot(0),
2504-
.mask_clr = __pgprot(~page_flags & (_PAGE_NX|_PAGE_RW)),
2504+
.mask_clr = __pgprot(~page_flags & (_PAGE_NX|_PAGE_RW|_PAGE_DIRTY)),
25052505
.flags = CPA_NO_CHECK_ALIAS,
25062506
};
25072507

@@ -2544,7 +2544,7 @@ int __init kernel_unmap_pages_in_pgd(pgd_t *pgd, unsigned long address,
25442544
.pgd = pgd,
25452545
.numpages = numpages,
25462546
.mask_set = __pgprot(0),
2547-
.mask_clr = __pgprot(_PAGE_PRESENT | _PAGE_RW),
2547+
.mask_clr = __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY),
25482548
.flags = CPA_NO_CHECK_ALIAS,
25492549
};
25502550

0 commit comments

Comments
 (0)