Commit 780c083a authored by Will Deacon's avatar Will Deacon

arm64: Add support for PR_SPEC_DISABLE_NOEXEC prctl() option

The PR_SPEC_DISABLE_NOEXEC option to the PR_SPEC_STORE_BYPASS prctl()
allows the SSB mitigation to be enabled only until the next execve(),
at which point the state will revert back to PR_SPEC_ENABLE and the
mitigation will be disabled.

Add support for PR_SPEC_DISABLE_NOEXEC on arm64.
Reported-by: default avatarAnthony Steinhauser <asteinhauser@google.com>
Signed-off-by: default avatarWill Deacon <will@kernel.org>
parent 5c8b0cbd
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include <linux/lockdep.h> #include <linux/lockdep.h>
#include <linux/mman.h> #include <linux/mman.h>
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/nospec.h>
#include <linux/stddef.h> #include <linux/stddef.h>
#include <linux/sysctl.h> #include <linux/sysctl.h>
#include <linux/unistd.h> #include <linux/unistd.h>
...@@ -609,6 +610,11 @@ void arch_setup_new_exec(void) ...@@ -609,6 +610,11 @@ void arch_setup_new_exec(void)
current->mm->context.flags = is_compat_task() ? MMCF_AARCH32 : 0; current->mm->context.flags = is_compat_task() ? MMCF_AARCH32 : 0;
ptrauth_thread_init_user(current); ptrauth_thread_init_user(current);
if (task_spec_ssb_noexec(current)) {
arch_prctl_spec_ctrl_set(current, PR_SPEC_STORE_BYPASS,
PR_SPEC_ENABLE);
}
} }
#ifdef CONFIG_ARM64_TAGGED_ADDR_ABI #ifdef CONFIG_ARM64_TAGGED_ADDR_ABI
......
...@@ -660,6 +660,20 @@ void spectre_v4_enable_task_mitigation(struct task_struct *tsk) ...@@ -660,6 +660,20 @@ void spectre_v4_enable_task_mitigation(struct task_struct *tsk)
* prctl() may be necessary even when PSTATE.SSBS can be toggled directly * prctl() may be necessary even when PSTATE.SSBS can be toggled directly
* from userspace. * from userspace.
*/ */
static void ssbd_prctl_enable_mitigation(struct task_struct *task)
{
task_clear_spec_ssb_noexec(task);
task_set_spec_ssb_disable(task);
set_tsk_thread_flag(task, TIF_SSBD);
}
static void ssbd_prctl_disable_mitigation(struct task_struct *task)
{
task_clear_spec_ssb_noexec(task);
task_clear_spec_ssb_disable(task);
clear_tsk_thread_flag(task, TIF_SSBD);
}
static int ssbd_prctl_set(struct task_struct *task, unsigned long ctrl) static int ssbd_prctl_set(struct task_struct *task, unsigned long ctrl)
{ {
switch (ctrl) { switch (ctrl) {
...@@ -679,8 +693,7 @@ static int ssbd_prctl_set(struct task_struct *task, unsigned long ctrl) ...@@ -679,8 +693,7 @@ static int ssbd_prctl_set(struct task_struct *task, unsigned long ctrl)
if (spectre_v4_mitigations_on()) if (spectre_v4_mitigations_on())
return -EPERM; return -EPERM;
task_clear_spec_ssb_disable(task); ssbd_prctl_disable_mitigation(task);
clear_tsk_thread_flag(task, TIF_SSBD);
break; break;
case PR_SPEC_FORCE_DISABLE: case PR_SPEC_FORCE_DISABLE:
/* Force disable speculation: force enable mitigation */ /* Force disable speculation: force enable mitigation */
...@@ -699,8 +712,22 @@ static int ssbd_prctl_set(struct task_struct *task, unsigned long ctrl) ...@@ -699,8 +712,22 @@ static int ssbd_prctl_set(struct task_struct *task, unsigned long ctrl)
if (spectre_v4_mitigations_off()) if (spectre_v4_mitigations_off())
return -EPERM; return -EPERM;
task_set_spec_ssb_disable(task); ssbd_prctl_enable_mitigation(task);
set_tsk_thread_flag(task, TIF_SSBD); break;
case PR_SPEC_DISABLE_NOEXEC:
/* Disable speculation until execve(): enable mitigation */
/*
* If the mitigation state is forced one way or the other, then
* we must fail now before we try to toggle it on execve().
*/
if (task_spec_ssb_force_disable(task) ||
spectre_v4_mitigations_off() ||
spectre_v4_mitigations_on()) {
return -EPERM;
}
ssbd_prctl_enable_mitigation(task);
task_set_spec_ssb_noexec(task);
break; break;
default: default:
return -ERANGE; return -ERANGE;
...@@ -745,6 +772,9 @@ static int ssbd_prctl_get(struct task_struct *task) ...@@ -745,6 +772,9 @@ static int ssbd_prctl_get(struct task_struct *task)
if (task_spec_ssb_force_disable(task)) if (task_spec_ssb_force_disable(task))
return PR_SPEC_PRCTL | PR_SPEC_FORCE_DISABLE; return PR_SPEC_PRCTL | PR_SPEC_FORCE_DISABLE;
if (task_spec_ssb_noexec(task))
return PR_SPEC_PRCTL | PR_SPEC_DISABLE_NOEXEC;
if (task_spec_ssb_disable(task)) if (task_spec_ssb_disable(task))
return PR_SPEC_PRCTL | PR_SPEC_DISABLE; return PR_SPEC_PRCTL | PR_SPEC_DISABLE;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment