[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <1521228593-3820-36-git-send-email-joro@8bytes.org>
Date: Fri, 16 Mar 2018 20:29:53 +0100
From: Joerg Roedel <joro@...tes.org>
To: Thomas Gleixner <tglx@...utronix.de>,
Ingo Molnar <mingo@...nel.org>,
"H . Peter Anvin" <hpa@...or.com>
Cc: x86@...nel.org, linux-kernel@...r.kernel.org, linux-mm@...ck.org,
Linus Torvalds <torvalds@...ux-foundation.org>,
Andy Lutomirski <luto@...nel.org>,
Dave Hansen <dave.hansen@...el.com>,
Josh Poimboeuf <jpoimboe@...hat.com>,
Juergen Gross <jgross@...e.com>,
Peter Zijlstra <peterz@...radead.org>,
Borislav Petkov <bp@...en8.de>, Jiri Kosina <jkosina@...e.cz>,
Boris Ostrovsky <boris.ostrovsky@...cle.com>,
Brian Gerst <brgerst@...il.com>,
David Laight <David.Laight@...lab.com>,
Denys Vlasenko <dvlasenk@...hat.com>,
Eduardo Valentin <eduval@...zon.com>,
Greg KH <gregkh@...uxfoundation.org>,
Will Deacon <will.deacon@....com>, aliguori@...zon.com,
daniel.gruss@...k.tugraz.at, hughd@...gle.com, keescook@...gle.com,
Andrea Arcangeli <aarcange@...hat.com>,
Waiman Long <llong@...hat.com>, Pavel Machek <pavel@....cz>,
jroedel@...e.de, joro@...tes.org
Subject: [PATCH 35/35] x86/entry/32: Add debug code to check entry/exit cr3
From: Joerg Roedel <jroedel@...e.de>
Add a config option that enabled code to check that we enter
and leave the kernel with the correct cr3. This is needed
because we have no NX protection of user-addresses in the
kernel-cr3 on x86-32 and wouldn't notice that type of bug
otherwise.
Signed-off-by: Joerg Roedel <jroedel@...e.de>
---
arch/x86/Kconfig.debug | 12 ++++++++++++
arch/x86/entry/entry_32.S | 43 +++++++++++++++++++++++++++++++++++++++++++
2 files changed, 55 insertions(+)
diff --git a/arch/x86/Kconfig.debug b/arch/x86/Kconfig.debug
index 672441c..b8a772c 100644
--- a/arch/x86/Kconfig.debug
+++ b/arch/x86/Kconfig.debug
@@ -345,6 +345,18 @@ config X86_DEBUG_FPU
If unsure, say N.
+config X86_DEBUG_ENTRY_CR3
+ bool "Debug CR3 for Kernel entry/exit"
+ depends on X86_32 && PAGE_TABLE_ISOLATION
+ ---help---
+ Add instructions to the x86-32 entry code to check whether the kernel
+ is entered and left with the correct CR3. When PTI is enabled, this
+ checks whether we enter the kernel with the user-space cr3 when
+ coming from user-mode and if we leave with user-cr3 back to
+ user-space.
+
+ If unsure, say N.
+
config PUNIT_ATOM_DEBUG
tristate "ATOM Punit debug driver"
depends on PCI
diff --git a/arch/x86/entry/entry_32.S b/arch/x86/entry/entry_32.S
index 0250b79..ea19bcf 100644
--- a/arch/x86/entry/entry_32.S
+++ b/arch/x86/entry/entry_32.S
@@ -166,6 +166,24 @@
.Lend_\@:
.endm
+.macro BUG_IF_WRONG_CR3 no_user_check=0
+#ifdef CONFIG_X86_DEBUG_ENTRY_CR3
+ ALTERNATIVE "jmp .Lend_\@", "", X86_FEATURE_PTI
+ .if \no_user_check == 0
+ /* coming from usermode? */
+ testl $SEGMENT_RPL_MASK, PT_CS(%esp)
+ jz .Lend_\@
+ .endif
+ /* On user-cr3? */
+ movl %cr3, %eax
+ testl $PTI_SWITCH_MASK, %eax
+ jnz .Lend_\@
+ /* From userspace with kernel cr3 - BUG */
+ ud2
+.Lend_\@:
+#endif
+.endm
+
/*
* Switch to kernel cr3 if not already loaded and return current cr3 in
* \scratch_reg
@@ -218,6 +236,8 @@
.macro SAVE_ALL_NMI cr3_reg:req
SAVE_ALL
+ BUG_IF_WRONG_CR3
+
/*
* Now switch the CR3 when PTI is enabled.
*
@@ -229,6 +249,7 @@
.Lend_\@:
.endm
+
/*
* This is a sneaky trick to help the unwinder find pt_regs on the stack. The
* frame pointer is replaced with an encoded pointer to pt_regs. The encoding
@@ -292,6 +313,8 @@
.Lswitched_\@:
+ BUG_IF_WRONG_CR3
+
RESTORE_REGS pop=\pop
.endm
@@ -362,6 +385,8 @@
ALTERNATIVE "", "jmp .Lend_\@", X86_FEATURE_XENPV
+ BUG_IF_WRONG_CR3
+
SWITCH_TO_KERNEL_CR3 scratch_reg=%eax
/*
@@ -804,6 +829,7 @@ ENTRY(entry_SYSENTER_32)
*/
pushfl
pushl %eax
+ BUG_IF_WRONG_CR3 no_user_check=1
SWITCH_TO_KERNEL_CR3 scratch_reg=%eax
popl %eax
popfl
@@ -898,6 +924,7 @@ ENTRY(entry_SYSENTER_32)
* whereas POPF does not.)
*/
btr $X86_EFLAGS_IF_BIT, (%esp)
+ BUG_IF_WRONG_CR3 no_user_check=1
popfl
popl %eax
@@ -975,6 +1002,8 @@ restore_all:
/* Switch back to user CR3 */
SWITCH_TO_USER_CR3 scratch_reg=%eax
+ BUG_IF_WRONG_CR3
+
/* Restore user state */
RESTORE_REGS pop=4 # skip orig_eax/error_code
.Lirq_return:
@@ -983,6 +1012,7 @@ restore_all:
restore_all_kernel:
TRACE_IRQS_IRET
PARANOID_EXIT_TO_KERNEL_MODE
+ BUG_IF_WRONG_CR3
RESTORE_REGS 4
jmp .Lirq_return
@@ -990,6 +1020,19 @@ restore_all_kernel:
ENTRY(iret_exc )
pushl $0 # no error code
pushl $do_iret_error
+
+#ifdef CONFIG_X86_DEBUG_ENTRY_CR3
+ /*
+ * The stack-frame here is the one that iret faulted on, so its a
+ * return-to-user frame. We are on kernel-cr3 because we come here from
+ * the fixup code. This confuses the CR3 checker, so switch to user-cr3
+ * as the checker expects it.
+ */
+ pushl %eax
+ SWITCH_TO_USER_CR3 scratch_reg=%eax
+ popl %eax
+#endif
+
jmp common_exception
.previous
_ASM_EXTABLE(.Lirq_return, iret_exc)
--
2.7.4
Powered by blists - more mailing lists