Re: [PATCH] x86/fpu: verify xstate buffer size according with requested features

From: Thomas Gleixner
Date: Mon Jan 22 2024 - 08:26:20 EST


On Sun, Jan 21 2024 at 19:58, Andrei Vagin wrote:
> On Thu, Jan 18, 2024 at 2:11 PM Thomas Gleixner <tglx@xxxxxxxxxxxxx> wrote:
>> >> After staring more at it, it's arguable to pass fpstate->user_size to
>> >> fault_in_readable() and ignore fx_sw->xstate_size completely.
>> >>
>> >> That's a guaranteed to be reliable size which prevents endless loops
>> >> because arguably that's the maximum size which can be touched by XRSTOR,
>> >> no?
>
> fpstate->user_size isn't constant. It can be modified from the XFD #NM
> handler. For example, it happens when a process invokes one of amx
> instructions for the first time. It means we have to be able to restore
> an fpu state from signal frames generated with a smaller
> fpstate->user_size. Can it trigger any issues?

I know, but the #NM handler does not run in the signal restore
path. fpstate->user_size is guaranteed to be correct at that point.

The untested below should just work.

Thanks,

tglx
---
--- a/arch/x86/kernel/fpu/signal.c
+++ b/arch/x86/kernel/fpu/signal.c
@@ -274,8 +274,7 @@ static int __restore_fpregs_from_user(vo
* Attempt to restore the FPU registers directly from user memory.
* Pagefaults are handled and any errors returned are fatal.
*/
-static bool restore_fpregs_from_user(void __user *buf, u64 xrestore,
- bool fx_only, unsigned int size)
+static bool restore_fpregs_from_user(void __user *buf, u64 xrestore, bool fx_only)
{
struct fpu *fpu = &current->thread.fpu;
int ret;
@@ -309,7 +308,7 @@ static bool restore_fpregs_from_user(voi
if (ret != X86_TRAP_PF)
return false;

- if (!fault_in_readable(buf, size))
+ if (!fault_in_readable(buf, fpu->fpstate->user_size))
goto retry;
return false;
}
@@ -339,7 +338,6 @@ static bool __fpu_restore_sig(void __use
struct user_i387_ia32_struct env;
bool success, fx_only = false;
union fpregs_state *fpregs;
- unsigned int state_size;
u64 user_xfeatures = 0;

if (use_xsave()) {
@@ -349,17 +347,14 @@ static bool __fpu_restore_sig(void __use
return false;

fx_only = !fx_sw_user.magic1;
- state_size = fx_sw_user.xstate_size;
user_xfeatures = fx_sw_user.xfeatures;
} else {
user_xfeatures = XFEATURE_MASK_FPSSE;
- state_size = fpu->fpstate->user_size;
}

if (likely(!ia32_fxstate)) {
/* Restore the FPU registers directly from user memory. */
- return restore_fpregs_from_user(buf_fx, user_xfeatures, fx_only,
- state_size);
+ return restore_fpregs_from_user(buf_fx, user_xfeatures, fx_only);
}

/*