diff options
-rw-r--r-- | include/linux/tracehook.h | 29 | ||||
-rw-r--r-- | kernel/signal.c | 38 |
2 files changed, 56 insertions, 11 deletions
diff --git a/include/linux/tracehook.h b/include/linux/tracehook.h index 3548694a24db..42a0d7b11959 100644 --- a/include/linux/tracehook.h +++ b/include/linux/tracehook.h | |||
@@ -422,4 +422,33 @@ static inline int tracehook_consider_fatal_signal(struct task_struct *task, | |||
422 | return (task_ptrace(task) & PT_PTRACED) != 0; | 422 | return (task_ptrace(task) & PT_PTRACED) != 0; |
423 | } | 423 | } |
424 | 424 | ||
425 | /** | ||
426 | * tracehook_get_signal - deliver synthetic signal to traced task | ||
427 | * @task: @current | ||
428 | * @regs: task_pt_regs(@current) | ||
429 | * @info: details of synthetic signal | ||
430 | * @return_ka: sigaction for synthetic signal | ||
431 | * | ||
432 | * Return zero to check for a real pending signal normally. | ||
433 | * Return -1 after releasing the siglock to repeat the check. | ||
434 | * Return a signal number to induce an artifical signal delivery, | ||
435 | * setting *@info and *@return_ka to specify its details and behavior. | ||
436 | * | ||
437 | * The @return_ka->sa_handler value controls the disposition of the | ||
438 | * signal, no matter the signal number. For %SIG_DFL, the return value | ||
439 | * is a representative signal to indicate the behavior (e.g. %SIGTERM | ||
440 | * for death, %SIGQUIT for core dump, %SIGSTOP for job control stop, | ||
441 | * %SIGTSTP for stop unless in an orphaned pgrp), but the signal number | ||
442 | * reported will be @info->si_signo instead. | ||
443 | * | ||
444 | * Called with @task->sighand->siglock held, before dequeuing pending signals. | ||
445 | */ | ||
446 | static inline int tracehook_get_signal(struct task_struct *task, | ||
447 | struct pt_regs *regs, | ||
448 | siginfo_t *info, | ||
449 | struct k_sigaction *return_ka) | ||
450 | { | ||
451 | return 0; | ||
452 | } | ||
453 | |||
425 | #endif /* <linux/tracehook.h> */ | 454 | #endif /* <linux/tracehook.h> */ |
diff --git a/kernel/signal.c b/kernel/signal.c index 1a942ce32ba0..10b31ecdd9c8 100644 --- a/kernel/signal.c +++ b/kernel/signal.c | |||
@@ -1754,17 +1754,33 @@ relock: | |||
1754 | do_signal_stop(0)) | 1754 | do_signal_stop(0)) |
1755 | goto relock; | 1755 | goto relock; |
1756 | 1756 | ||
1757 | signr = dequeue_signal(current, ¤t->blocked, info); | 1757 | /* |
1758 | if (!signr) | 1758 | * Tracing can induce an artifical signal and choose sigaction. |
1759 | break; /* will return 0 */ | 1759 | * The return value in @signr determines the default action, |
1760 | * but @info->si_signo is the signal number we will report. | ||
1761 | */ | ||
1762 | signr = tracehook_get_signal(current, regs, info, return_ka); | ||
1763 | if (unlikely(signr < 0)) | ||
1764 | goto relock; | ||
1765 | if (unlikely(signr != 0)) | ||
1766 | ka = return_ka; | ||
1767 | else { | ||
1768 | signr = dequeue_signal(current, ¤t->blocked, | ||
1769 | info); | ||
1760 | 1770 | ||
1761 | if (signr != SIGKILL) { | ||
1762 | signr = ptrace_signal(signr, info, regs, cookie); | ||
1763 | if (!signr) | 1771 | if (!signr) |
1764 | continue; | 1772 | break; /* will return 0 */ |
1773 | |||
1774 | if (signr != SIGKILL) { | ||
1775 | signr = ptrace_signal(signr, info, | ||
1776 | regs, cookie); | ||
1777 | if (!signr) | ||
1778 | continue; | ||
1779 | } | ||
1780 | |||
1781 | ka = &sighand->action[signr-1]; | ||
1765 | } | 1782 | } |
1766 | 1783 | ||
1767 | ka = &sighand->action[signr-1]; | ||
1768 | if (ka->sa.sa_handler == SIG_IGN) /* Do nothing. */ | 1784 | if (ka->sa.sa_handler == SIG_IGN) /* Do nothing. */ |
1769 | continue; | 1785 | continue; |
1770 | if (ka->sa.sa_handler != SIG_DFL) { | 1786 | if (ka->sa.sa_handler != SIG_DFL) { |
@@ -1812,7 +1828,7 @@ relock: | |||
1812 | spin_lock_irq(&sighand->siglock); | 1828 | spin_lock_irq(&sighand->siglock); |
1813 | } | 1829 | } |
1814 | 1830 | ||
1815 | if (likely(do_signal_stop(signr))) { | 1831 | if (likely(do_signal_stop(info->si_signo))) { |
1816 | /* It released the siglock. */ | 1832 | /* It released the siglock. */ |
1817 | goto relock; | 1833 | goto relock; |
1818 | } | 1834 | } |
@@ -1833,7 +1849,7 @@ relock: | |||
1833 | 1849 | ||
1834 | if (sig_kernel_coredump(signr)) { | 1850 | if (sig_kernel_coredump(signr)) { |
1835 | if (print_fatal_signals) | 1851 | if (print_fatal_signals) |
1836 | print_fatal_signal(regs, signr); | 1852 | print_fatal_signal(regs, info->si_signo); |
1837 | /* | 1853 | /* |
1838 | * If it was able to dump core, this kills all | 1854 | * If it was able to dump core, this kills all |
1839 | * other threads in the group and synchronizes with | 1855 | * other threads in the group and synchronizes with |
@@ -1842,13 +1858,13 @@ relock: | |||
1842 | * first and our do_group_exit call below will use | 1858 | * first and our do_group_exit call below will use |
1843 | * that value and ignore the one we pass it. | 1859 | * that value and ignore the one we pass it. |
1844 | */ | 1860 | */ |
1845 | do_coredump((long)signr, signr, regs); | 1861 | do_coredump(info->si_signo, info->si_signo, regs); |
1846 | } | 1862 | } |
1847 | 1863 | ||
1848 | /* | 1864 | /* |
1849 | * Death signals, no core dump. | 1865 | * Death signals, no core dump. |
1850 | */ | 1866 | */ |
1851 | do_group_exit(signr); | 1867 | do_group_exit(info->si_signo); |
1852 | /* NOTREACHED */ | 1868 | /* NOTREACHED */ |
1853 | } | 1869 | } |
1854 | spin_unlock_irq(&sighand->siglock); | 1870 | spin_unlock_irq(&sighand->siglock); |