[PATCHv9 13/16] x86/traps: Handle LASS thrown #SS

Kirill A. Shutemov posted 16 patches 3 months ago
There is a newer version of this series
[PATCHv9 13/16] x86/traps: Handle LASS thrown #SS
Posted by Kirill A. Shutemov 3 months ago
LASS throws a #GP for any violations except for stack register accesses,
in which case it throws a #SS instead. Handle this similarly to how other
LASS violations are handled.

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

Co-developed-by: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Signed-off-by: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
---
 arch/x86/kernel/traps.c | 41 +++++++++++++++++++++++++++++++++++------
 1 file changed, 35 insertions(+), 6 deletions(-)

diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c
index f75d6a8dcf20..0f6f187b1a9e 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";
@@ -869,6 +863,41 @@ DEFINE_IDTENTRY_ERRORCODE(exc_general_protection)
 	cond_local_irq_disable(regs);
 }
 
+#define SSFSTR "stack segment"
+
+DEFINE_IDTENTRY_ERRORCODE(exc_stack_segment)
+{
+	enum kernel_exc_hint hint;
+	unsigned long exc_addr;
+
+	if (user_mode(regs))
+		goto error_trap;
+
+	if (cpu_feature_enabled(X86_FEATURE_FRED) &&
+	    fixup_exception(regs, X86_TRAP_SS, error_code, 0))
+		return;
+
+	if (!cpu_feature_enabled(X86_FEATURE_LASS))
+		goto error_trap;
+
+	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(SSFSTR ", %s 0x%lx", kernel_exc_hint_help[hint], exc_addr);
+
+	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.47.2
Re: [PATCHv9 13/16] x86/traps: Handle LASS thrown #SS
Posted by Sohil Mehta 2 months, 4 weeks ago
On 7/7/2025 1:03 AM, Kirill A. Shutemov wrote:
> LASS throws a #GP for any violations except for stack register accesses,
> in which case it throws a #SS instead. Handle this similarly to how other
> LASS violations are handled.
> 
> In case of FRED, before handling #SS as LASS violation, kernel has to
> check if there's a fixup for the exception. It can address #SS due to
> invalid user context on ERETU. See 5105e7687ad3 ("x86/fred: Fixup
> fault on ERETU by jumping to fred_entrypoint_user") for more details.
> 
> Co-developed-by: Alexander Shishkin <alexander.shishkin@linux.intel.com>
> Signed-off-by: Alexander Shishkin <alexander.shishkin@linux.intel.com>
> Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
> ---
>  arch/x86/kernel/traps.c | 41 +++++++++++++++++++++++++++++++++++------
>  1 file changed, 35 insertions(+), 6 deletions(-)
> 

Reviewed-by: Sohil Mehta <sohil.mehta@intel.com>
Re: [PATCHv9 13/16] x86/traps: Handle LASS thrown #SS
Posted by Sohil Mehta 3 months ago
On 7/7/2025 1:03 AM, Kirill A. Shutemov wrote:

> +	hint = get_kernel_exc_address(regs, &exc_addr);
> +	if (hint != EXC_NO_HINT)
> +		printk(SSFSTR ", %s 0x%lx", kernel_exc_hint_help[hint], exc_addr);
> +
> +	if (hint != EXC_NON_CANONICAL)
> +		exc_addr = 0;
> +
> +	die_addr(SSFSTR, regs, error_code, exc_addr);

I see a slight difference between the #GP handling and the #SS handling
here. For the #GP case, we seem to pass the hint string to die_addr().

However, for the #SS, the hint is printed above and only SSFSTR gets
passed onto die_addr(). I am curious about the reasoning.

> +	return;
> +
> +error_trap:
> +	do_error_trap(regs, error_code, SSFSTR, X86_TRAP_SS, SIGBUS, 0, NULL);
> +}
> +
Re: [PATCHv9 13/16] x86/traps: Handle LASS thrown #SS
Posted by Kirill A. Shutemov 3 months ago
On Tue, Jul 08, 2025 at 10:12:28PM -0700, Sohil Mehta wrote:
> On 7/7/2025 1:03 AM, Kirill A. Shutemov wrote:
> 
> > +	hint = get_kernel_exc_address(regs, &exc_addr);
> > +	if (hint != EXC_NO_HINT)
> > +		printk(SSFSTR ", %s 0x%lx", kernel_exc_hint_help[hint], exc_addr);
> > +
> > +	if (hint != EXC_NON_CANONICAL)
> > +		exc_addr = 0;
> > +
> > +	die_addr(SSFSTR, regs, error_code, exc_addr);
> 
> I see a slight difference between the #GP handling and the #SS handling
> here. For the #GP case, we seem to pass the hint string to die_addr().
> 
> However, for the #SS, the hint is printed above and only SSFSTR gets
> passed onto die_addr(). I am curious about the reasoning.

I hate how 'desc' size is defined in #GP handler:

	char desc[sizeof(GPFSTR) + 50 + 2*sizeof(unsigned long) + 1] = GPFSTR;

Too much voodoo to my liking. And it will overflow if any hint string is
going to be longer than 50.

I don't want to repeat this magic for #SS.

I would argue we need to print directly in #GP handler as I do in #SS.
But, IMO, it is outside of the scope of this patchset.

-- 
  Kiryl Shutsemau / Kirill A. Shutemov
Re: [PATCHv9 13/16] x86/traps: Handle LASS thrown #SS
Posted by Sohil Mehta 2 months, 4 weeks ago
On 7/9/2025 3:38 AM, Kirill A. Shutemov wrote:
> On Tue, Jul 08, 2025 at 10:12:28PM -0700, Sohil Mehta wrote:
>> On 7/7/2025 1:03 AM, Kirill A. Shutemov wrote:
>>
>>> +	hint = get_kernel_exc_address(regs, &exc_addr);
>>> +	if (hint != EXC_NO_HINT)
>>> +		printk(SSFSTR ", %s 0x%lx", kernel_exc_hint_help[hint], exc_addr);
>>> +
>>> +	if (hint != EXC_NON_CANONICAL)
>>> +		exc_addr = 0;
>>> +
>>> +	die_addr(SSFSTR, regs, error_code, exc_addr);
>>
>> I see a slight difference between the #GP handling and the #SS handling
>> here. For the #GP case, we seem to pass the hint string to die_addr().
>>
>> However, for the #SS, the hint is printed above and only SSFSTR gets
>> passed onto die_addr(). I am curious about the reasoning.
> 
> I hate how 'desc' size is defined in #GP handler:
> 
> 	char desc[sizeof(GPFSTR) + 50 + 2*sizeof(unsigned long) + 1] = GPFSTR;
> 
> Too much voodoo to my liking. And it will overflow if any hint string is
> going to be longer than 50.
> 
> I don't want to repeat this magic for #SS.
> 

Thanks, that makes sense.

> I would argue we need to print directly in #GP handler as I do in #SS.
> But, IMO, it is outside of the scope of this patchset.
>