lkml.org 
[lkml]   [2017]   [Aug]   [9]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 4.4 55/58] signal: protect SIGNAL_UNKILLABLE from unintentional clearing.
    Date
    4.4-stable review patch.  If anyone has any objections, please let me know.

    ------------------

    From: Jamie Iles <jamie.iles@oracle.com>


    [ Upstream commit 2d39b3cd34e6d323720d4c61bd714f5ae202c022 ]

    Since commit 00cd5c37afd5 ("ptrace: permit ptracing of /sbin/init") we
    can now trace init processes. init is initially protected with
    SIGNAL_UNKILLABLE which will prevent fatal signals such as SIGSTOP, but
    there are a number of paths during tracing where SIGNAL_UNKILLABLE can
    be implicitly cleared.

    This can result in init becoming stoppable/killable after tracing. For
    example, running:

    while true; do kill -STOP 1; done &
    strace -p 1

    and then stopping strace and the kill loop will result in init being
    left in state TASK_STOPPED. Sending SIGCONT to init will resume it, but
    init will now respond to future SIGSTOP signals rather than ignoring
    them.

    Make sure that when setting SIGNAL_STOP_CONTINUED/SIGNAL_STOP_STOPPED
    that we don't clear SIGNAL_UNKILLABLE.

    Link: http://lkml.kernel.org/r/20170104122017.25047-1-jamie.iles@oracle.com
    Signed-off-by: Jamie Iles <jamie.iles@oracle.com>
    Acked-by: Oleg Nesterov <oleg@redhat.com>
    Cc: Alexander Viro <viro@zeniv.linux.org.uk>
    Cc: Ingo Molnar <mingo@redhat.com>
    Cc: Peter Zijlstra <peterz@infradead.org>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
    Signed-off-by: Sasha Levin <alexander.levin@verizon.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
    ---
    include/linux/sched.h | 10 ++++++++++
    kernel/signal.c | 4 ++--
    2 files changed, 12 insertions(+), 2 deletions(-)

    --- a/include/linux/sched.h
    +++ b/include/linux/sched.h
    @@ -801,6 +801,16 @@ struct signal_struct {

    #define SIGNAL_UNKILLABLE 0x00000040 /* for init: ignore fatal signals */

    +#define SIGNAL_STOP_MASK (SIGNAL_CLD_MASK | SIGNAL_STOP_STOPPED | \
    + SIGNAL_STOP_CONTINUED)
    +
    +static inline void signal_set_stop_flags(struct signal_struct *sig,
    + unsigned int flags)
    +{
    + WARN_ON(sig->flags & (SIGNAL_GROUP_EXIT|SIGNAL_GROUP_COREDUMP));
    + sig->flags = (sig->flags & ~SIGNAL_STOP_MASK) | flags;
    +}
    +
    /* If true, all threads except ->group_exit_task have pending SIGKILL */
    static inline int signal_group_exit(const struct signal_struct *sig)
    {
    --- a/kernel/signal.c
    +++ b/kernel/signal.c
    @@ -346,7 +346,7 @@ static bool task_participate_group_stop(
    * fresh group stop. Read comment in do_signal_stop() for details.
    */
    if (!sig->group_stop_count && !(sig->flags & SIGNAL_STOP_STOPPED)) {
    - sig->flags = SIGNAL_STOP_STOPPED;
    + signal_set_stop_flags(sig, SIGNAL_STOP_STOPPED);
    return true;
    }
    return false;
    @@ -845,7 +845,7 @@ static bool prepare_signal(int sig, stru
    * will take ->siglock, notice SIGNAL_CLD_MASK, and
    * notify its parent. See get_signal_to_deliver().
    */
    - signal->flags = why | SIGNAL_STOP_CONTINUED;
    + signal_set_stop_flags(signal, why | SIGNAL_STOP_CONTINUED);
    signal->group_stop_count = 0;
    signal->group_exit_code = 0;
    }

    \
     
     \ /
      Last update: 2017-08-09 21:46    [W:4.298 / U:0.096 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site