Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Kees Cook and committed by
Thomas Gleixner
7bbf1373 a73ec77e

+26 -17
+16 -11
arch/x86/kernel/cpu/bugs.c
··· 530 530 531 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 537 if (ssb_mode != SPEC_STORE_BYPASS_PRCTL) 538 538 return -ENXIO; 539 539 540 540 if (ctrl == PR_SPEC_ENABLE) 541 - clear_tsk_thread_flag(current, TIF_RDS); 541 + clear_tsk_thread_flag(task, TIF_RDS); 542 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 550 speculative_store_bypass_update(); 547 551 548 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 557 switch (ssb_mode) { 554 558 case SPEC_STORE_BYPASS_DISABLE: 555 559 return PR_SPEC_DISABLE; 556 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 562 return PR_SPEC_PRCTL | PR_SPEC_DISABLE; 559 563 return PR_SPEC_PRCTL | PR_SPEC_ENABLE; 560 564 default: ··· 568 564 } 569 565 } 570 566 571 - int arch_prctl_spec_ctrl_set(unsigned long which, unsigned long ctrl) 567 + int arch_prctl_spec_ctrl_set(struct task_struct *task, unsigned long which, 568 + unsigned long ctrl) 572 569 { 573 570 if (ctrl != PR_SPEC_ENABLE && ctrl != PR_SPEC_DISABLE) 574 571 return -ERANGE; 575 572 576 573 switch (which) { 577 574 case PR_SPEC_STORE_BYPASS: 578 - return ssb_prctl_set(ctrl); 575 + return ssb_prctl_set(task, ctrl); 579 576 default: 580 577 return -ENODEV; 581 578 } 582 579 } 583 580 584 - int arch_prctl_spec_ctrl_get(unsigned long which) 581 + int arch_prctl_spec_ctrl_get(struct task_struct *task, unsigned long which) 585 582 { 586 583 switch (which) { 587 584 case PR_SPEC_STORE_BYPASS: 588 - return ssb_prctl_get(); 585 + return ssb_prctl_get(task); 589 586 default: 590 587 return -ENODEV; 591 588 }
+5 -2
include/linux/nospec.h
··· 7 7 #define _LINUX_NOSPEC_H 8 8 #include <asm/barrier.h> 9 9 10 + struct task_struct; 11 + 10 12 /** 11 13 * array_index_mask_nospec() - generate a ~0 mask when index < size, 0 otherwise 12 14 * @index: array element index ··· 59 57 }) 60 58 61 59 /* Speculation control prctl */ 62 - int arch_prctl_spec_ctrl_get(unsigned long which); 63 - int arch_prctl_spec_ctrl_set(unsigned long which, unsigned long ctrl); 60 + int arch_prctl_spec_ctrl_get(struct task_struct *task, unsigned long which); 61 + int arch_prctl_spec_ctrl_set(struct task_struct *task, unsigned long which, 62 + unsigned long ctrl); 64 63 65 64 #endif /* _LINUX_NOSPEC_H */
+5 -4
kernel/sys.c
··· 2244 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 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 2255 return -EINVAL; 2255 2256 } ··· 2466 2465 case PR_GET_SPECULATION_CTRL: 2467 2466 if (arg3 || arg4 || arg5) 2468 2467 return -EINVAL; 2469 - error = arch_prctl_spec_ctrl_get(arg2); 2468 + error = arch_prctl_spec_ctrl_get(me, arg2); 2470 2469 break; 2471 2470 case PR_SET_SPECULATION_CTRL: 2472 2471 if (arg4 || arg5) 2473 2472 return -EINVAL; 2474 - error = arch_prctl_spec_ctrl_set(arg2, arg3); 2473 + error = arch_prctl_spec_ctrl_set(me, arg2, arg3); 2475 2474 break; 2476 2475 default: 2477 2476 error = -EINVAL;