From: Alexander Shishkin <alexander.shishkin@linux.intel.com>
A LASS violation typically results in a #GP. With LASS active, any
invalid access to user memory (including the first page frame) would be
reported as a #GP, instead of a #PF.
Unfortunately, the #GP error messages provide limited information about
the cause of the fault. This could be confusing for kernel developers
and users who are accustomed to the friendly #PF messages.
To make the transition easier, enhance the #GP Oops message to include a
hint about LASS violations. Also, add a special hint for kernel NULL
pointer dereferences to match with the existing #PF message.
Signed-off-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>
---
v11:
- Improve commit log.
v10:
- Minor improvement to code comments and hints.
---
arch/x86/kernel/traps.c | 45 ++++++++++++++++++++++++++++++-----------
1 file changed, 33 insertions(+), 12 deletions(-)
diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c
index 6b22611e69cc..30d5c690f9a1 100644
--- a/arch/x86/kernel/traps.c
+++ b/arch/x86/kernel/traps.c
@@ -635,13 +635,23 @@ DEFINE_IDTENTRY(exc_bounds)
enum kernel_gp_hint {
GP_NO_HINT,
GP_NON_CANONICAL,
- GP_CANONICAL
+ GP_CANONICAL,
+ GP_LASS_VIOLATION,
+ GP_NULL_POINTER,
+};
+
+static const char * const kernel_gp_hint_help[] = {
+ [GP_NON_CANONICAL] = "probably for non-canonical address",
+ [GP_CANONICAL] = "maybe for address",
+ [GP_LASS_VIOLATION] = "probably LASS violation for address",
+ [GP_NULL_POINTER] = "kernel NULL pointer dereference",
};
/*
* When an uncaught #GP occurs, try to determine the memory address accessed by
* the instruction and return that address to the caller. Also, try to figure
- * out whether any part of the access to that address was non-canonical.
+ * out whether any part of the access to that address was non-canonical or
+ * across privilege levels.
*/
static enum kernel_gp_hint get_kernel_gp_address(struct pt_regs *regs,
unsigned long *addr)
@@ -663,14 +673,27 @@ static enum kernel_gp_hint get_kernel_gp_address(struct pt_regs *regs,
return GP_NO_HINT;
#ifdef CONFIG_X86_64
- /*
- * Check that:
- * - the operand is not in the kernel half
- * - the last byte of the operand is not in the user canonical half
- */
- if (*addr < ~__VIRTUAL_MASK &&
- *addr + insn.opnd_bytes - 1 > __VIRTUAL_MASK)
+ /* Operand is in the kernel half */
+ if (*addr >= ~__VIRTUAL_MASK)
+ return GP_CANONICAL;
+
+ /* The last byte of the operand is not in the user canonical half */
+ if (*addr + insn.opnd_bytes - 1 > __VIRTUAL_MASK)
return GP_NON_CANONICAL;
+
+ /*
+ * If LASS is active, a NULL pointer dereference generates a #GP
+ * instead of a #PF.
+ */
+ if (*addr < PAGE_SIZE)
+ return GP_NULL_POINTER;
+
+ /*
+ * Assume that LASS caused the exception, because the address is
+ * canonical and in the user half.
+ */
+ if (cpu_feature_enabled(X86_FEATURE_LASS))
+ return GP_LASS_VIOLATION;
#endif
return GP_CANONICAL;
@@ -833,9 +856,7 @@ DEFINE_IDTENTRY_ERRORCODE(exc_general_protection)
if (hint != GP_NO_HINT)
snprintf(desc, sizeof(desc), GPFSTR ", %s 0x%lx",
- (hint == GP_NON_CANONICAL) ? "probably for non-canonical address"
- : "maybe for address",
- gp_addr);
+ kernel_gp_hint_help[hint], gp_addr);
/*
* KASAN is interested only in the non-canonical case, clear it
--
2.43.0
On 10/29/25 14:03, Sohil Mehta wrote: > To make the transition easier, enhance the #GP Oops message to include a > hint about LASS violations. Also, add a special hint for kernel NULL > pointer dereferences to match with the existing #PF message. Reviewed-by: Dave Hansen <dave.hansen@linux.intel.com> This also reminds me... Are there tests for this somewhere? How did you test all these new messages?
On 10/31/2025 10:16 AM, Dave Hansen wrote: > On 10/29/25 14:03, Sohil Mehta wrote: >> To make the transition easier, enhance the #GP Oops message to include a >> hint about LASS violations. Also, add a special hint for kernel NULL >> pointer dereferences to match with the existing #PF message. > > Reviewed-by: Dave Hansen <dave.hansen@linux.intel.com> > > This also reminds me... Are there tests for this somewhere? How did you > test all these new messages? I have some very simple kernel modules that access invalid user memory and generate these faults. I configure the kernel not to panic/reboot. But, I have been running them manually. Invalid accesses from the kernel generate: #PF (without LASS): BUG: kernel NULL pointer dereference, address: 0000000000000000 BUG: unable to handle page fault for address: 0000000000100000 #GP (with LASS): Oops: general protection fault, kernel NULL pointer dereference 0x0: 0000 Oops: general protection fault, probably LASS violation for address 0x100000: 0000 For testing user SIGSEGVs, the Vsyscall tests have been sufficient to cover all scenarios. Were you looking for anything specific? I can clean them up and post them if required.
On 10/31/25 12:59, Sohil Mehta wrote: > Were you looking for anything specific? I can clean them up and post > them if required. It would be nice to have these in-kernel somehow, even if they were silly debugfs knobs or something. Ira had some tests for PKS that never went in but you might be able to reuse some of his techniques.
On Fri, Oct 31, 2025, at 12:59 PM, Sohil Mehta wrote: > On 10/31/2025 10:16 AM, Dave Hansen wrote: >> On 10/29/25 14:03, Sohil Mehta wrote: >>> To make the transition easier, enhance the #GP Oops message to include a >>> hint about LASS violations. Also, add a special hint for kernel NULL >>> pointer dereferences to match with the existing #PF message. >> >> Reviewed-by: Dave Hansen <dave.hansen@linux.intel.com> >> >> This also reminds me... Are there tests for this somewhere? How did you >> test all these new messages? > > I have some very simple kernel modules that access invalid user memory > and generate these faults. I configure the kernel not to panic/reboot. > But, I have been running them manually. > > Invalid accesses from the kernel generate: > #PF (without LASS): > BUG: kernel NULL pointer dereference, address: 0000000000000000 > BUG: unable to handle page fault for address: 0000000000100000 > > #GP (with LASS): > Oops: general protection fault, kernel NULL pointer dereference 0x0: 0000 > Oops: general protection fault, probably LASS violation for address > 0x100000: 0000 > > For testing user SIGSEGVs, the Vsyscall tests have been sufficient to > cover all scenarios. > > Were you looking for anything specific? I can clean them up and post > them if required. LKDTM is basically meant for this use case. If you can’t provoke a LASS failure from there, maybe just add another failure type? I would expect that LKDTM can already do a SMAP violation.
© 2016 - 2025 Red Hat, Inc.