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.
Unified · Split
| @@ -173,21 +173,24 @@ static int seccomp_check_filter(struct sock_filter *filter, unsigned int flen) · 172 unmodified lines | ||
| 173 | 173 | */ |
| 174 | 174 | static u32 seccomp_run_filters(int syscall) |
| 175 | 175 | { |
| 176 | − struct seccomp_filter *f; | |
| 176 | + struct seccomp_filter *f = ACCESS_ONCE(current->seccomp.filter); | |
| 177 | 177 | struct seccomp_data sd; |
| 178 | 178 | u32 ret = SECCOMP_RET_ALLOW; |
| 179 | 179 | |
| 180 | 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 | 182 | return SECCOMP_RET_KILL; |
| 183 | 183 | |
| 184 | + /* Make sure cross-thread synced filter points somewhere sane. */ | |
| 185 | + smp_read_barrier_depends(); | |
| 186 | + | |
| 184 | 187 | populate_seccomp_data(&sd); |
| 185 | 188 | |
| 186 | 189 | /* |
| 187 | 190 | * All filters in the list are evaluated and the lowest BPF return |
| 188 | 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 | 194 | u32 cur_ret = SK_RUN_FILTER(f->prog, (void *)&sd); |
| 192 | 195 | |
| 193 | 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) · 13 unmodified lines | ||
| 207 | 210 | return true; |
| 208 | 211 | } |
| 209 | 212 | |
| 210 | −static inline void seccomp_assign_mode(unsigned long seccomp_mode) | |
| 213 | +static inline void seccomp_assign_mode(struct task_struct *task, | |
| 214 | + unsigned long seccomp_mode) | |
| 211 | 215 | { |
| 212 | − BUG_ON(!spin_is_locked(¤t->sighand->siglock)); | |
| 216 | + BUG_ON(!spin_is_locked(&task->sighand->siglock)); | |
| 213 | 217 | |
| 214 | − current->seccomp.mode = seccomp_mode; | |
| 215 | − set_tsk_thread_flag(current, TIF_SECCOMP); | |
| 218 | + task->seccomp.mode = seccomp_mode; | |
| 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 | 227 | #ifdef CONFIG_SECCOMP_FILTER |
| @@ -435,12 +444,17 @@ static int mode1_syscalls_32[] = { · 216 unmodified lines | ||
| 435 | 444 | |
| 436 | 445 | int __secure_computing(int this_syscall) |
| 437 | 446 | { |
| 438 | − int mode = current->seccomp.mode; | |
| 439 | 447 | int exit_sig = 0; |
| 440 | 448 | int *syscall; |
| 441 | 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 | 458 | case SECCOMP_MODE_STRICT: |
| 445 | 459 | syscall = mode1_syscalls; |
| 446 | 460 | #ifdef CONFIG_COMPAT |
| @@ -545,7 +559,7 @@ static long seccomp_set_mode_strict(void) · 98 unmodified lines | ||
| 545 | 559 | #ifdef TIF_NOTSC |
| 546 | 560 | disable_TSC(); |
| 547 | 561 | #endif |
| 548 | − seccomp_assign_mode(seccomp_mode); | |
| 562 | + seccomp_assign_mode(current, seccomp_mode); | |
| 549 | 563 | ret = 0; |
| 550 | 564 | |
| 551 | 565 | out: |
| @@ -595,7 +609,7 @@ static long seccomp_set_mode_filter(unsigned int flags, · 43 unmodified lines | ||
| 595 | 609 | /* Do not free the successfully attached filter. */ |
| 596 | 610 | prepared = NULL; |
| 597 | 611 | |
| 598 | − seccomp_assign_mode(seccomp_mode); | |
| 612 | + seccomp_assign_mode(current, seccomp_mode); | |
| 599 | 613 | out: |
| 600 | 614 | spin_unlock_irq(¤t->sighand->siglock); |
| 601 | 615 | seccomp_filter_free(prepared); |