aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/seccomp.c
diff options
context:
space:
mode:
authorKees Cook <keescook@chromium.org>2014-06-27 18:01:35 -0400
committerKees Cook <keescook@chromium.org>2014-07-18 15:13:40 -0400
commit3ba2530cc06eb4aee4f1f754f43d781e8a12ee09 (patch)
tree29a898621ce07eabf881ef40123f2882d7dccc1a /kernel/seccomp.c
parentdbd952127d11bb44a4ea30b08cc60531b6a23d71 (diff)
seccomp: allow mode setting across threads
This changes the mode setting helper to allow threads to change the seccomp mode from another thread. We must maintain barriers to keep TIF_SECCOMP synchronized with the rest of the seccomp state. Signed-off-by: Kees Cook <keescook@chromium.org> Reviewed-by: Oleg Nesterov <oleg@redhat.com> Reviewed-by: Andy Lutomirski <luto@amacapital.net>
Diffstat (limited to 'kernel/seccomp.c')
-rw-r--r--kernel/seccomp.c36
1 files changed, 25 insertions, 11 deletions
diff --git a/kernel/seccomp.c b/kernel/seccomp.c
index d5543e787e4e..9065d2c79c56 100644
--- a/kernel/seccomp.c
+++ b/kernel/seccomp.c
@@ -173,21 +173,24 @@ static int seccomp_check_filter(struct sock_filter *filter, unsigned int flen)
173 */ 173 */
174static u32 seccomp_run_filters(int syscall) 174static u32 seccomp_run_filters(int syscall)
175{ 175{
176 struct seccomp_filter *f; 176 struct seccomp_filter *f = ACCESS_ONCE(current->seccomp.filter);
177 struct seccomp_data sd; 177 struct seccomp_data sd;
178 u32 ret = SECCOMP_RET_ALLOW; 178 u32 ret = SECCOMP_RET_ALLOW;
179 179
180 /* Ensure unexpected behavior doesn't result in failing open. */ 180 /* Ensure unexpected behavior doesn't result in failing open. */
181 if (WARN_ON(current->seccomp.filter == NULL)) 181 if (unlikely(WARN_ON(f == NULL)))
182 return SECCOMP_RET_KILL; 182 return SECCOMP_RET_KILL;
183 183
184 /* Make sure cross-thread synced filter points somewhere sane. */
185 smp_read_barrier_depends();
186
184 populate_seccomp_data(&sd); 187 populate_seccomp_data(&sd);
185 188
186 /* 189 /*
187 * All filters in the list are evaluated and the lowest BPF return 190 * All filters in the list are evaluated and the lowest BPF return
188 * value always takes priority (ignoring the DATA). 191 * value always takes priority (ignoring the DATA).
189 */ 192 */
190 for (f = current->seccomp.filter; f; f = f->prev) { 193 for (; f; f = f->prev) {
191 u32 cur_ret = SK_RUN_FILTER(f->prog, (void *)&sd); 194 u32 cur_ret = SK_RUN_FILTER(f->prog, (void *)&sd);
192 195
193 if ((cur_ret & SECCOMP_RET_ACTION) < (ret & SECCOMP_RET_ACTION)) 196 if ((cur_ret & SECCOMP_RET_ACTION) < (ret & SECCOMP_RET_ACTION))
@@ -207,12 +210,18 @@ static inline bool seccomp_may_assign_mode(unsigned long seccomp_mode)
207 return true; 210 return true;
208} 211}
209 212
210static inline void seccomp_assign_mode(unsigned long seccomp_mode) 213static inline void seccomp_assign_mode(struct task_struct *task,
214 unsigned long seccomp_mode)
211{ 215{
212 BUG_ON(!spin_is_locked(&current->sighand->siglock)); 216 BUG_ON(!spin_is_locked(&task->sighand->siglock));
213 217
214 current->seccomp.mode = seccomp_mode; 218 task->seccomp.mode = seccomp_mode;
215 set_tsk_thread_flag(current, TIF_SECCOMP); 219 /*
220 * Make sure TIF_SECCOMP cannot be set before the mode (and
221 * filter) is set.
222 */
223 smp_mb__before_atomic();
224 set_tsk_thread_flag(task, TIF_SECCOMP);
216} 225}
217 226
218#ifdef CONFIG_SECCOMP_FILTER 227#ifdef CONFIG_SECCOMP_FILTER
@@ -435,12 +444,17 @@ static int mode1_syscalls_32[] = {
435 444
436int __secure_computing(int this_syscall) 445int __secure_computing(int this_syscall)
437{ 446{
438 int mode = current->seccomp.mode;
439 int exit_sig = 0; 447 int exit_sig = 0;
440 int *syscall; 448 int *syscall;
441 u32 ret; 449 u32 ret;
442 450
443 switch (mode) { 451 /*
452 * Make sure that any changes to mode from another thread have
453 * been seen after TIF_SECCOMP was seen.
454 */
455 rmb();
456
457 switch (current->seccomp.mode) {
444 case SECCOMP_MODE_STRICT: 458 case SECCOMP_MODE_STRICT:
445 syscall = mode1_syscalls; 459 syscall = mode1_syscalls;
446#ifdef CONFIG_COMPAT 460#ifdef CONFIG_COMPAT
@@ -545,7 +559,7 @@ static long seccomp_set_mode_strict(void)
545#ifdef TIF_NOTSC 559#ifdef TIF_NOTSC
546 disable_TSC(); 560 disable_TSC();
547#endif 561#endif
548 seccomp_assign_mode(seccomp_mode); 562 seccomp_assign_mode(current, seccomp_mode);
549 ret = 0; 563 ret = 0;
550 564
551out: 565out:
@@ -595,7 +609,7 @@ static long seccomp_set_mode_filter(unsigned int flags,
595 /* Do not free the successfully attached filter. */ 609 /* Do not free the successfully attached filter. */
596 prepared = NULL; 610 prepared = NULL;
597 611
598 seccomp_assign_mode(seccomp_mode); 612 seccomp_assign_mode(current, seccomp_mode);
599out: 613out:
600 spin_unlock_irq(&current->sighand->siglock); 614 spin_unlock_irq(&current->sighand->siglock);
601 seccomp_filter_free(prepared); 615 seccomp_filter_free(prepared);