lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:   Sat, 1 Sep 2018 06:03:52 -0700
From:   tip-bot for LuckTony <tipbot@...or.com>
To:     linux-tip-commits@...r.kernel.org
Cc:     dave.jiang@...el.com, hpa@...or.com, bp@...en8.de,
        mingo@...nel.org, linux-kernel@...r.kernel.org, tglx@...utronix.de,
        tony.luck@...el.com, dan.j.williams@...el.com,
        linux-edac@...r.kernel.org, torvalds@...ux-foundation.org
Subject: [tip:x86/urgent] x86/mce: Fix set_mce_nospec() to avoid #GP fault

Commit-ID:  c7486104a5ce7e8763e3cb5157bba8d0f1468d87
Gitweb:     https://git.kernel.org/tip/c7486104a5ce7e8763e3cb5157bba8d0f1468d87
Author:     LuckTony <tony.luck@...el.com>
AuthorDate: Fri, 31 Aug 2018 09:55:06 -0700
Committer:  Thomas Gleixner <tglx@...utronix.de>
CommitDate: Sat, 1 Sep 2018 14:59:19 +0200

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: 284ce4011ba6 ("x86/memory_failure: Introduce {set, clear}_mce_nospec()")
Suggested-by: Linus Torvalds <torvalds@...ux-foundation.org>
Signed-off-by: Tony Luck <tony.luck@...el.com>
Signed-off-by: Thomas Gleixner <tglx@...utronix.de>
Acked-by: Linus Torvalds <torvalds@...ux-foundation.org>
Cc: Peter Anvin <hpa@...or.com>
Cc: Borislav Petkov <bp@...en8.de>
Cc: linux-edac <linux-edac@...r.kernel.org>
Cc: Dan Williams <dan.j.williams@...el.com>
Cc: Dave Jiang <dave.jiang@...el.com>
Link: https://lkml.kernel.org/r/20180831165506.GA9605@agluck-desk

---
 arch/x86/mm/pageattr.c | 25 ++++++++++++++++++++++++-
 1 file changed, 24 insertions(+), 1 deletion(-)

diff --git a/arch/x86/mm/pageattr.c b/arch/x86/mm/pageattr.c
index 8d6c34fe49be..51a5a69ecac9 100644
--- a/arch/x86/mm/pageattr.c
+++ b/arch/x86/mm/pageattr.c
@@ -1420,6 +1420,29 @@ static int __change_page_attr_set_clr(struct cpa_data *cpa, int checkalias)
 	return 0;
 }
 
+/*
+ * Machine check recovery code needs to change cache mode of poisoned
+ * pages to UC to avoid speculative access logging another error. But
+ * passing the address of the 1:1 mapping to set_memory_uc() is a fine
+ * way to encourage a speculative access. So we cheat and flip the top
+ * bit of the address. This works fine for the code that updates the
+ * page tables. But at the end of the process we need to flush the cache
+ * and the non-canonical address causes a #GP fault when used by the
+ * CLFLUSH instruction.
+ *
+ * But in the common case we already have a canonical address. This code
+ * will fix the top bit if needed and is a no-op otherwise.
+ */
+static inline unsigned long make_addr_canonical_again(unsigned long addr)
+{
+#ifdef CONFIG_X86_64
+	return (long)(addr << 1) >> 1;
+#else
+	return addr;
+#endif
+}
+
+
 static int change_page_attr_set_clr(unsigned long *addr, int numpages,
 				    pgprot_t mask_set, pgprot_t mask_clr,
 				    int force_split, int in_flag,
@@ -1465,7 +1488,7 @@ static int change_page_attr_set_clr(unsigned long *addr, int numpages,
 		 * Save address for cache flush. *addr is modified in the call
 		 * to __change_page_attr_set_clr() below.
 		 */
-		baddr = *addr;
+		baddr = make_addr_canonical_again(*addr);
 	}
 
 	/* Must avoid aliasing mappings in the highmem code */

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ