[PATCH v10 12/28] x86/fpu/xstate: Update the XSTATE context copy function to support dynamic states

From: Chang S. Bae
Date: Wed Aug 25 2021 - 12:01:40 EST


ptrace() and signal return paths use XSTATE context copy functions. They
allow callers to read XSTATE values in the target's buffer. With dynamic
user states, a component's position in the buffer may vary and the init
fpstate is not always large enough to cover all the states.

Introduce a new helper to adjust to find the source address correctly.

Signed-off-by: Chang S. Bae <chang.seok.bae@xxxxxxxxx>
Reviewed-by: Len Brown <len.brown@xxxxxxxxx>
Cc: x86@xxxxxxxxxx
Cc: linux-kernel@xxxxxxxxxxxxxxx
---
Changes from v9:
* Refactor the new code in the loop. (Borislav Petkov)
* Move out the copy_uabi_to_xstate() changes (to Patch1,9). (Borislav
Petkov)

Changes from v5:
* Updated to ensure xstate_bv aligned with the target.
* Rewrote the xstate copy loop, for the ptrace() read path, in an open
code.
* Adjusted the changelog.

Changes from v3:
* Cleaned up the code change with more comments.
* Removed 'no functional change' in the changelog. (Borislav Petkov)

Changes from v2:
* Updated the changelog with task->fpu removed. (Borislav Petkov)
---
arch/x86/kernel/fpu/xstate.c | 29 +++++++++++++++++++++++++----
1 file changed, 25 insertions(+), 4 deletions(-)

diff --git a/arch/x86/kernel/fpu/xstate.c b/arch/x86/kernel/fpu/xstate.c
index 6929db20be0a..bd6a5c746d3f 100644
--- a/arch/x86/kernel/fpu/xstate.c
+++ b/arch/x86/kernel/fpu/xstate.c
@@ -1152,6 +1152,30 @@ static void copy_feature(bool from_xstate, struct membuf *to, void *xstate,
membuf_write(to, from_xstate ? xstate : init_xstate, size);
}

+static void copy_extended_feature(struct membuf *to, struct fpu *fpu,
+ struct xstate_header *hdr,
+ int feature_nr)
+{
+ unsigned int size = xstate_sizes[feature_nr];
+ u64 mask = BIT_ULL(feature_nr);
+ void *from = NULL;
+
+ /*
+ * Copy from the XSTATE buffer if available. Otherwise, write the
+ * init value as recorded for legacy states (FP and SSE) or as
+ * zeros for others.
+ */
+ if (hdr->xfeatures & mask) {
+ from = __raw_xsave_addr(fpu, feature_nr);
+ membuf_write(to, from, size);
+ } else if (XFEATURE_MASK_FPSSE & mask) {
+ from = __raw_xsave_addr(NULL, feature_nr);
+ membuf_write(to, from, size);
+ } else {
+ membuf_zero(to, size);
+ }
+}
+
/**
* copy_xstate_to_uabi_buf - Copy kernel saved xstate to a UABI buffer
* @to: membuf descriptor
@@ -1253,10 +1277,7 @@ void copy_xstate_to_uabi_buf(struct membuf to, struct task_struct *tsk,
pkru.pkru = tsk->thread.pkru;
membuf_write(&to, &pkru, sizeof(pkru));
} else {
- copy_feature(header.xfeatures & BIT_ULL(i), &to,
- __raw_xsave_addr(&tsk->thread.fpu, i),
- __raw_xsave_addr(NULL, i),
- xstate_sizes[i]);
+ copy_extended_feature(&to, &tsk->thread.fpu, &header, i);
}
/*
* Keep track of the last copied state in the non-compacted
--
2.17.1