summaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel/fpu/regset.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86/kernel/fpu/regset.c')
-rw-r--r--arch/x86/kernel/fpu/regset.c37
1 files changed, 23 insertions, 14 deletions
diff --git a/arch/x86/kernel/fpu/regset.c b/arch/x86/kernel/fpu/regset.c
index d60e77d39222..f24ce873bfc2 100644
--- a/arch/x86/kernel/fpu/regset.c
+++ b/arch/x86/kernel/fpu/regset.c
@@ -47,30 +47,39 @@ int xfpregs_set(struct task_struct *target, const struct user_regset *regset,
const void *kbuf, const void __user *ubuf)
{
struct fpu *fpu = &target->thread.fpu;
+ struct user32_fxsr_struct newstate;
int ret;
- if (!boot_cpu_has(X86_FEATURE_FXSR))
+ BUILD_BUG_ON(sizeof(newstate) != sizeof(struct fxregs_state));
+
+ if (!cpu_feature_enabled(X86_FEATURE_FXSR))
return -ENODEV;
+ /* No funny business with partial or oversized writes is permitted. */
+ if (pos != 0 || count != sizeof(newstate))
+ return -EINVAL;
+
+ ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &newstate, 0, -1);
+ if (ret)
+ return ret;
+
+ /* Mask invalid MXCSR bits (for historical reasons). */
+ newstate.mxcsr &= mxcsr_feature_mask;
+
fpu__prepare_write(fpu);
- fpstate_sanitize_xstate(fpu);
- ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
- &fpu->state.fxsave, 0, -1);
+ /* Copy the state */
+ memcpy(&fpu->state.fxsave, &newstate, sizeof(newstate));
- /*
- * mxcsr reserved bits must be masked to zero for security reasons.
- */
- fpu->state.fxsave.mxcsr &= mxcsr_feature_mask;
+ /* Clear xmm8..15 */
+ BUILD_BUG_ON(sizeof(fpu->state.fxsave.xmm_space) != 16 * 16);
+ memset(&fpu->state.fxsave.xmm_space[8], 0, 8 * 16);
- /*
- * update the header bits in the xsave header, indicating the
- * presence of FP and SSE state.
- */
- if (boot_cpu_has(X86_FEATURE_XSAVE))
+ /* Mark FP and SSE as in use when XSAVE is enabled */
+ if (use_xsave())
fpu->state.xsave.header.xfeatures |= XFEATURE_MASK_FPSSE;
- return ret;
+ return 0;
}
int xstateregs_get(struct task_struct *target, const struct user_regset *regset,