diff options
author | Ingo Molnar <mingo@elte.hu> | 2008-08-18 21:34:07 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2008-08-18 21:34:07 -0400 |
commit | 2879a927bb7a3cf91ae3906a5e59215f9c17dd75 (patch) | |
tree | 870bdd1bd530a3d5d2abd10539700446b2878188 /kernel/signal.c | |
parent | 7e7b43892b87b6be259479ef4de14029dcb4012f (diff) | |
parent | 20211e4d344729f4d4c93da37a590fc1c3a1fd9b (diff) |
Merge branch 'x86/oprofile' into oprofile
Diffstat (limited to 'kernel/signal.c')
-rw-r--r-- | kernel/signal.c | 100 |
1 files changed, 64 insertions, 36 deletions
diff --git a/kernel/signal.c b/kernel/signal.c index 82c3545596c5..c539f60c6f41 100644 --- a/kernel/signal.c +++ b/kernel/signal.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <linux/ptrace.h> | 22 | #include <linux/ptrace.h> |
23 | #include <linux/signal.h> | 23 | #include <linux/signal.h> |
24 | #include <linux/signalfd.h> | 24 | #include <linux/signalfd.h> |
25 | #include <linux/tracehook.h> | ||
25 | #include <linux/capability.h> | 26 | #include <linux/capability.h> |
26 | #include <linux/freezer.h> | 27 | #include <linux/freezer.h> |
27 | #include <linux/pid_namespace.h> | 28 | #include <linux/pid_namespace.h> |
@@ -39,24 +40,21 @@ | |||
39 | 40 | ||
40 | static struct kmem_cache *sigqueue_cachep; | 41 | static struct kmem_cache *sigqueue_cachep; |
41 | 42 | ||
42 | static int __sig_ignored(struct task_struct *t, int sig) | 43 | static void __user *sig_handler(struct task_struct *t, int sig) |
43 | { | 44 | { |
44 | void __user *handler; | 45 | return t->sighand->action[sig - 1].sa.sa_handler; |
46 | } | ||
45 | 47 | ||
48 | static int sig_handler_ignored(void __user *handler, int sig) | ||
49 | { | ||
46 | /* Is it explicitly or implicitly ignored? */ | 50 | /* Is it explicitly or implicitly ignored? */ |
47 | |||
48 | handler = t->sighand->action[sig - 1].sa.sa_handler; | ||
49 | return handler == SIG_IGN || | 51 | return handler == SIG_IGN || |
50 | (handler == SIG_DFL && sig_kernel_ignore(sig)); | 52 | (handler == SIG_DFL && sig_kernel_ignore(sig)); |
51 | } | 53 | } |
52 | 54 | ||
53 | static int sig_ignored(struct task_struct *t, int sig) | 55 | static int sig_ignored(struct task_struct *t, int sig) |
54 | { | 56 | { |
55 | /* | 57 | void __user *handler; |
56 | * Tracers always want to know about signals.. | ||
57 | */ | ||
58 | if (t->ptrace & PT_PTRACED) | ||
59 | return 0; | ||
60 | 58 | ||
61 | /* | 59 | /* |
62 | * Blocked signals are never ignored, since the | 60 | * Blocked signals are never ignored, since the |
@@ -66,7 +64,14 @@ static int sig_ignored(struct task_struct *t, int sig) | |||
66 | if (sigismember(&t->blocked, sig) || sigismember(&t->real_blocked, sig)) | 64 | if (sigismember(&t->blocked, sig) || sigismember(&t->real_blocked, sig)) |
67 | return 0; | 65 | return 0; |
68 | 66 | ||
69 | return __sig_ignored(t, sig); | 67 | handler = sig_handler(t, sig); |
68 | if (!sig_handler_ignored(handler, sig)) | ||
69 | return 0; | ||
70 | |||
71 | /* | ||
72 | * Tracers may want to know about even ignored signals. | ||
73 | */ | ||
74 | return !tracehook_consider_ignored_signal(t, sig, handler); | ||
70 | } | 75 | } |
71 | 76 | ||
72 | /* | 77 | /* |
@@ -129,7 +134,9 @@ void recalc_sigpending_and_wake(struct task_struct *t) | |||
129 | 134 | ||
130 | void recalc_sigpending(void) | 135 | void recalc_sigpending(void) |
131 | { | 136 | { |
132 | if (!recalc_sigpending_tsk(current) && !freezing(current)) | 137 | if (unlikely(tracehook_force_sigpending())) |
138 | set_thread_flag(TIF_SIGPENDING); | ||
139 | else if (!recalc_sigpending_tsk(current) && !freezing(current)) | ||
133 | clear_thread_flag(TIF_SIGPENDING); | 140 | clear_thread_flag(TIF_SIGPENDING); |
134 | 141 | ||
135 | } | 142 | } |
@@ -295,12 +302,12 @@ flush_signal_handlers(struct task_struct *t, int force_default) | |||
295 | 302 | ||
296 | int unhandled_signal(struct task_struct *tsk, int sig) | 303 | int unhandled_signal(struct task_struct *tsk, int sig) |
297 | { | 304 | { |
305 | void __user *handler = tsk->sighand->action[sig-1].sa.sa_handler; | ||
298 | if (is_global_init(tsk)) | 306 | if (is_global_init(tsk)) |
299 | return 1; | 307 | return 1; |
300 | if (tsk->ptrace & PT_PTRACED) | 308 | if (handler != SIG_IGN && handler != SIG_DFL) |
301 | return 0; | 309 | return 0; |
302 | return (tsk->sighand->action[sig-1].sa.sa_handler == SIG_IGN) || | 310 | return !tracehook_consider_fatal_signal(tsk, sig, handler); |
303 | (tsk->sighand->action[sig-1].sa.sa_handler == SIG_DFL); | ||
304 | } | 311 | } |
305 | 312 | ||
306 | 313 | ||
@@ -591,9 +598,6 @@ static int check_kill_permission(int sig, struct siginfo *info, | |||
591 | return security_task_kill(t, info, sig, 0); | 598 | return security_task_kill(t, info, sig, 0); |
592 | } | 599 | } |
593 | 600 | ||
594 | /* forward decl */ | ||
595 | static void do_notify_parent_cldstop(struct task_struct *tsk, int why); | ||
596 | |||
597 | /* | 601 | /* |
598 | * Handle magic process-wide effects of stop/continue signals. Unlike | 602 | * Handle magic process-wide effects of stop/continue signals. Unlike |
599 | * the signal actions, these happen immediately at signal-generation | 603 | * the signal actions, these happen immediately at signal-generation |
@@ -756,7 +760,8 @@ static void complete_signal(int sig, struct task_struct *p, int group) | |||
756 | if (sig_fatal(p, sig) && | 760 | if (sig_fatal(p, sig) && |
757 | !(signal->flags & (SIGNAL_UNKILLABLE | SIGNAL_GROUP_EXIT)) && | 761 | !(signal->flags & (SIGNAL_UNKILLABLE | SIGNAL_GROUP_EXIT)) && |
758 | !sigismember(&t->real_blocked, sig) && | 762 | !sigismember(&t->real_blocked, sig) && |
759 | (sig == SIGKILL || !(t->ptrace & PT_PTRACED))) { | 763 | (sig == SIGKILL || |
764 | !tracehook_consider_fatal_signal(t, sig, SIG_DFL))) { | ||
760 | /* | 765 | /* |
761 | * This signal will be fatal to the whole group. | 766 | * This signal will be fatal to the whole group. |
762 | */ | 767 | */ |
@@ -1299,6 +1304,7 @@ int send_sigqueue(struct sigqueue *q, struct task_struct *t, int group) | |||
1299 | q->info.si_overrun++; | 1304 | q->info.si_overrun++; |
1300 | goto out; | 1305 | goto out; |
1301 | } | 1306 | } |
1307 | q->info.si_overrun = 0; | ||
1302 | 1308 | ||
1303 | signalfd_notify(t, sig); | 1309 | signalfd_notify(t, sig); |
1304 | pending = group ? &t->signal->shared_pending : &t->pending; | 1310 | pending = group ? &t->signal->shared_pending : &t->pending; |
@@ -1323,9 +1329,11 @@ static inline void __wake_up_parent(struct task_struct *p, | |||
1323 | /* | 1329 | /* |
1324 | * Let a parent know about the death of a child. | 1330 | * Let a parent know about the death of a child. |
1325 | * For a stopped/continued status change, use do_notify_parent_cldstop instead. | 1331 | * For a stopped/continued status change, use do_notify_parent_cldstop instead. |
1332 | * | ||
1333 | * Returns -1 if our parent ignored us and so we've switched to | ||
1334 | * self-reaping, or else @sig. | ||
1326 | */ | 1335 | */ |
1327 | 1336 | int do_notify_parent(struct task_struct *tsk, int sig) | |
1328 | void do_notify_parent(struct task_struct *tsk, int sig) | ||
1329 | { | 1337 | { |
1330 | struct siginfo info; | 1338 | struct siginfo info; |
1331 | unsigned long flags; | 1339 | unsigned long flags; |
@@ -1396,12 +1404,14 @@ void do_notify_parent(struct task_struct *tsk, int sig) | |||
1396 | */ | 1404 | */ |
1397 | tsk->exit_signal = -1; | 1405 | tsk->exit_signal = -1; |
1398 | if (psig->action[SIGCHLD-1].sa.sa_handler == SIG_IGN) | 1406 | if (psig->action[SIGCHLD-1].sa.sa_handler == SIG_IGN) |
1399 | sig = 0; | 1407 | sig = -1; |
1400 | } | 1408 | } |
1401 | if (valid_signal(sig) && sig > 0) | 1409 | if (valid_signal(sig) && sig > 0) |
1402 | __group_send_sig_info(sig, &info, tsk->parent); | 1410 | __group_send_sig_info(sig, &info, tsk->parent); |
1403 | __wake_up_parent(tsk, tsk->parent); | 1411 | __wake_up_parent(tsk, tsk->parent); |
1404 | spin_unlock_irqrestore(&psig->siglock, flags); | 1412 | spin_unlock_irqrestore(&psig->siglock, flags); |
1413 | |||
1414 | return sig; | ||
1405 | } | 1415 | } |
1406 | 1416 | ||
1407 | static void do_notify_parent_cldstop(struct task_struct *tsk, int why) | 1417 | static void do_notify_parent_cldstop(struct task_struct *tsk, int why) |
@@ -1599,7 +1609,7 @@ finish_stop(int stop_count) | |||
1599 | * a group stop in progress and we are the last to stop, | 1609 | * a group stop in progress and we are the last to stop, |
1600 | * report to the parent. When ptraced, every thread reports itself. | 1610 | * report to the parent. When ptraced, every thread reports itself. |
1601 | */ | 1611 | */ |
1602 | if (stop_count == 0 || (current->ptrace & PT_PTRACED)) { | 1612 | if (tracehook_notify_jctl(stop_count == 0, CLD_STOPPED)) { |
1603 | read_lock(&tasklist_lock); | 1613 | read_lock(&tasklist_lock); |
1604 | do_notify_parent_cldstop(current, CLD_STOPPED); | 1614 | do_notify_parent_cldstop(current, CLD_STOPPED); |
1605 | read_unlock(&tasklist_lock); | 1615 | read_unlock(&tasklist_lock); |
@@ -1735,6 +1745,9 @@ relock: | |||
1735 | signal->flags &= ~SIGNAL_CLD_MASK; | 1745 | signal->flags &= ~SIGNAL_CLD_MASK; |
1736 | spin_unlock_irq(&sighand->siglock); | 1746 | spin_unlock_irq(&sighand->siglock); |
1737 | 1747 | ||
1748 | if (unlikely(!tracehook_notify_jctl(1, why))) | ||
1749 | goto relock; | ||
1750 | |||
1738 | read_lock(&tasklist_lock); | 1751 | read_lock(&tasklist_lock); |
1739 | do_notify_parent_cldstop(current->group_leader, why); | 1752 | do_notify_parent_cldstop(current->group_leader, why); |
1740 | read_unlock(&tasklist_lock); | 1753 | read_unlock(&tasklist_lock); |
@@ -1748,17 +1761,33 @@ relock: | |||
1748 | do_signal_stop(0)) | 1761 | do_signal_stop(0)) |
1749 | goto relock; | 1762 | goto relock; |
1750 | 1763 | ||
1751 | signr = dequeue_signal(current, ¤t->blocked, info); | 1764 | /* |
1752 | if (!signr) | 1765 | * Tracing can induce an artifical signal and choose sigaction. |
1753 | break; /* will return 0 */ | 1766 | * The return value in @signr determines the default action, |
1767 | * but @info->si_signo is the signal number we will report. | ||
1768 | */ | ||
1769 | signr = tracehook_get_signal(current, regs, info, return_ka); | ||
1770 | if (unlikely(signr < 0)) | ||
1771 | goto relock; | ||
1772 | if (unlikely(signr != 0)) | ||
1773 | ka = return_ka; | ||
1774 | else { | ||
1775 | signr = dequeue_signal(current, ¤t->blocked, | ||
1776 | info); | ||
1754 | 1777 | ||
1755 | if (signr != SIGKILL) { | ||
1756 | signr = ptrace_signal(signr, info, regs, cookie); | ||
1757 | if (!signr) | 1778 | if (!signr) |
1758 | continue; | 1779 | break; /* will return 0 */ |
1780 | |||
1781 | if (signr != SIGKILL) { | ||
1782 | signr = ptrace_signal(signr, info, | ||
1783 | regs, cookie); | ||
1784 | if (!signr) | ||
1785 | continue; | ||
1786 | } | ||
1787 | |||
1788 | ka = &sighand->action[signr-1]; | ||
1759 | } | 1789 | } |
1760 | 1790 | ||
1761 | ka = &sighand->action[signr-1]; | ||
1762 | if (ka->sa.sa_handler == SIG_IGN) /* Do nothing. */ | 1791 | if (ka->sa.sa_handler == SIG_IGN) /* Do nothing. */ |
1763 | continue; | 1792 | continue; |
1764 | if (ka->sa.sa_handler != SIG_DFL) { | 1793 | if (ka->sa.sa_handler != SIG_DFL) { |
@@ -1806,7 +1835,7 @@ relock: | |||
1806 | spin_lock_irq(&sighand->siglock); | 1835 | spin_lock_irq(&sighand->siglock); |
1807 | } | 1836 | } |
1808 | 1837 | ||
1809 | if (likely(do_signal_stop(signr))) { | 1838 | if (likely(do_signal_stop(info->si_signo))) { |
1810 | /* It released the siglock. */ | 1839 | /* It released the siglock. */ |
1811 | goto relock; | 1840 | goto relock; |
1812 | } | 1841 | } |
@@ -1827,7 +1856,7 @@ relock: | |||
1827 | 1856 | ||
1828 | if (sig_kernel_coredump(signr)) { | 1857 | if (sig_kernel_coredump(signr)) { |
1829 | if (print_fatal_signals) | 1858 | if (print_fatal_signals) |
1830 | print_fatal_signal(regs, signr); | 1859 | print_fatal_signal(regs, info->si_signo); |
1831 | /* | 1860 | /* |
1832 | * If it was able to dump core, this kills all | 1861 | * If it was able to dump core, this kills all |
1833 | * other threads in the group and synchronizes with | 1862 | * other threads in the group and synchronizes with |
@@ -1836,13 +1865,13 @@ relock: | |||
1836 | * first and our do_group_exit call below will use | 1865 | * first and our do_group_exit call below will use |
1837 | * that value and ignore the one we pass it. | 1866 | * that value and ignore the one we pass it. |
1838 | */ | 1867 | */ |
1839 | do_coredump((long)signr, signr, regs); | 1868 | do_coredump(info->si_signo, info->si_signo, regs); |
1840 | } | 1869 | } |
1841 | 1870 | ||
1842 | /* | 1871 | /* |
1843 | * Death signals, no core dump. | 1872 | * Death signals, no core dump. |
1844 | */ | 1873 | */ |
1845 | do_group_exit(signr); | 1874 | do_group_exit(info->si_signo); |
1846 | /* NOTREACHED */ | 1875 | /* NOTREACHED */ |
1847 | } | 1876 | } |
1848 | spin_unlock_irq(&sighand->siglock); | 1877 | spin_unlock_irq(&sighand->siglock); |
@@ -1884,7 +1913,7 @@ void exit_signals(struct task_struct *tsk) | |||
1884 | out: | 1913 | out: |
1885 | spin_unlock_irq(&tsk->sighand->siglock); | 1914 | spin_unlock_irq(&tsk->sighand->siglock); |
1886 | 1915 | ||
1887 | if (unlikely(group_stop)) { | 1916 | if (unlikely(group_stop) && tracehook_notify_jctl(1, CLD_STOPPED)) { |
1888 | read_lock(&tasklist_lock); | 1917 | read_lock(&tasklist_lock); |
1889 | do_notify_parent_cldstop(tsk, CLD_STOPPED); | 1918 | do_notify_parent_cldstop(tsk, CLD_STOPPED); |
1890 | read_unlock(&tasklist_lock); | 1919 | read_unlock(&tasklist_lock); |
@@ -1895,7 +1924,6 @@ EXPORT_SYMBOL(recalc_sigpending); | |||
1895 | EXPORT_SYMBOL_GPL(dequeue_signal); | 1924 | EXPORT_SYMBOL_GPL(dequeue_signal); |
1896 | EXPORT_SYMBOL(flush_signals); | 1925 | EXPORT_SYMBOL(flush_signals); |
1897 | EXPORT_SYMBOL(force_sig); | 1926 | EXPORT_SYMBOL(force_sig); |
1898 | EXPORT_SYMBOL(ptrace_notify); | ||
1899 | EXPORT_SYMBOL(send_sig); | 1927 | EXPORT_SYMBOL(send_sig); |
1900 | EXPORT_SYMBOL(send_sig_info); | 1928 | EXPORT_SYMBOL(send_sig_info); |
1901 | EXPORT_SYMBOL(sigprocmask); | 1929 | EXPORT_SYMBOL(sigprocmask); |
@@ -2299,7 +2327,7 @@ int do_sigaction(int sig, struct k_sigaction *act, struct k_sigaction *oact) | |||
2299 | * (for example, SIGCHLD), shall cause the pending signal to | 2327 | * (for example, SIGCHLD), shall cause the pending signal to |
2300 | * be discarded, whether or not it is blocked" | 2328 | * be discarded, whether or not it is blocked" |
2301 | */ | 2329 | */ |
2302 | if (__sig_ignored(t, sig)) { | 2330 | if (sig_handler_ignored(sig_handler(t, sig), sig)) { |
2303 | sigemptyset(&mask); | 2331 | sigemptyset(&mask); |
2304 | sigaddset(&mask, sig); | 2332 | sigaddset(&mask, sig); |
2305 | rm_from_queue_full(&mask, &t->signal->shared_pending); | 2333 | rm_from_queue_full(&mask, &t->signal->shared_pending); |