[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20210523193259.26200-17-chang.seok.bae@intel.com>
Date: Sun, 23 May 2021 12:32:47 -0700
From: "Chang S. Bae" <chang.seok.bae@...el.com>
To: bp@...e.de, luto@...nel.org, tglx@...utronix.de, mingo@...nel.org,
x86@...nel.org
Cc: len.brown@...el.com, dave.hansen@...el.com, jing2.liu@...el.com,
ravi.v.shankar@...el.com, linux-kernel@...r.kernel.org,
chang.seok.bae@...el.com
Subject: [PATCH v5 16/28] x86/fpu/xstate: Support ptracer-induced xstate buffer expansion
ptrace() may update xstate data before the target task has taken an XFD
fault and expanded the xstate buffer. Detect this case and allocate a
sufficient buffer to support the request. Also, disable the (now
unnecessary) associated first-use fault.
Signed-off-by: Chang S. Bae <chang.seok.bae@...el.com>
Reviewed-by: Len Brown <len.brown@...el.com>
Cc: x86@...nel.org
Cc: linux-kernel@...r.kernel.org
---
Changes from v4:
* Improved the condition check for the expansion.
* Simplified the XSTATE_BV retrieval.
* Updated the code comment.
Changes from v3:
* Removed 'no functional changes' in the changelog. (Borislav Petkov)
Changes from v2:
* Updated the changelog with task->fpu removed. (Borislav Petkov)
* Updated the code comments.
---
arch/x86/kernel/fpu/regset.c | 32 ++++++++++++++++++++++++++++++++
1 file changed, 32 insertions(+)
diff --git a/arch/x86/kernel/fpu/regset.c b/arch/x86/kernel/fpu/regset.c
index ee27df4caed6..b2fac4b5e483 100644
--- a/arch/x86/kernel/fpu/regset.c
+++ b/arch/x86/kernel/fpu/regset.c
@@ -122,6 +122,38 @@ int xstateregs_set(struct task_struct *target, const struct user_regset *regset,
xsave = &fpu->state->xsave;
+ /*
+ * When a ptracer attempts to write any dynamic user state in the target buffer but not
+ * sufficiently allocated, it dynamically expands the buffer.
+ *
+ * Check if the expansion is possibly needed.
+ */
+ if (xfeatures_mask_user_dynamic &&
+ ((fpu->state_mask & xfeatures_mask_user_dynamic) != xfeatures_mask_user_dynamic)) {
+ unsigned int offset, size;
+ u64 state_mask;
+
+ offset = offsetof(struct xregs_state, header);
+ size = sizeof(u64);
+
+ /* Retrieve XSTATE_BV. */
+ if (kbuf) {
+ memcpy(&state_mask, kbuf + offset, size);
+ } else {
+ ret = __copy_from_user(&state_mask, ubuf + offset, size);
+ if (ret)
+ return ret;
+ }
+
+ /* Expand the xstate buffer based on the XSTATE_BV. */
+ state_mask &= xfeatures_mask_user_dynamic;
+ if (state_mask) {
+ ret = alloc_xstate_buffer(fpu, state_mask);
+ if (ret)
+ return ret;
+ }
+ }
+
fpu__prepare_write(fpu);
if (using_compacted_format()) {
--
2.17.1
Powered by blists - more mailing lists