diff options
Diffstat (limited to 'kernel/signal.c')
-rw-r--r-- | kernel/signal.c | 53 |
1 files changed, 50 insertions, 3 deletions
diff --git a/kernel/signal.c b/kernel/signal.c index 9f10b246fd46..f65403da4101 100644 --- a/kernel/signal.c +++ b/kernel/signal.c | |||
@@ -1694,6 +1694,15 @@ static int sigkill_pending(struct task_struct *tsk) | |||
1694 | } | 1694 | } |
1695 | 1695 | ||
1696 | /* | 1696 | /* |
1697 | * Test whether the target task of the usual cldstop notification - the | ||
1698 | * real_parent of @child - is in the same group as the ptracer. | ||
1699 | */ | ||
1700 | static bool real_parent_is_ptracer(struct task_struct *child) | ||
1701 | { | ||
1702 | return same_thread_group(child->parent, child->real_parent); | ||
1703 | } | ||
1704 | |||
1705 | /* | ||
1697 | * This must be called with current->sighand->siglock held. | 1706 | * This must be called with current->sighand->siglock held. |
1698 | * | 1707 | * |
1699 | * This should be the path for all ptrace stops. | 1708 | * This should be the path for all ptrace stops. |
@@ -1708,6 +1717,8 @@ static void ptrace_stop(int exit_code, int why, int clear_code, siginfo_t *info) | |||
1708 | __releases(¤t->sighand->siglock) | 1717 | __releases(¤t->sighand->siglock) |
1709 | __acquires(¤t->sighand->siglock) | 1718 | __acquires(¤t->sighand->siglock) |
1710 | { | 1719 | { |
1720 | bool gstop_done = false; | ||
1721 | |||
1711 | if (arch_ptrace_stop_needed(exit_code, info)) { | 1722 | if (arch_ptrace_stop_needed(exit_code, info)) { |
1712 | /* | 1723 | /* |
1713 | * The arch code has something special to do before a | 1724 | * The arch code has something special to do before a |
@@ -1735,7 +1746,7 @@ static void ptrace_stop(int exit_code, int why, int clear_code, siginfo_t *info) | |||
1735 | * is entered - ignore it. | 1746 | * is entered - ignore it. |
1736 | */ | 1747 | */ |
1737 | if (why == CLD_STOPPED && (current->group_stop & GROUP_STOP_PENDING)) | 1748 | if (why == CLD_STOPPED && (current->group_stop & GROUP_STOP_PENDING)) |
1738 | task_participate_group_stop(current); | 1749 | gstop_done = task_participate_group_stop(current); |
1739 | 1750 | ||
1740 | current->last_siginfo = info; | 1751 | current->last_siginfo = info; |
1741 | current->exit_code = exit_code; | 1752 | current->exit_code = exit_code; |
@@ -1757,7 +1768,20 @@ static void ptrace_stop(int exit_code, int why, int clear_code, siginfo_t *info) | |||
1757 | spin_unlock_irq(¤t->sighand->siglock); | 1768 | spin_unlock_irq(¤t->sighand->siglock); |
1758 | read_lock(&tasklist_lock); | 1769 | read_lock(&tasklist_lock); |
1759 | if (may_ptrace_stop()) { | 1770 | if (may_ptrace_stop()) { |
1760 | do_notify_parent_cldstop(current, task_ptrace(current), why); | 1771 | /* |
1772 | * Notify parents of the stop. | ||
1773 | * | ||
1774 | * While ptraced, there are two parents - the ptracer and | ||
1775 | * the real_parent of the group_leader. The ptracer should | ||
1776 | * know about every stop while the real parent is only | ||
1777 | * interested in the completion of group stop. The states | ||
1778 | * for the two don't interact with each other. Notify | ||
1779 | * separately unless they're gonna be duplicates. | ||
1780 | */ | ||
1781 | do_notify_parent_cldstop(current, true, why); | ||
1782 | if (gstop_done && !real_parent_is_ptracer(current)) | ||
1783 | do_notify_parent_cldstop(current, false, why); | ||
1784 | |||
1761 | /* | 1785 | /* |
1762 | * Don't want to allow preemption here, because | 1786 | * Don't want to allow preemption here, because |
1763 | * sys_ptrace() needs this task to be inactive. | 1787 | * sys_ptrace() needs this task to be inactive. |
@@ -1772,7 +1796,16 @@ static void ptrace_stop(int exit_code, int why, int clear_code, siginfo_t *info) | |||
1772 | /* | 1796 | /* |
1773 | * By the time we got the lock, our tracer went away. | 1797 | * By the time we got the lock, our tracer went away. |
1774 | * Don't drop the lock yet, another tracer may come. | 1798 | * Don't drop the lock yet, another tracer may come. |
1799 | * | ||
1800 | * If @gstop_done, the ptracer went away between group stop | ||
1801 | * completion and here. During detach, it would have set | ||
1802 | * GROUP_STOP_PENDING on us and we'll re-enter TASK_STOPPED | ||
1803 | * in do_signal_stop() on return, so notifying the real | ||
1804 | * parent of the group stop completion is enough. | ||
1775 | */ | 1805 | */ |
1806 | if (gstop_done) | ||
1807 | do_notify_parent_cldstop(current, false, why); | ||
1808 | |||
1776 | __set_current_state(TASK_RUNNING); | 1809 | __set_current_state(TASK_RUNNING); |
1777 | if (clear_code) | 1810 | if (clear_code) |
1778 | current->exit_code = 0; | 1811 | current->exit_code = 0; |
@@ -2017,10 +2050,24 @@ relock: | |||
2017 | 2050 | ||
2018 | spin_unlock_irq(&sighand->siglock); | 2051 | spin_unlock_irq(&sighand->siglock); |
2019 | 2052 | ||
2053 | /* | ||
2054 | * Notify the parent that we're continuing. This event is | ||
2055 | * always per-process and doesn't make whole lot of sense | ||
2056 | * for ptracers, who shouldn't consume the state via | ||
2057 | * wait(2) either, but, for backward compatibility, notify | ||
2058 | * the ptracer of the group leader too unless it's gonna be | ||
2059 | * a duplicate. | ||
2060 | */ | ||
2020 | read_lock(&tasklist_lock); | 2061 | read_lock(&tasklist_lock); |
2062 | |||
2063 | do_notify_parent_cldstop(current, false, why); | ||
2064 | |||
2021 | leader = current->group_leader; | 2065 | leader = current->group_leader; |
2022 | do_notify_parent_cldstop(leader, task_ptrace(leader), why); | 2066 | if (task_ptrace(leader) && !real_parent_is_ptracer(leader)) |
2067 | do_notify_parent_cldstop(leader, true, why); | ||
2068 | |||
2023 | read_unlock(&tasklist_lock); | 2069 | read_unlock(&tasklist_lock); |
2070 | |||
2024 | goto relock; | 2071 | goto relock; |
2025 | } | 2072 | } |
2026 | 2073 | ||