Skip to content

Commit 9bc4f28

Browse files
anadavKAGA-KOKO
authored andcommitted
x86/mm: Use WRITE_ONCE() when setting PTEs
When page-table entries are set, the compiler might optimize their assignment by using multiple instructions to set the PTE. This might turn into a security hazard if the user somehow manages to use the interim PTE. L1TF does not make our lives easier, making even an interim non-present PTE a security hazard. Using WRITE_ONCE() to set PTEs and friends should prevent this potential security hazard. I skimmed the differences in the binary with and without this patch. The differences are (obviously) greater when CONFIG_PARAVIRT=n as more code optimizations are possible. For better and worse, the impact on the binary with this patch is pretty small. Skimming the code did not cause anything to jump out as a security hazard, but it seems that at least move_soft_dirty_pte() caused set_pte_at() to use multiple writes. Signed-off-by: Nadav Amit <[email protected]> Signed-off-by: Thomas Gleixner <[email protected]> Acked-by: Peter Zijlstra (Intel) <[email protected]> Cc: Dave Hansen <[email protected]> Cc: Andi Kleen <[email protected]> Cc: Josh Poimboeuf <[email protected]> Cc: Michal Hocko <[email protected]> Cc: Vlastimil Babka <[email protected]> Cc: Sean Christopherson <[email protected]> Cc: Andy Lutomirski <[email protected]> Cc: [email protected] Link: https://lkml.kernel.org/r/[email protected]
1 parent 47b7360 commit 9bc4f28

File tree

3 files changed

+15
-15
lines changed

3 files changed

+15
-15
lines changed

arch/x86/include/asm/pgtable.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1195,7 +1195,7 @@ static inline pmd_t pmdp_establish(struct vm_area_struct *vma,
11951195
return xchg(pmdp, pmd);
11961196
} else {
11971197
pmd_t old = *pmdp;
1198-
*pmdp = pmd;
1198+
WRITE_ONCE(*pmdp, pmd);
11991199
return old;
12001200
}
12011201
}

arch/x86/include/asm/pgtable_64.h

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -55,15 +55,15 @@ struct mm_struct;
5555
void set_pte_vaddr_p4d(p4d_t *p4d_page, unsigned long vaddr, pte_t new_pte);
5656
void set_pte_vaddr_pud(pud_t *pud_page, unsigned long vaddr, pte_t new_pte);
5757

58-
static inline void native_pte_clear(struct mm_struct *mm, unsigned long addr,
59-
pte_t *ptep)
58+
static inline void native_set_pte(pte_t *ptep, pte_t pte)
6059
{
61-
*ptep = native_make_pte(0);
60+
WRITE_ONCE(*ptep, pte);
6261
}
6362

64-
static inline void native_set_pte(pte_t *ptep, pte_t pte)
63+
static inline void native_pte_clear(struct mm_struct *mm, unsigned long addr,
64+
pte_t *ptep)
6565
{
66-
*ptep = pte;
66+
native_set_pte(ptep, native_make_pte(0));
6767
}
6868

6969
static inline void native_set_pte_atomic(pte_t *ptep, pte_t pte)
@@ -73,7 +73,7 @@ static inline void native_set_pte_atomic(pte_t *ptep, pte_t pte)
7373

7474
static inline void native_set_pmd(pmd_t *pmdp, pmd_t pmd)
7575
{
76-
*pmdp = pmd;
76+
WRITE_ONCE(*pmdp, pmd);
7777
}
7878

7979
static inline void native_pmd_clear(pmd_t *pmd)
@@ -109,7 +109,7 @@ static inline pmd_t native_pmdp_get_and_clear(pmd_t *xp)
109109

110110
static inline void native_set_pud(pud_t *pudp, pud_t pud)
111111
{
112-
*pudp = pud;
112+
WRITE_ONCE(*pudp, pud);
113113
}
114114

115115
static inline void native_pud_clear(pud_t *pud)
@@ -137,13 +137,13 @@ static inline void native_set_p4d(p4d_t *p4dp, p4d_t p4d)
137137
pgd_t pgd;
138138

139139
if (pgtable_l5_enabled() || !IS_ENABLED(CONFIG_PAGE_TABLE_ISOLATION)) {
140-
*p4dp = p4d;
140+
WRITE_ONCE(*p4dp, p4d);
141141
return;
142142
}
143143

144144
pgd = native_make_pgd(native_p4d_val(p4d));
145145
pgd = pti_set_user_pgtbl((pgd_t *)p4dp, pgd);
146-
*p4dp = native_make_p4d(native_pgd_val(pgd));
146+
WRITE_ONCE(*p4dp, native_make_p4d(native_pgd_val(pgd)));
147147
}
148148

149149
static inline void native_p4d_clear(p4d_t *p4d)
@@ -153,7 +153,7 @@ static inline void native_p4d_clear(p4d_t *p4d)
153153

154154
static inline void native_set_pgd(pgd_t *pgdp, pgd_t pgd)
155155
{
156-
*pgdp = pti_set_user_pgtbl(pgdp, pgd);
156+
WRITE_ONCE(*pgdp, pti_set_user_pgtbl(pgdp, pgd));
157157
}
158158

159159
static inline void native_pgd_clear(pgd_t *pgd)

arch/x86/mm/pgtable.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,7 @@ static void mop_up_one_pmd(struct mm_struct *mm, pgd_t *pgdp)
269269
if (pgd_val(pgd) != 0) {
270270
pmd_t *pmd = (pmd_t *)pgd_page_vaddr(pgd);
271271

272-
*pgdp = native_make_pgd(0);
272+
pgd_clear(pgdp);
273273

274274
paravirt_release_pmd(pgd_val(pgd) >> PAGE_SHIFT);
275275
pmd_free(mm, pmd);
@@ -494,7 +494,7 @@ int ptep_set_access_flags(struct vm_area_struct *vma,
494494
int changed = !pte_same(*ptep, entry);
495495

496496
if (changed && dirty)
497-
*ptep = entry;
497+
set_pte(ptep, entry);
498498

499499
return changed;
500500
}
@@ -509,7 +509,7 @@ int pmdp_set_access_flags(struct vm_area_struct *vma,
509509
VM_BUG_ON(address & ~HPAGE_PMD_MASK);
510510

511511
if (changed && dirty) {
512-
*pmdp = entry;
512+
set_pmd(pmdp, entry);
513513
/*
514514
* We had a write-protection fault here and changed the pmd
515515
* to to more permissive. No need to flush the TLB for that,
@@ -529,7 +529,7 @@ int pudp_set_access_flags(struct vm_area_struct *vma, unsigned long address,
529529
VM_BUG_ON(address & ~HPAGE_PUD_MASK);
530530

531531
if (changed && dirty) {
532-
*pudp = entry;
532+
set_pud(pudp, entry);
533533
/*
534534
* We had a write-protection fault here and changed the pud
535535
* to to more permissive. No need to flush the TLB for that,

0 commit comments

Comments
 (0)