diff options
| -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 | ||
