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]; |
