lkml.org 
[lkml]   [2019]   [Apr]   [22]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH AUTOSEL 4.14 42/43] ptrace: take into account saved_sigmask in PTRACE{GET,SET}SIGMASK
    Date
    From: Andrei Vagin <avagin@gmail.com>

    [ Upstream commit fcfc2aa0185f4a731d05a21e9f359968fdfd02e7 ]

    There are a few system calls (pselect, ppoll, etc) which replace a task
    sigmask while they are running in a kernel-space

    When a task calls one of these syscalls, the kernel saves a current
    sigmask in task->saved_sigmask and sets a syscall sigmask.

    On syscall-exit-stop, ptrace traps a task before restoring the
    saved_sigmask, so PTRACE_GETSIGMASK returns the syscall sigmask and
    PTRACE_SETSIGMASK does nothing, because its sigmask is replaced by
    saved_sigmask, when the task returns to user-space.

    This patch fixes this problem. PTRACE_GETSIGMASK returns saved_sigmask
    if it's set. PTRACE_SETSIGMASK drops the TIF_RESTORE_SIGMASK flag.

    Link: http://lkml.kernel.org/r/20181120060616.6043-1-avagin@gmail.com
    Fixes: 29000caecbe8 ("ptrace: add ability to get/set signal-blocked mask")
    Signed-off-by: Andrei Vagin <avagin@gmail.com>
    Acked-by: Oleg Nesterov <oleg@redhat.com>
    Cc: "Eric W. Biederman" <ebiederm@xmission.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
    Signed-off-by: Sasha Levin (Microsoft) <sashal@kernel.org>
    ---
    include/linux/sched/signal.h | 18 ++++++++++++++++++
    kernel/ptrace.c | 15 +++++++++++++--
    2 files changed, 31 insertions(+), 2 deletions(-)

    diff --git a/include/linux/sched/signal.h b/include/linux/sched/signal.h
    index fbf86ecd149d..bcaba7e8ca6e 100644
    --- a/include/linux/sched/signal.h
    +++ b/include/linux/sched/signal.h
    @@ -377,10 +377,20 @@ static inline void set_restore_sigmask(void)
    set_thread_flag(TIF_RESTORE_SIGMASK);
    WARN_ON(!test_thread_flag(TIF_SIGPENDING));
    }
    +
    +static inline void clear_tsk_restore_sigmask(struct task_struct *tsk)
    +{
    + clear_tsk_thread_flag(tsk, TIF_RESTORE_SIGMASK);
    +}
    +
    static inline void clear_restore_sigmask(void)
    {
    clear_thread_flag(TIF_RESTORE_SIGMASK);
    }
    +static inline bool test_tsk_restore_sigmask(struct task_struct *tsk)
    +{
    + return test_tsk_thread_flag(tsk, TIF_RESTORE_SIGMASK);
    +}
    static inline bool test_restore_sigmask(void)
    {
    return test_thread_flag(TIF_RESTORE_SIGMASK);
    @@ -398,6 +408,10 @@ static inline void set_restore_sigmask(void)
    current->restore_sigmask = true;
    WARN_ON(!test_thread_flag(TIF_SIGPENDING));
    }
    +static inline void clear_tsk_restore_sigmask(struct task_struct *tsk)
    +{
    + tsk->restore_sigmask = false;
    +}
    static inline void clear_restore_sigmask(void)
    {
    current->restore_sigmask = false;
    @@ -406,6 +420,10 @@ static inline bool test_restore_sigmask(void)
    {
    return current->restore_sigmask;
    }
    +static inline bool test_tsk_restore_sigmask(struct task_struct *tsk)
    +{
    + return tsk->restore_sigmask;
    +}
    static inline bool test_and_clear_restore_sigmask(void)
    {
    if (!current->restore_sigmask)
    diff --git a/kernel/ptrace.c b/kernel/ptrace.c
    index 84b1367935e4..f1c85b6c39ae 100644
    --- a/kernel/ptrace.c
    +++ b/kernel/ptrace.c
    @@ -29,6 +29,7 @@
    #include <linux/hw_breakpoint.h>
    #include <linux/cn_proc.h>
    #include <linux/compat.h>
    +#include <linux/sched/signal.h>

    /*
    * Access another process' address space via ptrace.
    @@ -925,18 +926,26 @@ int ptrace_request(struct task_struct *child, long request,
    ret = ptrace_setsiginfo(child, &siginfo);
    break;

    - case PTRACE_GETSIGMASK:
    + case PTRACE_GETSIGMASK: {
    + sigset_t *mask;
    +
    if (addr != sizeof(sigset_t)) {
    ret = -EINVAL;
    break;
    }

    - if (copy_to_user(datavp, &child->blocked, sizeof(sigset_t)))
    + if (test_tsk_restore_sigmask(child))
    + mask = &child->saved_sigmask;
    + else
    + mask = &child->blocked;
    +
    + if (copy_to_user(datavp, mask, sizeof(sigset_t)))
    ret = -EFAULT;
    else
    ret = 0;

    break;
    + }

    case PTRACE_SETSIGMASK: {
    sigset_t new_set;
    @@ -962,6 +971,8 @@ int ptrace_request(struct task_struct *child, long request,
    child->blocked = new_set;
    spin_unlock_irq(&child->sighand->siglock);

    + clear_tsk_restore_sigmask(child);
    +
    ret = 0;
    break;
    }
    --
    2.19.1
    \
     
     \ /
      Last update: 2019-04-22 21:57    [W:4.983 / U:1.132 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site