| From fb2d6033b64347297b424b302309a00592b353f5 Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Wed, 23 Jun 2021 14:02:30 +0200 |
| Subject: x86/fpu: Return proper error codes from user access functions |
| |
| From: Thomas Gleixner <tglx@linutronix.de> |
| |
| [ Upstream commit aee8c67a4faa40a8df4e79316dbfc92d123989c1 ] |
| |
| When *RSTOR from user memory raises an exception, there is no way to |
| differentiate them. That's bad because it forces the slow path even when |
| the failure was not a fault. If the operation raised eg. #GP then going |
| through the slow path is pointless. |
| |
| Use _ASM_EXTABLE_FAULT() which stores the trap number and let the exception |
| fixup return the negated trap number as error. |
| |
| This allows to separate the fast path and let it handle faults directly and |
| avoid the slow path for all other exceptions. |
| |
| Signed-off-by: Thomas Gleixner <tglx@linutronix.de> |
| Signed-off-by: Borislav Petkov <bp@suse.de> |
| Link: https://lkml.kernel.org/r/20210623121457.601480369@linutronix.de |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| arch/x86/include/asm/fpu/internal.h | 19 ++++++++++++------- |
| 1 file changed, 12 insertions(+), 7 deletions(-) |
| |
| diff --git a/arch/x86/include/asm/fpu/internal.h b/arch/x86/include/asm/fpu/internal.h |
| index 16bf4d4a8159..4e5af2b00d89 100644 |
| --- a/arch/x86/include/asm/fpu/internal.h |
| +++ b/arch/x86/include/asm/fpu/internal.h |
| @@ -103,6 +103,7 @@ static inline void fpstate_init_fxstate(struct fxregs_state *fx) |
| } |
| extern void fpstate_sanitize_xstate(struct fpu *fpu); |
| |
| +/* Returns 0 or the negated trap number, which results in -EFAULT for #PF */ |
| #define user_insn(insn, output, input...) \ |
| ({ \ |
| int err; \ |
| @@ -110,14 +111,14 @@ extern void fpstate_sanitize_xstate(struct fpu *fpu); |
| might_fault(); \ |
| \ |
| asm volatile(ASM_STAC "\n" \ |
| - "1:" #insn "\n\t" \ |
| + "1: " #insn "\n" \ |
| "2: " ASM_CLAC "\n" \ |
| ".section .fixup,\"ax\"\n" \ |
| - "3: movl $-1,%[err]\n" \ |
| + "3: negl %%eax\n" \ |
| " jmp 2b\n" \ |
| ".previous\n" \ |
| - _ASM_EXTABLE(1b, 3b) \ |
| - : [err] "=r" (err), output \ |
| + _ASM_EXTABLE_FAULT(1b, 3b) \ |
| + : [err] "=a" (err), output \ |
| : "0"(0), input); \ |
| err; \ |
| }) |
| @@ -219,16 +220,20 @@ static inline void fxsave(struct fxregs_state *fx) |
| #define XRSTOR ".byte " REX_PREFIX "0x0f,0xae,0x2f" |
| #define XRSTORS ".byte " REX_PREFIX "0x0f,0xc7,0x1f" |
| |
| +/* |
| + * After this @err contains 0 on success or the negated trap number when |
| + * the operation raises an exception. For faults this results in -EFAULT. |
| + */ |
| #define XSTATE_OP(op, st, lmask, hmask, err) \ |
| asm volatile("1:" op "\n\t" \ |
| "xor %[err], %[err]\n" \ |
| "2:\n\t" \ |
| ".pushsection .fixup,\"ax\"\n\t" \ |
| - "3: movl $-2,%[err]\n\t" \ |
| + "3: negl %%eax\n\t" \ |
| "jmp 2b\n\t" \ |
| ".popsection\n\t" \ |
| - _ASM_EXTABLE(1b, 3b) \ |
| - : [err] "=r" (err) \ |
| + _ASM_EXTABLE_FAULT(1b, 3b) \ |
| + : [err] "=a" (err) \ |
| : "D" (st), "m" (*st), "a" (lmask), "d" (hmask) \ |
| : "memory") |
| |
| -- |
| 2.30.2 |
| |