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>
Reviewed-by: Dave Hansen <dave.hansen@linux.intel.com>
---
v12:
- Pick up review tag.
v11:
- Improve commit log.
---
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 Thu, Nov 13, 2025 at 02:42:02PM -0800, Sohil Mehta wrote:
> + /*
> + * If LASS is active, a NULL pointer dereference generates a #GP
> + * instead of a #PF.
> + */
I'm having trouble matching the comment...
> + if (*addr < PAGE_SIZE)
... to the conditional.
Aaaha:
"With LASS active, any invalid access to user memory (including the first page
frame) would be..."
Why is the first page frame special to justify a special check?
I must be missing something obvious here...
Thx.
--
Regards/Gruss,
Boris.
https://people.kernel.org/tglx/notes-about-netiquette
On 11/17/2025 6:48 AM, Borislav Petkov wrote:
> Why is the first page frame special to justify a special check?
>
Any dereference to a very low address (the first page frame) is
typically considered as a "NULL" pointer dereference.
$ git log | grep "BUG: kernel NULL pointer dereference"
BUG: kernel NULL pointer dereference, address: 0000000000000000
BUG: kernel NULL pointer dereference, address: 0000000000000010
BUG: kernel NULL pointer dereference, address: 0000000000000008
BUG: kernel NULL pointer dereference, address: 0000000000000008
BUG: kernel NULL pointer dereference, address: 0000000000000040
BUG: kernel NULL pointer dereference, address: 0000000000000264
BUG: kernel NULL pointer dereference, address: 0000000000000000
BUG: kernel NULL pointer dereference, address: 0000000000000098
BUG: kernel NULL pointer dereference, address: 0000000000000000
BUG: kernel NULL pointer dereference, address: 00000000000003c0
The page fault error messages have similar logic:
if (address < PAGE_SIZE && !user_mode(regs))
pr_alert("BUG: kernel NULL pointer dereference, address: %px\n",
(void *)address);
I believe the check is to account for arithmetic or other operations
that may have happened on the "NULL" pointer before it is dereferenced.
On Mon, Nov 17, 2025 at 09:24:20AM -0800, Sohil Mehta wrote:
> The page fault error messages have similar logic:
>
> if (address < PAGE_SIZE && !user_mode(regs))
> pr_alert("BUG: kernel NULL pointer dereference, address: %px\n",
> (void *)address);
>
> I believe the check is to account for arithmetic or other operations
> that may have happened on the "NULL" pointer before it is dereferenced.
Ah ok, that makes sense. That comment still reads weird:
+ /*
+ * If LASS is active, a NULL pointer dereference generates a #GP
+ * instead of a #PF.
+ */
+ if (*addr < PAGE_SIZE)
It says "if LASS is active" but the check if
(cpu_feature_enabled(X86_FEATURE_LASS)) is below it.
I guess you want to have
if (cpu_feature_enabled(X86_FEATURE_LASS)) {
if (*addr < PAGE_SIZE)
return GP_NULL_POINTER;
else
return GP_LASS_VIOLATION;
}
so that it is perfectly clear.
Then the catch-all GP_CANONICAL will take care of the absurd cases, if we ever
hit them.
Thx.
--
Regards/Gruss,
Boris.
https://people.kernel.org/tglx/notes-about-netiquette
On 11/17/2025 10:29 AM, Borislav Petkov wrote:
>
> Ah ok, that makes sense. That comment still reads weird:
>
I see. The idea with the comment was to clarify why the check is outside
cpu_feature_enabled(X86_FEATURE_LASS). That clearly failed! :)
> I guess you want to have
>
> if (cpu_feature_enabled(X86_FEATURE_LASS)) {
> if (*addr < PAGE_SIZE)
> return GP_NULL_POINTER;
> else
> return GP_LASS_VIOLATION;
> }
>
> so that it is perfectly clear.
>
You are right. The condition would typically hit only with LASS enabled.
But since we are adding an extra hint for NULL pointers, I figured it
would be helpful even without LASS (even though it is unlikely to happen).
Therefore, the printed message isn't LASS specific either:
Oops: general protection fault, kernel NULL pointer dereference 0x0:
Also, it makes the code a tiny bit prettier (aesthetically, without the
nested if). We now have 4 hints and a check for each:
if (condition1)
return HINT_1;
...
if (condition4)
return HINT_4;
Would this update to the comment help clarify?
/*
* A NULL pointer dereference usually causes a #PF. However, it
* can result in a #GP when LASS is active. Provide the same
* hint in the rare case that the condition is hit without LASS.
*/
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;
Though, I won't push for it further. Code clarity is more important than
reducing indentation.
On Mon, Nov 17, 2025 at 11:45:38AM -0800, Sohil Mehta wrote:
> Would this update to the comment help clarify?
Yap, that LGTM.
> /*
> * A NULL pointer dereference usually causes a #PF. However, it
> * can result in a #GP when LASS is active. Provide the same
> * hint in the rare case that the condition is hit without LASS.
> */
> 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;
Thx.
--
Regards/Gruss,
Boris.
https://people.kernel.org/tglx/notes-about-netiquette
© 2016 - 2026 Red Hat, Inc.