[PATCH v11 28/29] x86/arch_prctl: ARCH_GET_FEATURES_WITH_KERNEL_ASSISTANCE

From: Chang S. Bae
Date: Fri Oct 01 2021 - 18:46:20 EST


arch_prctl(ARCH_GET_FEATURES_WITH_KERNEL_ASSISTANCE, u64 *bitmask)
Return the bitmask of the kernel-supported features. If XSAVE is
disabled, the bitmask indicates only legacy states.

Suggested-by: Borislav Petkov <bp@xxxxxxx>
Signed-off-by: Chang S. Bae <chang.seok.bae@xxxxxxxxx>
Cc: x86@xxxxxxxxxx
Cc: linux-kernel@xxxxxxxxxxxxxxx
---
Changes from v9:
* Add as a new patch. (Thiago Macieira and Borislav Petkov)
---
arch/x86/include/uapi/asm/prctl.h | 23 +++++++++++----------
arch/x86/kernel/fpu/xstate.c | 34 ++++++++++++++++++++-----------
arch/x86/kernel/process.c | 1 +
3 files changed, 35 insertions(+), 23 deletions(-)

diff --git a/arch/x86/include/uapi/asm/prctl.h b/arch/x86/include/uapi/asm/prctl.h
index c73e141ce90a..6912d5fe85f3 100644
--- a/arch/x86/include/uapi/asm/prctl.h
+++ b/arch/x86/include/uapi/asm/prctl.h
@@ -2,19 +2,20 @@
#ifndef _ASM_X86_PRCTL_H
#define _ASM_X86_PRCTL_H

-#define ARCH_SET_GS 0x1001
-#define ARCH_SET_FS 0x1002
-#define ARCH_GET_FS 0x1003
-#define ARCH_GET_GS 0x1004
+#define ARCH_SET_GS 0x1001
+#define ARCH_SET_FS 0x1002
+#define ARCH_GET_FS 0x1003
+#define ARCH_GET_GS 0x1004

-#define ARCH_GET_CPUID 0x1011
-#define ARCH_SET_CPUID 0x1012
+#define ARCH_GET_CPUID 0x1011
+#define ARCH_SET_CPUID 0x1012

-#define ARCH_SET_STATE_ENABLE 0x1021
-#define ARCH_GET_STATE_ENABLE 0x1022
+#define ARCH_GET_FEATURES_WITH_KERNEL_ASSISTANCE 0x1020
+#define ARCH_SET_STATE_ENABLE 0x1021
+#define ARCH_GET_STATE_ENABLE 0x1022

-#define ARCH_MAP_VDSO_X32 0x2001
-#define ARCH_MAP_VDSO_32 0x2002
-#define ARCH_MAP_VDSO_64 0x2003
+#define ARCH_MAP_VDSO_X32 0x2001
+#define ARCH_MAP_VDSO_32 0x2002
+#define ARCH_MAP_VDSO_64 0x2003

#endif /* _ASM_X86_PRCTL_H */
diff --git a/arch/x86/kernel/fpu/xstate.c b/arch/x86/kernel/fpu/xstate.c
index 81566a18643b..75db4def5ec5 100644
--- a/arch/x86/kernel/fpu/xstate.c
+++ b/arch/x86/kernel/fpu/xstate.c
@@ -1299,6 +1299,24 @@ int realloc_xstate_buffer(struct fpu *fpu, u64 mask)
return 0;
}

+/**
+ * get_features_mask_uabi - Get a feature list that the kernel supports
+ * Return: A bitmap that indicates which state the kernel enabled.
+ */
+static u64 get_features_mask_uabi(void)
+{
+ if (!cpu_feature_enabled(X86_FEATURE_FPU))
+ return 0;
+
+ if (use_xsave())
+ return xfeatures_mask_uabi();
+
+ if (use_fxsr())
+ return XFEATURE_MASK_FPSSE;
+
+ return XFEATURE_MASK_FP;
+}
+
/**
* reset_state_perm - Reset a task's permission for dynamic user state
*
@@ -1329,7 +1347,7 @@ void reset_state_perm(struct task_struct *tsk)
}

/**
- * do_arch_prctl_state - Read or write the state permission.
+ * do_arch_prctl_state - Handle xstate-related buffer or usage control
* @fpu: A struct task_struct * pointer
* @option: A subfunction of arch_prctl()
* @arg2: Either a pointer to userspace memory or state-component
@@ -1338,22 +1356,14 @@ void reset_state_perm(struct task_struct *tsk)
*/
long do_arch_prctl_state(struct task_struct *tsk, int option, unsigned long arg2)
{
- u64 features_mask;
-
- if (!cpu_feature_enabled(X86_FEATURE_FPU))
- features_mask = 0;
- else if (use_fxsr())
- features_mask = XFEATURE_MASK_FPSSE;
- else
- features_mask = XFEATURE_MASK_FP;
+ u64 features_mask = get_features_mask_uabi();

switch (option) {
+ case ARCH_GET_FEATURES_WITH_KERNEL_ASSISTANCE:
+ return put_user(features_mask, (unsigned long __user *)arg2);
case ARCH_SET_STATE_ENABLE: {
u64 state_perm = arg2;

- if (use_xsave())
- features_mask = xfeatures_mask_uabi();
-
if (state_perm & ~features_mask)
return -EINVAL;

diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c
index b43e2b0f52f2..ae53ffd76882 100644
--- a/arch/x86/kernel/process.c
+++ b/arch/x86/kernel/process.c
@@ -1023,6 +1023,7 @@ long do_arch_prctl_common(struct task_struct *task, int option,
return get_cpuid_mode();
case ARCH_SET_CPUID:
return set_cpuid_mode(task, arg2);
+ case ARCH_GET_FEATURES_WITH_KERNEL_ASSISTANCE:
case ARCH_SET_STATE_ENABLE:
case ARCH_GET_STATE_ENABLE:
return do_arch_prctl_state(task, option, arg2);
--
2.17.1