[PATCH v10 14/15] x86/traps: Provide additional hints for a kernel stack segment fault

Sohil Mehta posted 15 patches 13 hours ago
[PATCH v10 14/15] x86/traps: Provide additional hints for a kernel stack segment fault
Posted by Sohil Mehta 13 hours ago
From: "Kirill A. Shutemov" <kirill.shutemov@linux.intel.com>

Kernel triggered #SS exceptions are rare, and the faulting instruction
may not even have a memory operand. In cases where it does, hints about
the cause of the fault can be useful.

LASS throws a #GP for any violation except for stack register access,
which instead triggers a #SS. Handle a kernel #SS similarly to a #GP and
reuse the address decode logic to provide additional hints, such as a
non-canonical address or an LASS violation.

In case of FRED, before handling #SS as a kernel violation, check if
there's a fixup for the exception. Redirect the #SS due to invalid user
context on ERETU to userspace. See commit 5105e7687ad3 ("x86/fred: Fixup
fault on ERETU by jumping to fred_entrypoint_user") for details.

Originally-by: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
Signed-off-by: Sohil Mehta <sohil.mehta@intel.com>
---
v10:
 - Remove the LASS feature check to always provide hints independent of
   LASS being enabled.
 - Update printk to use KERN_DEFAULT (checkpatch warning).
 - Add code comments.
---
 arch/x86/kernel/traps.c | 43 +++++++++++++++++++++++++++++++++++------
 1 file changed, 37 insertions(+), 6 deletions(-)

diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c
index 3ee8a36a4e6a..864c614cddab 100644
--- a/arch/x86/kernel/traps.c
+++ b/arch/x86/kernel/traps.c
@@ -418,12 +418,6 @@ DEFINE_IDTENTRY_ERRORCODE(exc_segment_not_present)
 		      SIGBUS, 0, NULL);
 }
 
-DEFINE_IDTENTRY_ERRORCODE(exc_stack_segment)
-{
-	do_error_trap(regs, error_code, "stack segment", X86_TRAP_SS, SIGBUS,
-		      0, NULL);
-}
-
 DEFINE_IDTENTRY_ERRORCODE(exc_alignment_check)
 {
 	char *str = "alignment check";
@@ -873,6 +867,43 @@ DEFINE_IDTENTRY_ERRORCODE(exc_general_protection)
 	cond_local_irq_disable(regs);
 }
 
+#define SSFSTR "stack segment fault"
+
+DEFINE_IDTENTRY_ERRORCODE(exc_stack_segment)
+{
+	enum kernel_exc_hint hint;
+	unsigned long exc_addr;
+
+	if (user_mode(regs))
+		goto error_trap;
+
+	/*
+	 * With FRED enabled, an invalid user context can lead to an #SS
+	 * trap on ERETU. Fixup the exception and redirect the fault to
+	 * userspace in that case.
+	 */
+	if (cpu_feature_enabled(X86_FEATURE_FRED) &&
+	    fixup_exception(regs, X86_TRAP_SS, error_code, 0))
+		return;
+
+	if (notify_die(DIE_TRAP, SSFSTR, regs, error_code, X86_TRAP_SS, SIGBUS) == NOTIFY_STOP)
+		return;
+
+	hint = get_kernel_exc_address(regs, &exc_addr);
+	if (hint != EXC_NO_HINT)
+		printk(KERN_DEFAULT SSFSTR ", %s 0x%lx", kernel_exc_hint_help[hint], exc_addr);
+
+	/* KASAN only cares about the non-canonical case, clear it otherwise */
+	if (hint != EXC_NON_CANONICAL)
+		exc_addr = 0;
+
+	die_addr(SSFSTR, regs, error_code, exc_addr);
+	return;
+
+error_trap:
+	do_error_trap(regs, error_code, SSFSTR, X86_TRAP_SS, SIGBUS, 0, NULL);
+}
+
 static bool do_int3(struct pt_regs *regs)
 {
 	int res;
-- 
2.43.0