x86/fpu: Sanitize xstateregs_set()
[linux-2.6-microblaze.git] / arch / x86 / kernel / fpu / regset.c
index 6bb8744..a50c0a9 100644 (file)
@@ -2,11 +2,13 @@
 /*
  * FPU register's regset abstraction, for ptrace, core dumps, etc.
  */
+#include <linux/sched/task_stack.h>
+#include <linux/vmalloc.h>
+
 #include <asm/fpu/internal.h>
 #include <asm/fpu/signal.h>
 #include <asm/fpu/regset.h>
 #include <asm/fpu/xstate.h>
-#include <linux/sched/task_stack.h>
 
 /*
  * The xstateregs_active() routine is the same as the regset_fpregs_active() routine,
@@ -108,10 +110,10 @@ int xstateregs_set(struct task_struct *target, const struct user_regset *regset,
                  const void *kbuf, const void __user *ubuf)
 {
        struct fpu *fpu = &target->thread.fpu;
-       struct xregs_state *xsave;
+       struct xregs_state *tmpbuf = NULL;
        int ret;
 
-       if (!boot_cpu_has(X86_FEATURE_XSAVE))
+       if (!cpu_feature_enabled(X86_FEATURE_XSAVE))
                return -ENODEV;
 
        /*
@@ -120,32 +122,22 @@ int xstateregs_set(struct task_struct *target, const struct user_regset *regset,
        if (pos != 0 || count != fpu_user_xstate_size)
                return -EFAULT;
 
-       xsave = &fpu->state.xsave;
-
-       fpu__prepare_write(fpu);
+       if (!kbuf) {
+               tmpbuf = vmalloc(count);
+               if (!tmpbuf)
+                       return -ENOMEM;
 
-       if (using_compacted_format()) {
-               if (kbuf)
-                       ret = copy_kernel_to_xstate(xsave, kbuf);
-               else
-                       ret = copy_user_to_xstate(xsave, ubuf);
-       } else {
-               ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, xsave, 0, -1);
-               if (!ret)
-                       ret = validate_user_xstate_header(&xsave->header);
+               if (copy_from_user(tmpbuf, ubuf, count)) {
+                       ret = -EFAULT;
+                       goto out;
+               }
        }
 
-       /*
-        * mxcsr reserved bits must be masked to zero for security reasons.
-        */
-       xsave->i387.mxcsr &= mxcsr_feature_mask;
-
-       /*
-        * In case of failure, mark all states as init:
-        */
-       if (ret)
-               fpstate_init(&fpu->state);
+       fpu__prepare_write(fpu);
+       ret = copy_kernel_to_xstate(&fpu->state.xsave, kbuf ?: tmpbuf);
 
+out:
+       vfree(tmpbuf);
        return ret;
 }