ptrace() may request an update to task->fpu that has not yet been
allocated. Detect this case and allocate task->fpu to support the request.
Also, disable the (now unnecessary) associated first-use fault.

No functional change until the kernel supports dynamic user states.

Signed-off-by: Chang S. Bae <chang.seok....@intel.com>
Reviewed-by: Len Brown <len.br...@intel.com>
Cc: x...@kernel.org
Cc: linux-kernel@vger.kernel.org
---
 arch/x86/kernel/fpu/regset.c | 29 +++++++++++++++++++++++++++++
 1 file changed, 29 insertions(+)

diff --git a/arch/x86/kernel/fpu/regset.c b/arch/x86/kernel/fpu/regset.c
index 8d863240b9c6..6b9d0c0a266d 100644
--- a/arch/x86/kernel/fpu/regset.c
+++ b/arch/x86/kernel/fpu/regset.c
@@ -125,6 +125,35 @@ int xstateregs_set(struct task_struct *target, const 
struct user_regset *regset,
 
        xsave = __xsave(fpu);
 
+       /*
+        * When a ptracer attempts to write any state in task->fpu but not 
allocated,
+        * it dynamically expands the xstate area of fpu->state_ptr.
+        */
+       if (count > get_xstate_size(fpu->state_mask)) {
+               unsigned int offset, size;
+               struct xstate_header hdr;
+               u64 mask;
+
+               offset = offsetof(struct xregs_state, header);
+               size = sizeof(hdr);
+
+               /* Retrieve XSTATE_BV */
+               if (kbuf) {
+                       memcpy(&hdr, kbuf + offset, size);
+               } else {
+                       ret = __copy_from_user(&hdr, ubuf + offset, size);
+                       if (ret)
+                               return ret;
+               }
+
+               mask = hdr.xfeatures & xfeatures_mask_user_dynamic;
+               if (!mask) {
+                       ret = alloc_xstate_area(fpu, mask, NULL);
+                       if (ret)
+                               return ret;
+               }
+       }
+
        fpu__prepare_write(fpu);
 
        if (using_compacted_format()) {
-- 
2.17.1

Reply via email to