aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKees Cook <keescook@chromium.org>2018-05-01 18:19:04 -0400
committerThomas Gleixner <tglx@linutronix.de>2018-05-03 07:55:51 -0400
commit7bbf1373e228840bb0295a2ca26d548ef37f448e (patch)
treeb03e2356ba64fa645695440d0519324c43f365aa
parenta73ec77ee17ec556fe7f165d00314cb7c047b1ac (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.c27
-rw-r--r--include/linux/nospec.h7
-rw-r--r--kernel/sys.c9
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
533static int ssb_prctl_set(unsigned long ctrl) 533static 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
551static int ssb_prctl_get(void) 555static 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
567int arch_prctl_spec_ctrl_set(unsigned long which, unsigned long ctrl) 571int 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
580int arch_prctl_spec_ctrl_get(unsigned long which) 585int 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
10struct 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 */
60int arch_prctl_spec_ctrl_get(unsigned long which); 62int arch_prctl_spec_ctrl_get(struct task_struct *task, unsigned long which);
61int arch_prctl_spec_ctrl_set(unsigned long which, unsigned long ctrl); 63int 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
2247int __weak arch_prctl_spec_ctrl_get(unsigned long which) 2247int __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
2252int __weak arch_prctl_spec_ctrl_set(unsigned long which, unsigned long ctrl) 2252int __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;