Commit 71368af9 authored by Waiman Long's avatar Waiman Long Committed by Thomas Gleixner

x86/speculation: Add PR_SPEC_DISABLE_NOEXEC

With the default SPEC_STORE_BYPASS_SECCOMP/SPEC_STORE_BYPASS_PRCTL mode,
the TIF_SSBD bit will be inherited when a new task is fork'ed or cloned.
It will also remain when a new program is execve'ed.

Only certain class of applications (like Java) that can run on behalf of
multiple users on a single thread will require disabling speculative store
bypass for security purposes. Those applications will call prctl(2) at
startup time to disable SSB. They won't rely on the fact the SSB might have
been disabled. Other applications that don't need SSBD will just move on
without checking if SSBD has been turned on or not.

The fact that the TIF_SSBD is inherited across execve(2) boundary will
cause performance of applications that don't need SSBD but their
predecessors have SSBD on to be unwittingly impacted especially if they
write to memory a lot.

To remedy this problem, a new PR_SPEC_DISABLE_NOEXEC argument for the
PR_SET_SPECULATION_CTRL option of prctl(2) is added to allow applications
to specify that the SSBD feature bit on the task structure should be
cleared whenever a new program is being execve'ed.
Suggested-by: default avatarThomas Gleixner <tglx@linutronix.de>
Signed-off-by: default avatarWaiman Long <longman@redhat.com>
Signed-off-by: default avatarThomas Gleixner <tglx@linutronix.de>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Jonathan Corbet <corbet@lwn.net>
Cc: linux-doc@vger.kernel.org
Cc: "H. Peter Anvin" <hpa@zytor.com>
Cc: Andi Kleen <ak@linux.intel.com>
Cc: David Woodhouse <dwmw@amazon.co.uk>
Cc: Jiri Kosina <jikos@kernel.org>
Cc: Josh Poimboeuf <jpoimboe@redhat.com>
Cc: Tim Chen <tim.c.chen@linux.intel.com>
Cc: KarimAllah Ahmed <karahmed@amazon.de>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Link: https://lkml.kernel.org/r/1547676096-3281-1-git-send-email-longman@redhat.com
parent 4aa9fc2a
...@@ -28,9 +28,9 @@ PR_GET_SPECULATION_CTRL returns the state of the speculation misfeature ...@@ -28,9 +28,9 @@ PR_GET_SPECULATION_CTRL returns the state of the speculation misfeature
which is selected with arg2 of prctl(2). The return value uses bits 0-3 with which is selected with arg2 of prctl(2). The return value uses bits 0-3 with
the following meaning: the following meaning:
==== ===================== =================================================== ==== ====================== ==================================================
Bit Define Description Bit Define Description
==== ===================== =================================================== ==== ====================== ==================================================
0 PR_SPEC_PRCTL Mitigation can be controlled per task by 0 PR_SPEC_PRCTL Mitigation can be controlled per task by
PR_SET_SPECULATION_CTRL. PR_SET_SPECULATION_CTRL.
1 PR_SPEC_ENABLE The speculation feature is enabled, mitigation is 1 PR_SPEC_ENABLE The speculation feature is enabled, mitigation is
...@@ -39,7 +39,9 @@ Bit Define Description ...@@ -39,7 +39,9 @@ Bit Define Description
enabled. enabled.
3 PR_SPEC_FORCE_DISABLE Same as PR_SPEC_DISABLE, but cannot be undone. A 3 PR_SPEC_FORCE_DISABLE Same as PR_SPEC_DISABLE, but cannot be undone. A
subsequent prctl(..., PR_SPEC_ENABLE) will fail. subsequent prctl(..., PR_SPEC_ENABLE) will fail.
==== ===================== =================================================== 4 PR_SPEC_DISABLE_NOEXEC Same as PR_SPEC_DISABLE, but the state will be
cleared on :manpage:`execve(2)`.
==== ====================== ==================================================
If all bits are 0 the CPU is not affected by the speculation misfeature. If all bits are 0 the CPU is not affected by the speculation misfeature.
...@@ -92,6 +94,7 @@ Speculation misfeature controls ...@@ -92,6 +94,7 @@ Speculation misfeature controls
* prctl(PR_SET_SPECULATION_CTRL, PR_SPEC_STORE_BYPASS, PR_SPEC_ENABLE, 0, 0); * prctl(PR_SET_SPECULATION_CTRL, PR_SPEC_STORE_BYPASS, PR_SPEC_ENABLE, 0, 0);
* prctl(PR_SET_SPECULATION_CTRL, PR_SPEC_STORE_BYPASS, PR_SPEC_DISABLE, 0, 0); * prctl(PR_SET_SPECULATION_CTRL, PR_SPEC_STORE_BYPASS, PR_SPEC_DISABLE, 0, 0);
* prctl(PR_SET_SPECULATION_CTRL, PR_SPEC_STORE_BYPASS, PR_SPEC_FORCE_DISABLE, 0, 0); * prctl(PR_SET_SPECULATION_CTRL, PR_SPEC_STORE_BYPASS, PR_SPEC_FORCE_DISABLE, 0, 0);
* prctl(PR_SET_SPECULATION_CTRL, PR_SPEC_STORE_BYPASS, PR_SPEC_DISABLE_NOEXEC, 0, 0);
- PR_SPEC_INDIR_BRANCH: Indirect Branch Speculation in User Processes - PR_SPEC_INDIR_BRANCH: Indirect Branch Speculation in User Processes
(Mitigate Spectre V2 style attacks against user processes) (Mitigate Spectre V2 style attacks against user processes)
......
...@@ -798,15 +798,25 @@ static int ssb_prctl_set(struct task_struct *task, unsigned long ctrl) ...@@ -798,15 +798,25 @@ static int ssb_prctl_set(struct task_struct *task, unsigned long ctrl)
if (task_spec_ssb_force_disable(task)) if (task_spec_ssb_force_disable(task))
return -EPERM; return -EPERM;
task_clear_spec_ssb_disable(task); task_clear_spec_ssb_disable(task);
task_clear_spec_ssb_noexec(task);
task_update_spec_tif(task); task_update_spec_tif(task);
break; break;
case PR_SPEC_DISABLE: case PR_SPEC_DISABLE:
task_set_spec_ssb_disable(task); task_set_spec_ssb_disable(task);
task_clear_spec_ssb_noexec(task);
task_update_spec_tif(task); task_update_spec_tif(task);
break; break;
case PR_SPEC_FORCE_DISABLE: case PR_SPEC_FORCE_DISABLE:
task_set_spec_ssb_disable(task); task_set_spec_ssb_disable(task);
task_set_spec_ssb_force_disable(task); task_set_spec_ssb_force_disable(task);
task_clear_spec_ssb_noexec(task);
task_update_spec_tif(task);
break;
case PR_SPEC_DISABLE_NOEXEC:
if (task_spec_ssb_force_disable(task))
return -EPERM;
task_set_spec_ssb_disable(task);
task_set_spec_ssb_noexec(task);
task_update_spec_tif(task); task_update_spec_tif(task);
break; break;
default: default:
...@@ -885,6 +895,8 @@ static int ssb_prctl_get(struct task_struct *task) ...@@ -885,6 +895,8 @@ static int ssb_prctl_get(struct task_struct *task)
case SPEC_STORE_BYPASS_PRCTL: case SPEC_STORE_BYPASS_PRCTL:
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;
return PR_SPEC_PRCTL | PR_SPEC_ENABLE; return PR_SPEC_PRCTL | PR_SPEC_ENABLE;
......
...@@ -255,6 +255,18 @@ void arch_setup_new_exec(void) ...@@ -255,6 +255,18 @@ void arch_setup_new_exec(void)
/* If cpuid was previously disabled for this task, re-enable it. */ /* If cpuid was previously disabled for this task, re-enable it. */
if (test_thread_flag(TIF_NOCPUID)) if (test_thread_flag(TIF_NOCPUID))
enable_cpuid(); enable_cpuid();
/*
* Don't inherit TIF_SSBD across exec boundary when
* PR_SPEC_DISABLE_NOEXEC is used.
*/
if (test_thread_flag(TIF_SSBD) &&
task_spec_ssb_noexec(current)) {
clear_thread_flag(TIF_SSBD);
task_clear_spec_ssb_disable(current);
task_clear_spec_ssb_noexec(current);
speculation_ctrl_update(task_thread_info(current)->flags);
}
} }
static inline void switch_to_bitmap(struct thread_struct *prev, static inline void switch_to_bitmap(struct thread_struct *prev,
......
...@@ -1459,6 +1459,7 @@ static inline bool is_percpu_thread(void) ...@@ -1459,6 +1459,7 @@ static inline bool is_percpu_thread(void)
#define PFA_SPEC_SSB_FORCE_DISABLE 4 /* Speculative Store Bypass force disabled*/ #define PFA_SPEC_SSB_FORCE_DISABLE 4 /* Speculative Store Bypass force disabled*/
#define PFA_SPEC_IB_DISABLE 5 /* Indirect branch speculation restricted */ #define PFA_SPEC_IB_DISABLE 5 /* Indirect branch speculation restricted */
#define PFA_SPEC_IB_FORCE_DISABLE 6 /* Indirect branch speculation permanently restricted */ #define PFA_SPEC_IB_FORCE_DISABLE 6 /* Indirect branch speculation permanently restricted */
#define PFA_SPEC_SSB_NOEXEC 7 /* Speculative Store Bypass clear on execve() */
#define TASK_PFA_TEST(name, func) \ #define TASK_PFA_TEST(name, func) \
static inline bool task_##func(struct task_struct *p) \ static inline bool task_##func(struct task_struct *p) \
...@@ -1487,6 +1488,10 @@ TASK_PFA_TEST(SPEC_SSB_DISABLE, spec_ssb_disable) ...@@ -1487,6 +1488,10 @@ TASK_PFA_TEST(SPEC_SSB_DISABLE, spec_ssb_disable)
TASK_PFA_SET(SPEC_SSB_DISABLE, spec_ssb_disable) TASK_PFA_SET(SPEC_SSB_DISABLE, spec_ssb_disable)
TASK_PFA_CLEAR(SPEC_SSB_DISABLE, spec_ssb_disable) TASK_PFA_CLEAR(SPEC_SSB_DISABLE, spec_ssb_disable)
TASK_PFA_TEST(SPEC_SSB_NOEXEC, spec_ssb_noexec)
TASK_PFA_SET(SPEC_SSB_NOEXEC, spec_ssb_noexec)
TASK_PFA_CLEAR(SPEC_SSB_NOEXEC, spec_ssb_noexec)
TASK_PFA_TEST(SPEC_SSB_FORCE_DISABLE, spec_ssb_force_disable) TASK_PFA_TEST(SPEC_SSB_FORCE_DISABLE, spec_ssb_force_disable)
TASK_PFA_SET(SPEC_SSB_FORCE_DISABLE, spec_ssb_force_disable) TASK_PFA_SET(SPEC_SSB_FORCE_DISABLE, spec_ssb_force_disable)
......
...@@ -219,6 +219,7 @@ struct prctl_mm_map { ...@@ -219,6 +219,7 @@ struct prctl_mm_map {
# define PR_SPEC_ENABLE (1UL << 1) # define PR_SPEC_ENABLE (1UL << 1)
# define PR_SPEC_DISABLE (1UL << 2) # define PR_SPEC_DISABLE (1UL << 2)
# define PR_SPEC_FORCE_DISABLE (1UL << 3) # define PR_SPEC_FORCE_DISABLE (1UL << 3)
# define PR_SPEC_DISABLE_NOEXEC (1UL << 4)
/* Reset arm64 pointer authentication keys */ /* Reset arm64 pointer authentication keys */
#define PR_PAC_RESET_KEYS 54 #define PR_PAC_RESET_KEYS 54
......
...@@ -219,6 +219,7 @@ struct prctl_mm_map { ...@@ -219,6 +219,7 @@ struct prctl_mm_map {
# define PR_SPEC_ENABLE (1UL << 1) # define PR_SPEC_ENABLE (1UL << 1)
# define PR_SPEC_DISABLE (1UL << 2) # define PR_SPEC_DISABLE (1UL << 2)
# define PR_SPEC_FORCE_DISABLE (1UL << 3) # define PR_SPEC_FORCE_DISABLE (1UL << 3)
# define PR_SPEC_DISABLE_NOEXEC (1UL << 4)
/* Reset arm64 pointer authentication keys */ /* Reset arm64 pointer authentication keys */
#define PR_PAC_RESET_KEYS 54 #define PR_PAC_RESET_KEYS 54
......
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