[PATCH] x86/fpu: Set XFEATURE_PKRU when writing to pkru

From: Brian Geffon
Date: Tue Nov 09 2021 - 12:08:25 EST


On kernels prior to 5.14 the write_pkru path could
end up writing to the pkru register without updating
the corresponding state.

Signed-off-by: Brian Geffon <bgeffon@xxxxxxxxxx>
---
arch/x86/include/asm/fpu/internal.h | 22 ++++++++++------------
arch/x86/include/asm/pgtable.h | 5 +++--
2 files changed, 13 insertions(+), 14 deletions(-)

diff --git a/arch/x86/include/asm/fpu/internal.h
b/arch/x86/include/asm/fpu/internal.h
index 16bf4d4a8159..ed2ce7d1afeb 100644
--- a/arch/x86/include/asm/fpu/internal.h
+++ b/arch/x86/include/asm/fpu/internal.h
@@ -564,18 +564,16 @@ static inline void switch_fpu_finish(struct fpu *new_=
fpu)
* PKRU state is switched eagerly because it needs to be valid befo=
re we
* return to userland e.g. for a copy_to_user() operation.
*/
- if (!(current->flags & PF_KTHREAD)) {
- /*
- * If the PKRU bit in xsave.header.xfeatures is not set,
- * then the PKRU component was in init state, which means
- * XRSTOR will set PKRU to 0. If the bit is not set then
- * get_xsave_addr() will return NULL because the PKRU value
- * in memory is not valid. This means pkru_val has to be
- * set to 0 and not to init_pkru_value.
- */
- pk =3D get_xsave_addr(&new_fpu->state.xsave, XFEATURE_PKRU)=
;
- pkru_val =3D pk ? pk->pkru : 0;
- }
+ /*
+ * If the PKRU bit in xsave.header.xfeatures is not set,
+ * then the PKRU component was in init state, which means
+ * XRSTOR will set PKRU to 0. If the bit is not set then
+ * get_xsave_addr() will return NULL because the PKRU value
+ * in memory is not valid. This means pkru_val has to be
+ * set to 0 and not to init_pkru_value.
+ */
+ pk =3D get_xsave_addr(&new_fpu->state.xsave, XFEATURE_PKRU);
+ pkru_val =3D pk ? pk->pkru : 0;
__write_pkru(pkru_val);
}

diff --git a/arch/x86/include/asm/pgtable.h b/arch/x86/include/asm/pgtable.=
h
index b1099f2d9800..d00fc2df4cfe 100644
--- a/arch/x86/include/asm/pgtable.h
+++ b/arch/x86/include/asm/pgtable.h
@@ -137,18 +137,19 @@ static inline u32 read_pkru(void)
static inline void write_pkru(u32 pkru)
{
struct pkru_state *pk;
+ struct fpu *fpu =3D &current->thread.fpu;

if (!boot_cpu_has(X86_FEATURE_OSPKE))
return;

- pk =3D get_xsave_addr(&current->thread.fpu.state.xsave, XFEATURE_PK=
RU);
-
/*
* The PKRU value in xstate needs to be in sync with the value that=
is
* written to the CPU. The FPU restore on return to userland would
* otherwise load the previous value again.
*/
+ fpu->state.xsave.header.xfeatures |=3D XFEATURE_MASK_PKRU;
fpregs_lock();
+ pk =3D get_xsave_addr(&fpu->state.xsave, XFEATURE_PKRU);
if (pk)
pk->pkru =3D pkru;
__write_pkru(pkru);
--=20
2.34.0.rc0.344.g81b53c2807-goog