Add three new arch_prctl() handles: - ARCH_THREAD_FEATURE_ENABLE/DISABLE enables or disables the specified features. Returns what features are enabled after the operation. - ARCH_THREAD_FEATURE_LOCK prevents future disabling or enabling of the specified features. Returns the new set of locked features. The features handled per-thread and inherited over fork(2)/clone(2), but reset on exec(). This is preparation patch. It does not impelement any features. Signed-off-by: Kirill A. Shutemov <kirill.shutemov@xxxxxxxxxxxxxxx> --- arch/x86/include/asm/processor.h | 3 +++ arch/x86/include/uapi/asm/prctl.h | 5 +++++ arch/x86/kernel/process.c | 37 +++++++++++++++++++++++++++++++ 3 files changed, 45 insertions(+) diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h index 91d0f93a00c7..ff0c34e18cc6 100644 --- a/arch/x86/include/asm/processor.h +++ b/arch/x86/include/asm/processor.h @@ -530,6 +530,9 @@ struct thread_struct { */ u32 pkru; + unsigned long features; + unsigned long features_locked; + /* Floating point and extended processor state */ struct fpu fpu; /* diff --git a/arch/x86/include/uapi/asm/prctl.h b/arch/x86/include/uapi/asm/prctl.h index 500b96e71f18..67fc30d36c73 100644 --- a/arch/x86/include/uapi/asm/prctl.h +++ b/arch/x86/include/uapi/asm/prctl.h @@ -20,4 +20,9 @@ #define ARCH_MAP_VDSO_32 0x2002 #define ARCH_MAP_VDSO_64 0x2003 +/* Never implement 0x3001, it will confuse old glibc's */ +#define ARCH_THREAD_FEATURE_ENABLE 0x3002 +#define ARCH_THREAD_FEATURE_DISABLE 0x3003 +#define ARCH_THREAD_FEATURE_LOCK 0x3004 + #endif /* _ASM_X86_PRCTL_H */ diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c index b370767f5b19..cb8fc28f2eae 100644 --- a/arch/x86/kernel/process.c +++ b/arch/x86/kernel/process.c @@ -367,6 +367,10 @@ void arch_setup_new_exec(void) task_clear_spec_ssb_noexec(current); speculation_ctrl_update(read_thread_flags()); } + + /* Reset thread features on exec */ + current->thread.features = 0; + current->thread.features_locked = 0; } #ifdef CONFIG_X86_IOPL_IOPERM @@ -985,6 +989,35 @@ unsigned long __get_wchan(struct task_struct *p) return addr; } +static long thread_feature_prctl(struct task_struct *task, int option, + unsigned long features) +{ + const unsigned long known_features = 0; + + if (features & ~known_features) + return -EINVAL; + + if (option == ARCH_THREAD_FEATURE_LOCK) { + task->thread.features_locked |= features; + return task->thread.features_locked; + } + + /* Do not allow to change locked features */ + if (features & task->thread.features_locked) + return -EPERM; + + if (option == ARCH_THREAD_FEATURE_DISABLE) { + task->thread.features &= ~features; + goto out; + } + + /* Handle ARCH_THREAD_FEATURE_ENABLE */ + + task->thread.features |= features; +out: + return task->thread.features; +} + long do_arch_prctl_common(struct task_struct *task, int option, unsigned long arg2) { @@ -999,6 +1032,10 @@ long do_arch_prctl_common(struct task_struct *task, int option, case ARCH_GET_XCOMP_GUEST_PERM: case ARCH_REQ_XCOMP_GUEST_PERM: return fpu_xstate_prctl(task, option, arg2); + case ARCH_THREAD_FEATURE_ENABLE: + case ARCH_THREAD_FEATURE_DISABLE: + case ARCH_THREAD_FEATURE_LOCK: + return thread_feature_prctl(task, option, arg2); } return -EINVAL; -- 2.35.1