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

task_work: Call tracehook_notify_signal from get_signal on all architectures

Always handle TIF_NOTIFY_SIGNAL in get_signal. With commit 35d0b389f3b2
("task_work: unconditionally run task_work from get_signal()") always
calling task_work_run all of the work of tracehook_notify_signal is
already happening except clearing TIF_NOTIFY_SIGNAL.

Factor clear_notify_signal out of tracehook_notify_signal and use it in
get_signal so that get_signal only needs one call of task_work_run.

To keep the semantics in sync update xfer_to_guest_mode_work (which
does not call get_signal) to call tracehook_notify_signal if either
_TIF_SIGPENDING or _TIF_NOTIFY_SIGNAL.

Reviewed-by: Kees Cook <keescook@chromium.org>
Link: https://lkml.kernel.org/r/20220309162454.123006-8-ebiederm@xmission.com
Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>

+18 -29
+2 -2
arch/s390/kernel/signal.c
··· 453 453 * stack-frames in one go after that. 454 454 */ 455 455 456 - void arch_do_signal_or_restart(struct pt_regs *regs, bool has_signal) 456 + void arch_do_signal_or_restart(struct pt_regs *regs) 457 457 { 458 458 struct ksignal ksig; 459 459 sigset_t *oldset = sigmask_to_save(); ··· 466 466 current->thread.system_call = 467 467 test_pt_regs_flag(regs, PIF_SYSCALL) ? regs->int_code : 0; 468 468 469 - if (has_signal && get_signal(&ksig)) { 469 + if (get_signal(&ksig)) { 470 470 /* Whee! Actually deliver the signal. */ 471 471 if (current->thread.system_call) { 472 472 regs->int_code = current->thread.system_call;
+2 -2
arch/x86/kernel/signal.c
··· 861 861 * want to handle. Thus you cannot kill init even with a SIGKILL even by 862 862 * mistake. 863 863 */ 864 - void arch_do_signal_or_restart(struct pt_regs *regs, bool has_signal) 864 + void arch_do_signal_or_restart(struct pt_regs *regs) 865 865 { 866 866 struct ksignal ksig; 867 867 868 - if (has_signal && get_signal(&ksig)) { 868 + if (get_signal(&ksig)) { 869 869 /* Whee! Actually deliver the signal. */ 870 870 handle_signal(&ksig, regs); 871 871 return;
+1 -1
include/linux/entry-common.h
··· 257 257 * 258 258 * Invoked from exit_to_user_mode_loop(). 259 259 */ 260 - void arch_do_signal_or_restart(struct pt_regs *regs, bool has_signal); 260 + void arch_do_signal_or_restart(struct pt_regs *regs); 261 261 262 262 /** 263 263 * exit_to_user_mode - Fixup state when exiting to user mode
+7 -2
include/linux/tracehook.h
··· 106 106 rseq_handle_notify_resume(NULL, regs); 107 107 } 108 108 109 + static inline void clear_notify_signal(void) 110 + { 111 + clear_thread_flag(TIF_NOTIFY_SIGNAL); 112 + smp_mb__after_atomic(); 113 + } 114 + 109 115 /* 110 116 * called by exit_to_user_mode_loop() if ti_work & _TIF_NOTIFY_SIGNAL. This 111 117 * is currently used by TWA_SIGNAL based task_work, which requires breaking ··· 119 113 */ 120 114 static inline void tracehook_notify_signal(void) 121 115 { 122 - clear_thread_flag(TIF_NOTIFY_SIGNAL); 123 - smp_mb__after_atomic(); 116 + clear_notify_signal(); 124 117 if (task_work_pending(current)) 125 118 task_work_run(); 126 119 }
+2 -10
kernel/entry/common.c
··· 139 139 } 140 140 141 141 /* Workaround to allow gradual conversion of architecture code */ 142 - void __weak arch_do_signal_or_restart(struct pt_regs *regs, bool has_signal) { } 143 - 144 - static void handle_signal_work(struct pt_regs *regs, unsigned long ti_work) 145 - { 146 - if (ti_work & _TIF_NOTIFY_SIGNAL) 147 - tracehook_notify_signal(); 148 - 149 - arch_do_signal_or_restart(regs, ti_work & _TIF_SIGPENDING); 150 - } 142 + void __weak arch_do_signal_or_restart(struct pt_regs *regs) { } 151 143 152 144 static unsigned long exit_to_user_mode_loop(struct pt_regs *regs, 153 145 unsigned long ti_work) ··· 162 170 klp_update_patch_state(current); 163 171 164 172 if (ti_work & (_TIF_SIGPENDING | _TIF_NOTIFY_SIGNAL)) 165 - handle_signal_work(regs, ti_work); 173 + arch_do_signal_or_restart(regs); 166 174 167 175 if (ti_work & _TIF_NOTIFY_RESUME) 168 176 tracehook_notify_resume(regs);
+1 -1
kernel/entry/kvm.c
··· 8 8 do { 9 9 int ret; 10 10 11 - if (ti_work & _TIF_NOTIFY_SIGNAL) 11 + if (ti_work & (_TIF_SIGPENDING | _TIF_NOTIFY_SIGNAL)) 12 12 tracehook_notify_signal(); 13 13 14 14 if (ti_work & _TIF_SIGPENDING) {
+3 -11
kernel/signal.c
··· 2626 2626 struct signal_struct *signal = current->signal; 2627 2627 int signr; 2628 2628 2629 + clear_notify_signal(); 2629 2630 if (unlikely(task_work_pending(current))) 2630 2631 task_work_run(); 2631 2632 2632 - /* 2633 - * For non-generic architectures, check for TIF_NOTIFY_SIGNAL so 2634 - * that the arch handlers don't all have to do it. If we get here 2635 - * without TIF_SIGPENDING, just exit after running signal work. 2636 - */ 2637 - if (!IS_ENABLED(CONFIG_GENERIC_ENTRY)) { 2638 - if (test_thread_flag(TIF_NOTIFY_SIGNAL)) 2639 - tracehook_notify_signal(); 2640 - if (!task_sigpending(current)) 2641 - return false; 2642 - } 2633 + if (!task_sigpending(current)) 2634 + return false; 2643 2635 2644 2636 if (unlikely(uprobe_deny_signal())) 2645 2637 return false;