Skip to content

Commit ae1f05a

Browse files
committed
x86/mm: Warn if create Write=0,Dirty=1 with raw prot
When user shadow stack is in use, Write=0,Dirty=1 is treated by the CPU as shadow stack memory. So for shadow stack memory this bit combination is valid, but when Dirty=1,Write=1 (conventionally writable) memory is being write protected, the kernel has been taught to transition the Dirty=1 bit to SavedDirty=1, to avoid inadvertently creating shadow stack memory. It does this inside pte_wrprotect() because it knows the PTE is not intended to be a writable shadow stack entry, it is supposed to be write protected. However, when a PTE is created by a raw prot using mk_pte(), mk_pte() can't know whether to adjust Dirty=1 to SavedDirty=1. It can't distinguish between the caller intending to create a shadow stack PTE or needing the SavedDirty shift. The kernel has been updated to not do this, and so Write=0,Dirty=1 memory should only be created by the pte_mkfoo() helpers. Add a warning to make sure no new mk_pte() start doing this, like, for example, set_memory_rox() did. Signed-off-by: Rick Edgecombe <[email protected]> Signed-off-by: Dave Hansen <[email protected]> Tested-by: Pengfei Xu <[email protected]> Tested-by: John Allen <[email protected]> Tested-by: Kees Cook <[email protected]> Link: https://lore.kernel.org/all/20230613001108.3040476-19-rick.p.edgecombe%40intel.com
1 parent e5136e8 commit ae1f05a

File tree

1 file changed

+8
-1
lines changed

1 file changed

+8
-1
lines changed

arch/x86/include/asm/pgtable.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1033,7 +1033,14 @@ static inline unsigned long pmd_page_vaddr(pmd_t pmd)
10331033
* (Currently stuck as a macro because of indirect forward reference
10341034
* to linux/mm.h:page_to_nid())
10351035
*/
1036-
#define mk_pte(page, pgprot) pfn_pte(page_to_pfn(page), (pgprot))
1036+
#define mk_pte(page, pgprot) \
1037+
({ \
1038+
pgprot_t __pgprot = pgprot; \
1039+
\
1040+
WARN_ON_ONCE((pgprot_val(__pgprot) & (_PAGE_DIRTY | _PAGE_RW)) == \
1041+
_PAGE_DIRTY); \
1042+
pfn_pte(page_to_pfn(page), __pgprot); \
1043+
})
10371044

10381045
static inline int pmd_bad(pmd_t pmd)
10391046
{

0 commit comments

Comments
 (0)