diff options
author | Kees Cook <keescook@chromium.org> | 2018-05-01 18:19:04 -0400 |
---|---|---|
committer | Thomas Gleixner <tglx@linutronix.de> | 2018-05-03 07:55:51 -0400 |
commit | 7bbf1373e228840bb0295a2ca26d548ef37f448e (patch) | |
tree | b03e2356ba64fa645695440d0519324c43f365aa | |
parent | a73ec77ee17ec556fe7f165d00314cb7c047b1ac (diff) |
nospec: Allow getting/setting on non-current task
Adjust arch_prctl_get/set_spec_ctrl() to operate on tasks other than
current.
This is needed both for /proc/$pid/status queries and for seccomp (since
thread-syncing can trigger seccomp in non-current threads).
Signed-off-by: Kees Cook <keescook@chromium.org>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
-rw-r--r-- | arch/x86/kernel/cpu/bugs.c | 27 | ||||
-rw-r--r-- | include/linux/nospec.h | 7 | ||||
-rw-r--r-- | kernel/sys.c | 9 |
3 files changed, 26 insertions, 17 deletions
diff --git a/arch/x86/kernel/cpu/bugs.c b/arch/x86/kernel/cpu/bugs.c index fc9187b6fae7..e3afb610f2ad 100644 --- a/arch/x86/kernel/cpu/bugs.c +++ b/arch/x86/kernel/cpu/bugs.c | |||
@@ -530,31 +530,35 @@ static void ssb_select_mitigation() | |||
530 | 530 | ||
531 | #undef pr_fmt | 531 | #undef pr_fmt |
532 | 532 | ||
533 | static int ssb_prctl_set(unsigned long ctrl) | 533 | static int ssb_prctl_set(struct task_struct *task, unsigned long ctrl) |
534 | { | 534 | { |
535 | bool rds = !!test_tsk_thread_flag(current, TIF_RDS); | 535 | bool rds = !!test_tsk_thread_flag(task, TIF_RDS); |
536 | 536 | ||
537 | if (ssb_mode != SPEC_STORE_BYPASS_PRCTL) | 537 | if (ssb_mode != SPEC_STORE_BYPASS_PRCTL) |
538 | return -ENXIO; | 538 | return -ENXIO; |
539 | 539 | ||
540 | if (ctrl == PR_SPEC_ENABLE) | 540 | if (ctrl == PR_SPEC_ENABLE) |
541 | clear_tsk_thread_flag(current, TIF_RDS); | 541 | clear_tsk_thread_flag(task, TIF_RDS); |
542 | else | 542 | else |
543 | set_tsk_thread_flag(current, TIF_RDS); | 543 | set_tsk_thread_flag(task, TIF_RDS); |
544 | 544 | ||
545 | if (rds != !!test_tsk_thread_flag(current, TIF_RDS)) | 545 | /* |
546 | * If being set on non-current task, delay setting the CPU | ||
547 | * mitigation until it is next scheduled. | ||
548 | */ | ||
549 | if (task == current && rds != !!test_tsk_thread_flag(task, TIF_RDS)) | ||
546 | speculative_store_bypass_update(); | 550 | speculative_store_bypass_update(); |
547 | 551 | ||
548 | return 0; | 552 | return 0; |
549 | } | 553 | } |
550 | 554 | ||
551 | static int ssb_prctl_get(void) | 555 | static int ssb_prctl_get(struct task_struct *task) |
552 | { | 556 | { |
553 | switch (ssb_mode) { | 557 | switch (ssb_mode) { |
554 | case SPEC_STORE_BYPASS_DISABLE: | 558 | case SPEC_STORE_BYPASS_DISABLE: |
555 | return PR_SPEC_DISABLE; | 559 | return PR_SPEC_DISABLE; |
556 | case SPEC_STORE_BYPASS_PRCTL: | 560 | case SPEC_STORE_BYPASS_PRCTL: |
557 | if (test_tsk_thread_flag(current, TIF_RDS)) | 561 | if (test_tsk_thread_flag(task, TIF_RDS)) |
558 | return PR_SPEC_PRCTL | PR_SPEC_DISABLE; | 562 | return PR_SPEC_PRCTL | PR_SPEC_DISABLE; |
559 | return PR_SPEC_PRCTL | PR_SPEC_ENABLE; | 563 | return PR_SPEC_PRCTL | PR_SPEC_ENABLE; |
560 | default: | 564 | default: |
@@ -564,24 +568,25 @@ static int ssb_prctl_get(void) | |||
564 | } | 568 | } |
565 | } | 569 | } |
566 | 570 | ||
567 | int arch_prctl_spec_ctrl_set(unsigned long which, unsigned long ctrl) | 571 | int arch_prctl_spec_ctrl_set(struct task_struct *task, unsigned long which, |
572 | unsigned long ctrl) | ||
568 | { | 573 | { |
569 | if (ctrl != PR_SPEC_ENABLE && ctrl != PR_SPEC_DISABLE) | 574 | if (ctrl != PR_SPEC_ENABLE && ctrl != PR_SPEC_DISABLE) |
570 | return -ERANGE; | 575 | return -ERANGE; |
571 | 576 | ||
572 | switch (which) { | 577 | switch (which) { |
573 | case PR_SPEC_STORE_BYPASS: | 578 | case PR_SPEC_STORE_BYPASS: |
574 | return ssb_prctl_set(ctrl); | 579 | return ssb_prctl_set(task, ctrl); |
575 | default: | 580 | default: |
576 | return -ENODEV; | 581 | return -ENODEV; |
577 | } | 582 | } |
578 | } | 583 | } |
579 | 584 | ||
580 | int arch_prctl_spec_ctrl_get(unsigned long which) | 585 | int arch_prctl_spec_ctrl_get(struct task_struct *task, unsigned long which) |
581 | { | 586 | { |
582 | switch (which) { | 587 | switch (which) { |
583 | case PR_SPEC_STORE_BYPASS: | 588 | case PR_SPEC_STORE_BYPASS: |
584 | return ssb_prctl_get(); | 589 | return ssb_prctl_get(task); |
585 | default: | 590 | default: |
586 | return -ENODEV; | 591 | return -ENODEV; |
587 | } | 592 | } |
diff --git a/include/linux/nospec.h b/include/linux/nospec.h index 700bb8a4e4ea..a908c954484d 100644 --- a/include/linux/nospec.h +++ b/include/linux/nospec.h | |||
@@ -7,6 +7,8 @@ | |||
7 | #define _LINUX_NOSPEC_H | 7 | #define _LINUX_NOSPEC_H |
8 | #include <asm/barrier.h> | 8 | #include <asm/barrier.h> |
9 | 9 | ||
10 | struct task_struct; | ||
11 | |||
10 | /** | 12 | /** |
11 | * array_index_mask_nospec() - generate a ~0 mask when index < size, 0 otherwise | 13 | * array_index_mask_nospec() - generate a ~0 mask when index < size, 0 otherwise |
12 | * @index: array element index | 14 | * @index: array element index |
@@ -57,7 +59,8 @@ static inline unsigned long array_index_mask_nospec(unsigned long index, | |||
57 | }) | 59 | }) |
58 | 60 | ||
59 | /* Speculation control prctl */ | 61 | /* Speculation control prctl */ |
60 | int arch_prctl_spec_ctrl_get(unsigned long which); | 62 | int arch_prctl_spec_ctrl_get(struct task_struct *task, unsigned long which); |
61 | int arch_prctl_spec_ctrl_set(unsigned long which, unsigned long ctrl); | 63 | int arch_prctl_spec_ctrl_set(struct task_struct *task, unsigned long which, |
64 | unsigned long ctrl); | ||
62 | 65 | ||
63 | #endif /* _LINUX_NOSPEC_H */ | 66 | #endif /* _LINUX_NOSPEC_H */ |
diff --git a/kernel/sys.c b/kernel/sys.c index b76dee23bdc9..b0eee418ee0d 100644 --- a/kernel/sys.c +++ b/kernel/sys.c | |||
@@ -2244,12 +2244,13 @@ static int propagate_has_child_subreaper(struct task_struct *p, void *data) | |||
2244 | return 1; | 2244 | return 1; |
2245 | } | 2245 | } |
2246 | 2246 | ||
2247 | int __weak arch_prctl_spec_ctrl_get(unsigned long which) | 2247 | int __weak arch_prctl_spec_ctrl_get(struct task_struct *t, unsigned long which) |
2248 | { | 2248 | { |
2249 | return -EINVAL; | 2249 | return -EINVAL; |
2250 | } | 2250 | } |
2251 | 2251 | ||
2252 | int __weak arch_prctl_spec_ctrl_set(unsigned long which, unsigned long ctrl) | 2252 | int __weak arch_prctl_spec_ctrl_set(struct task_struct *t, unsigned long which, |
2253 | unsigned long ctrl) | ||
2253 | { | 2254 | { |
2254 | return -EINVAL; | 2255 | return -EINVAL; |
2255 | } | 2256 | } |
@@ -2465,12 +2466,12 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3, | |||
2465 | case PR_GET_SPECULATION_CTRL: | 2466 | case PR_GET_SPECULATION_CTRL: |
2466 | if (arg3 || arg4 || arg5) | 2467 | if (arg3 || arg4 || arg5) |
2467 | return -EINVAL; | 2468 | return -EINVAL; |
2468 | error = arch_prctl_spec_ctrl_get(arg2); | 2469 | error = arch_prctl_spec_ctrl_get(me, arg2); |
2469 | break; | 2470 | break; |
2470 | case PR_SET_SPECULATION_CTRL: | 2471 | case PR_SET_SPECULATION_CTRL: |
2471 | if (arg4 || arg5) | 2472 | if (arg4 || arg5) |
2472 | return -EINVAL; | 2473 | return -EINVAL; |
2473 | error = arch_prctl_spec_ctrl_set(arg2, arg3); | 2474 | error = arch_prctl_spec_ctrl_set(me, arg2, arg3); |
2474 | break; | 2475 | break; |
2475 | default: | 2476 | default: |
2476 | error = -EINVAL; | 2477 | error = -EINVAL; |