x86/traps: Communicate a LASS violation in #GP message

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>
Signed-off-by: Dave Hansen <dave.hansen@linux.intel.com>
Reviewed-by: Dave Hansen <dave.hansen@linux.intel.com>
Link: https://patch.msgid.link/20251118182911.2983253-7-sohil.mehta%40intel.com
This commit is contained in:
Alexander Shishkin 2025-11-18 10:29:08 -08:00 committed by Dave Hansen
parent 731d43750c
commit 42fea0a3a7
1 changed files with 34 additions and 12 deletions

View File

@ -635,13 +635,23 @@ DEFINE_IDTENTRY(exc_bounds)
enum kernel_gp_hint { enum kernel_gp_hint {
GP_NO_HINT, GP_NO_HINT,
GP_NON_CANONICAL, 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 * 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 * 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, static enum kernel_gp_hint get_kernel_gp_address(struct pt_regs *regs,
unsigned long *addr) unsigned long *addr)
@ -663,14 +673,28 @@ static enum kernel_gp_hint get_kernel_gp_address(struct pt_regs *regs,
return GP_NO_HINT; return GP_NO_HINT;
#ifdef CONFIG_X86_64 #ifdef CONFIG_X86_64
/* /* Operand is in the kernel half */
* Check that: if (*addr >= ~__VIRTUAL_MASK)
* - the operand is not in the kernel half return GP_CANONICAL;
* - the last byte of the operand is not in the user canonical half
*/ /* The last byte of the operand is not in the user canonical half */
if (*addr < ~__VIRTUAL_MASK && if (*addr + insn.opnd_bytes - 1 > __VIRTUAL_MASK)
*addr + insn.opnd_bytes - 1 > __VIRTUAL_MASK)
return GP_NON_CANONICAL; return GP_NON_CANONICAL;
/*
* 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;
#endif #endif
return GP_CANONICAL; return GP_CANONICAL;
@ -833,9 +857,7 @@ DEFINE_IDTENTRY_ERRORCODE(exc_general_protection)
if (hint != GP_NO_HINT) if (hint != GP_NO_HINT)
snprintf(desc, sizeof(desc), GPFSTR ", %s 0x%lx", snprintf(desc, sizeof(desc), GPFSTR ", %s 0x%lx",
(hint == GP_NON_CANONICAL) ? "probably for non-canonical address" kernel_gp_hint_help[hint], gp_addr);
: "maybe for address",
gp_addr);
/* /*
* KASAN is interested only in the non-canonical case, clear it * KASAN is interested only in the non-canonical case, clear it