]>
Commit | Line | Data |
---|---|---|
1f91e7a4 GKH |
1 | From foo@baz Tue 14 May 2019 08:29:35 PM CEST |
2 | From: Jiri Kosina <jkosina@suse.cz> | |
3 | Date: Tue, 25 Sep 2018 14:38:18 +0200 | |
4 | Subject: x86/speculation: Apply IBPB more strictly to avoid cross-process data leak | |
5 | ||
6 | From: Jiri Kosina <jkosina@suse.cz> | |
7 | ||
8 | commit dbfe2953f63c640463c630746cd5d9de8b2f63ae upstream. | |
9 | ||
10 | Currently, IBPB is only issued in cases when switching into a non-dumpable | |
11 | process, the rationale being to protect such 'important and security | |
12 | sensitive' processess (such as GPG) from data leaking into a different | |
13 | userspace process via spectre v2. | |
14 | ||
15 | This is however completely insufficient to provide proper userspace-to-userpace | |
16 | spectrev2 protection, as any process can poison branch buffers before being | |
17 | scheduled out, and the newly scheduled process immediately becomes spectrev2 | |
18 | victim. | |
19 | ||
20 | In order to minimize the performance impact (for usecases that do require | |
21 | spectrev2 protection), issue the barrier only in cases when switching between | |
22 | processess where the victim can't be ptraced by the potential attacker (as in | |
23 | such cases, the attacker doesn't have to bother with branch buffers at all). | |
24 | ||
25 | [ tglx: Split up PTRACE_MODE_NOACCESS_CHK into PTRACE_MODE_SCHED and | |
26 | PTRACE_MODE_IBPB to be able to do ptrace() context tracking reasonably | |
27 | fine-grained ] | |
28 | ||
29 | Fixes: 18bf3c3ea8 ("x86/speculation: Use Indirect Branch Prediction Barrier in context switch") | |
30 | Originally-by: Tim Chen <tim.c.chen@linux.intel.com> | |
31 | Signed-off-by: Jiri Kosina <jkosina@suse.cz> | |
32 | Signed-off-by: Thomas Gleixner <tglx@linutronix.de> | |
33 | Cc: Peter Zijlstra <peterz@infradead.org> | |
34 | Cc: Josh Poimboeuf <jpoimboe@redhat.com> | |
35 | Cc: Andrea Arcangeli <aarcange@redhat.com> | |
36 | Cc: "WoodhouseDavid" <dwmw@amazon.co.uk> | |
37 | Cc: Andi Kleen <ak@linux.intel.com> | |
38 | Cc: "SchauflerCasey" <casey.schaufler@intel.com> | |
39 | Link: https://lkml.kernel.org/r/nycvar.YFH.7.76.1809251437340.15880@cbobk.fhfr.pm | |
40 | Signed-off-by: Ben Hutchings <ben@decadent.org.uk> | |
41 | Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | |
42 | --- | |
43 | arch/x86/mm/tlb.c | 31 ++++++++++++++++++++----------- | |
44 | include/linux/ptrace.h | 21 +++++++++++++++++++-- | |
45 | kernel/ptrace.c | 10 ++++++++++ | |
46 | 3 files changed, 49 insertions(+), 13 deletions(-) | |
47 | ||
48 | --- a/arch/x86/mm/tlb.c | |
49 | +++ b/arch/x86/mm/tlb.c | |
50 | @@ -7,6 +7,7 @@ | |
51 | #include <linux/module.h> | |
52 | #include <linux/cpu.h> | |
53 | #include <linux/debugfs.h> | |
54 | +#include <linux/ptrace.h> | |
55 | ||
56 | #include <asm/tlbflush.h> | |
57 | #include <asm/mmu_context.h> | |
58 | @@ -101,6 +102,19 @@ void switch_mm(struct mm_struct *prev, s | |
59 | local_irq_restore(flags); | |
60 | } | |
61 | ||
62 | +static bool ibpb_needed(struct task_struct *tsk, u64 last_ctx_id) | |
63 | +{ | |
64 | + /* | |
65 | + * Check if the current (previous) task has access to the memory | |
66 | + * of the @tsk (next) task. If access is denied, make sure to | |
67 | + * issue a IBPB to stop user->user Spectre-v2 attacks. | |
68 | + * | |
69 | + * Note: __ptrace_may_access() returns 0 or -ERRNO. | |
70 | + */ | |
71 | + return (tsk && tsk->mm && tsk->mm->context.ctx_id != last_ctx_id && | |
72 | + ptrace_may_access_sched(tsk, PTRACE_MODE_SPEC_IBPB)); | |
73 | +} | |
74 | + | |
75 | void switch_mm_irqs_off(struct mm_struct *prev, struct mm_struct *next, | |
76 | struct task_struct *tsk) | |
77 | { | |
78 | @@ -115,18 +129,13 @@ void switch_mm_irqs_off(struct mm_struct | |
79 | * one process from doing Spectre-v2 attacks on another. | |
80 | * | |
81 | * As an optimization, flush indirect branches only when | |
82 | - * switching into processes that disable dumping. This | |
83 | - * protects high value processes like gpg, without having | |
84 | - * too high performance overhead. IBPB is *expensive*! | |
85 | - * | |
86 | - * This will not flush branches when switching into kernel | |
87 | - * threads. It will also not flush if we switch to idle | |
88 | - * thread and back to the same process. It will flush if we | |
89 | - * switch to a different non-dumpable process. | |
90 | + * switching into a processes that can't be ptrace by the | |
91 | + * current one (as in such case, attacker has much more | |
92 | + * convenient way how to tamper with the next process than | |
93 | + * branch buffer poisoning). | |
94 | */ | |
95 | - if (tsk && tsk->mm && | |
96 | - tsk->mm->context.ctx_id != last_ctx_id && | |
97 | - get_dumpable(tsk->mm) != SUID_DUMP_USER) | |
98 | + if (static_cpu_has(X86_FEATURE_USE_IBPB) && | |
99 | + ibpb_needed(tsk, last_ctx_id)) | |
100 | indirect_branch_prediction_barrier(); | |
101 | ||
102 | /* | |
103 | --- a/include/linux/ptrace.h | |
104 | +++ b/include/linux/ptrace.h | |
105 | @@ -57,14 +57,17 @@ extern void exit_ptrace(struct task_stru | |
106 | #define PTRACE_MODE_READ 0x01 | |
107 | #define PTRACE_MODE_ATTACH 0x02 | |
108 | #define PTRACE_MODE_NOAUDIT 0x04 | |
109 | -#define PTRACE_MODE_FSCREDS 0x08 | |
110 | -#define PTRACE_MODE_REALCREDS 0x10 | |
111 | +#define PTRACE_MODE_FSCREDS 0x08 | |
112 | +#define PTRACE_MODE_REALCREDS 0x10 | |
113 | +#define PTRACE_MODE_SCHED 0x20 | |
114 | +#define PTRACE_MODE_IBPB 0x40 | |
115 | ||
116 | /* shorthands for READ/ATTACH and FSCREDS/REALCREDS combinations */ | |
117 | #define PTRACE_MODE_READ_FSCREDS (PTRACE_MODE_READ | PTRACE_MODE_FSCREDS) | |
118 | #define PTRACE_MODE_READ_REALCREDS (PTRACE_MODE_READ | PTRACE_MODE_REALCREDS) | |
119 | #define PTRACE_MODE_ATTACH_FSCREDS (PTRACE_MODE_ATTACH | PTRACE_MODE_FSCREDS) | |
120 | #define PTRACE_MODE_ATTACH_REALCREDS (PTRACE_MODE_ATTACH | PTRACE_MODE_REALCREDS) | |
121 | +#define PTRACE_MODE_SPEC_IBPB (PTRACE_MODE_ATTACH_REALCREDS | PTRACE_MODE_IBPB) | |
122 | ||
123 | /** | |
124 | * ptrace_may_access - check whether the caller is permitted to access | |
125 | @@ -82,6 +85,20 @@ extern void exit_ptrace(struct task_stru | |
126 | */ | |
127 | extern bool ptrace_may_access(struct task_struct *task, unsigned int mode); | |
128 | ||
129 | +/** | |
130 | + * ptrace_may_access - check whether the caller is permitted to access | |
131 | + * a target task. | |
132 | + * @task: target task | |
133 | + * @mode: selects type of access and caller credentials | |
134 | + * | |
135 | + * Returns true on success, false on denial. | |
136 | + * | |
137 | + * Similar to ptrace_may_access(). Only to be called from context switch | |
138 | + * code. Does not call into audit and the regular LSM hooks due to locking | |
139 | + * constraints. | |
140 | + */ | |
141 | +extern bool ptrace_may_access_sched(struct task_struct *task, unsigned int mode); | |
142 | + | |
143 | static inline int ptrace_reparented(struct task_struct *child) | |
144 | { | |
145 | return !same_thread_group(child->real_parent, child->parent); | |
146 | --- a/kernel/ptrace.c | |
147 | +++ b/kernel/ptrace.c | |
148 | @@ -228,6 +228,9 @@ static int ptrace_check_attach(struct ta | |
149 | ||
150 | static int ptrace_has_cap(struct user_namespace *ns, unsigned int mode) | |
151 | { | |
152 | + if (mode & PTRACE_MODE_SCHED) | |
153 | + return false; | |
154 | + | |
155 | if (mode & PTRACE_MODE_NOAUDIT) | |
156 | return has_ns_capability_noaudit(current, ns, CAP_SYS_PTRACE); | |
157 | else | |
158 | @@ -295,9 +298,16 @@ ok: | |
159 | !ptrace_has_cap(mm->user_ns, mode))) | |
160 | return -EPERM; | |
161 | ||
162 | + if (mode & PTRACE_MODE_SCHED) | |
163 | + return 0; | |
164 | return security_ptrace_access_check(task, mode); | |
165 | } | |
166 | ||
167 | +bool ptrace_may_access_sched(struct task_struct *task, unsigned int mode) | |
168 | +{ | |
169 | + return __ptrace_may_access(task, mode | PTRACE_MODE_SCHED); | |
170 | +} | |
171 | + | |
172 | bool ptrace_may_access(struct task_struct *task, unsigned int mode) | |
173 | { | |
174 | int err; |