diff options
Diffstat (limited to 'kernel/signal.c')
-rw-r--r-- | kernel/signal.c | 71 |
1 files changed, 42 insertions, 29 deletions
diff --git a/kernel/signal.c b/kernel/signal.c index 6af1210092c3..cc8303cd093d 100644 --- a/kernel/signal.c +++ b/kernel/signal.c | |||
@@ -1757,6 +1757,45 @@ static int do_signal_stop(int signr) | |||
1757 | return 1; | 1757 | return 1; |
1758 | } | 1758 | } |
1759 | 1759 | ||
1760 | static int ptrace_signal(int signr, siginfo_t *info, | ||
1761 | struct pt_regs *regs, void *cookie) | ||
1762 | { | ||
1763 | if (!(current->ptrace & PT_PTRACED)) | ||
1764 | return signr; | ||
1765 | |||
1766 | ptrace_signal_deliver(regs, cookie); | ||
1767 | |||
1768 | /* Let the debugger run. */ | ||
1769 | ptrace_stop(signr, 0, info); | ||
1770 | |||
1771 | /* We're back. Did the debugger cancel the sig? */ | ||
1772 | signr = current->exit_code; | ||
1773 | if (signr == 0) | ||
1774 | return signr; | ||
1775 | |||
1776 | current->exit_code = 0; | ||
1777 | |||
1778 | /* Update the siginfo structure if the signal has | ||
1779 | changed. If the debugger wanted something | ||
1780 | specific in the siginfo structure then it should | ||
1781 | have updated *info via PTRACE_SETSIGINFO. */ | ||
1782 | if (signr != info->si_signo) { | ||
1783 | info->si_signo = signr; | ||
1784 | info->si_errno = 0; | ||
1785 | info->si_code = SI_USER; | ||
1786 | info->si_pid = task_pid_vnr(current->parent); | ||
1787 | info->si_uid = current->parent->uid; | ||
1788 | } | ||
1789 | |||
1790 | /* If the (new) signal is now blocked, requeue it. */ | ||
1791 | if (sigismember(¤t->blocked, signr)) { | ||
1792 | specific_send_sig_info(signr, info, current); | ||
1793 | signr = 0; | ||
1794 | } | ||
1795 | |||
1796 | return signr; | ||
1797 | } | ||
1798 | |||
1760 | int get_signal_to_deliver(siginfo_t *info, struct k_sigaction *return_ka, | 1799 | int get_signal_to_deliver(siginfo_t *info, struct k_sigaction *return_ka, |
1761 | struct pt_regs *regs, void *cookie) | 1800 | struct pt_regs *regs, void *cookie) |
1762 | { | 1801 | { |
@@ -1785,36 +1824,10 @@ relock: | |||
1785 | if (!signr) | 1824 | if (!signr) |
1786 | break; /* will return 0 */ | 1825 | break; /* will return 0 */ |
1787 | 1826 | ||
1788 | if ((current->ptrace & PT_PTRACED) && signr != SIGKILL) { | 1827 | if (signr != SIGKILL) { |
1789 | ptrace_signal_deliver(regs, cookie); | 1828 | signr = ptrace_signal(signr, info, regs, cookie); |
1790 | 1829 | if (!signr) | |
1791 | /* Let the debugger run. */ | ||
1792 | ptrace_stop(signr, 0, info); | ||
1793 | |||
1794 | /* We're back. Did the debugger cancel the sig? */ | ||
1795 | signr = current->exit_code; | ||
1796 | if (signr == 0) | ||
1797 | continue; | ||
1798 | |||
1799 | current->exit_code = 0; | ||
1800 | |||
1801 | /* Update the siginfo structure if the signal has | ||
1802 | changed. If the debugger wanted something | ||
1803 | specific in the siginfo structure then it should | ||
1804 | have updated *info via PTRACE_SETSIGINFO. */ | ||
1805 | if (signr != info->si_signo) { | ||
1806 | info->si_signo = signr; | ||
1807 | info->si_errno = 0; | ||
1808 | info->si_code = SI_USER; | ||
1809 | info->si_pid = task_pid_vnr(current->parent); | ||
1810 | info->si_uid = current->parent->uid; | ||
1811 | } | ||
1812 | |||
1813 | /* If the (new) signal is now blocked, requeue it. */ | ||
1814 | if (sigismember(¤t->blocked, signr)) { | ||
1815 | specific_send_sig_info(signr, info, current); | ||
1816 | continue; | 1830 | continue; |
1817 | } | ||
1818 | } | 1831 | } |
1819 | 1832 | ||
1820 | ka = ¤t->sighand->action[signr-1]; | 1833 | ka = ¤t->sighand->action[signr-1]; |