Skip to content

Commit c748610

Browse files
aeglKAGA-KOKO
authored andcommitted
x86/mce: Fix set_mce_nospec() to avoid #GP fault
The trick with flipping bit 63 to avoid loading the address of the 1:1 mapping of the poisoned page while the 1:1 map is updated used to work when unmapping the page. But it falls down horribly when attempting to directly set the page as uncacheable. The problem is that when the cache mode is changed to uncachable, the pages needs to be flushed from the cache first. But the decoy address is non-canonical due to bit 63 flipped, and the CLFLUSH instruction throws a #GP fault. Add code to change_page_attr_set_clr() to fix the address before calling flush. Fixes: 284ce40 ("x86/memory_failure: Introduce {set, clear}_mce_nospec()") Suggested-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Tony Luck <tony.luck@intel.com> Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Acked-by: Linus Torvalds <torvalds@linux-foundation.org> Cc: Peter Anvin <hpa@zytor.com> Cc: Borislav Petkov <bp@alien8.de> Cc: linux-edac <linux-edac@vger.kernel.org> Cc: Dan Williams <dan.j.williams@intel.com> Cc: Dave Jiang <dave.jiang@intel.com> Link: https://lkml.kernel.org/r/20180831165506.GA9605@agluck-desk
1 parent eeb89e2 commit c748610

File tree

1 file changed

+24
-1
lines changed

1 file changed

+24
-1
lines changed

arch/x86/mm/pageattr.c

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1420,6 +1420,29 @@ static int __change_page_attr_set_clr(struct cpa_data *cpa, int checkalias)
14201420
return 0;
14211421
}
14221422

1423+
/*
1424+
* Machine check recovery code needs to change cache mode of poisoned
1425+
* pages to UC to avoid speculative access logging another error. But
1426+
* passing the address of the 1:1 mapping to set_memory_uc() is a fine
1427+
* way to encourage a speculative access. So we cheat and flip the top
1428+
* bit of the address. This works fine for the code that updates the
1429+
* page tables. But at the end of the process we need to flush the cache
1430+
* and the non-canonical address causes a #GP fault when used by the
1431+
* CLFLUSH instruction.
1432+
*
1433+
* But in the common case we already have a canonical address. This code
1434+
* will fix the top bit if needed and is a no-op otherwise.
1435+
*/
1436+
static inline unsigned long make_addr_canonical_again(unsigned long addr)
1437+
{
1438+
#ifdef CONFIG_X86_64
1439+
return (long)(addr << 1) >> 1;
1440+
#else
1441+
return addr;
1442+
#endif
1443+
}
1444+
1445+
14231446
static int change_page_attr_set_clr(unsigned long *addr, int numpages,
14241447
pgprot_t mask_set, pgprot_t mask_clr,
14251448
int force_split, int in_flag,
@@ -1465,7 +1488,7 @@ static int change_page_attr_set_clr(unsigned long *addr, int numpages,
14651488
* Save address for cache flush. *addr is modified in the call
14661489
* to __change_page_attr_set_clr() below.
14671490
*/
1468-
baddr = *addr;
1491+
baddr = make_addr_canonical_again(*addr);
14691492
}
14701493

14711494
/* Must avoid aliasing mappings in the highmem code */

0 commit comments

Comments
 (0)