Commit 42fea0a3 authored by Alexander Shishkin's avatar Alexander Shishkin Committed by Dave Hansen
Browse files

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: default avatarAlexander Shishkin <alexander.shishkin@linux.intel.com>
Signed-off-by: default avatarKirill A. Shutemov <kirill.shutemov@linux.intel.com>
Signed-off-by: default avatarSohil Mehta <sohil.mehta@intel.com>
Signed-off-by: default avatarDave Hansen <dave.hansen@linux.intel.com>
Reviewed-by: default avatarDave Hansen <dave.hansen@linux.intel.com>
Link: https://patch.msgid.link/20251118182911.2983253-7-sohil.mehta%40intel.com
parent 731d4375
Loading
Loading
Loading
Loading
+33 −11
Original line number Diff line number Diff line
@@ -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,28 @@ static enum kernel_gp_hint get_kernel_gp_address(struct pt_regs *regs,
		return GP_NO_HINT;

#ifdef CONFIG_X86_64
	/* 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;

	/*
	 * Check that:
	 *  - the operand is not in the kernel half
	 *  - the last byte of the operand is not in the user canonical half
	 * 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 < ~__VIRTUAL_MASK &&
	    *addr + insn.opnd_bytes - 1 > __VIRTUAL_MASK)
		return GP_NON_CANONICAL;
	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 +857,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