lkml.org 
[lkml]   [2022]   [Mar]   [15]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Date
    Subject[PATCH 1/2] ptrace: Move setting/clearing ptrace_message into ptrace_stop

    Today ptrace_message is easy to overlook as it not a core part of
    ptrace_stop. It has been overlooked so much that there are places
    that set ptrace_message and don't clear it, and places that never set
    it. So if you get an unlucky sequence of events the ptracer may be
    able to read a ptrace_message that does not apply to the current
    ptrace stop.

    Move setting of ptrace_message into ptrace_stop so that it always gets
    set before the stop, and always gets cleared after the stop. This
    prevents non-sense from being reported to userspace and makes
    ptrace_message more visible in the ptrace helper functions so that
    kernel developers can see it.

    Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
    ---
    include/linux/ptrace.h | 9 +++------
    include/uapi/linux/ptrace.h | 2 +-
    kernel/signal.c | 21 ++++++++++++---------
    3 files changed, 16 insertions(+), 16 deletions(-)

    diff --git a/include/linux/ptrace.h b/include/linux/ptrace.h
    index 5310f43e4762..3e6b46e2b7be 100644
    --- a/include/linux/ptrace.h
    +++ b/include/linux/ptrace.h
    @@ -60,7 +60,7 @@ extern int ptrace_writedata(struct task_struct *tsk, char __user *src, unsigned
    extern void ptrace_disable(struct task_struct *);
    extern int ptrace_request(struct task_struct *child, long request,
    unsigned long addr, unsigned long data);
    -extern void ptrace_notify(int exit_code);
    +extern void ptrace_notify(int exit_code, unsigned long message);
    extern void __ptrace_link(struct task_struct *child,
    struct task_struct *new_parent,
    const struct cred *ptracer_cred);
    @@ -155,8 +155,7 @@ static inline bool ptrace_event_enabled(struct task_struct *task, int event)
    static inline void ptrace_event(int event, unsigned long message)
    {
    if (unlikely(ptrace_event_enabled(current, event))) {
    - current->ptrace_message = message;
    - ptrace_notify((event << 8) | SIGTRAP);
    + ptrace_notify((event << 8) | SIGTRAP, message);
    } else if (event == PTRACE_EVENT_EXEC) {
    /* legacy EXEC report via SIGTRAP */
    if ((current->ptrace & (PT_PTRACED|PT_SEIZED)) == PT_PTRACED)
    @@ -424,8 +423,7 @@ static inline int ptrace_report_syscall(unsigned long message)
    if (!(ptrace & PT_PTRACED))
    return 0;

    - current->ptrace_message = message;
    - ptrace_notify(SIGTRAP | ((ptrace & PT_TRACESYSGOOD) ? 0x80 : 0));
    + ptrace_notify(SIGTRAP | ((ptrace & PT_TRACESYSGOOD) ? 0x80 : 0), message);

    /*
    * this isn't the same as continuing with a signal, but it will do
    @@ -437,7 +435,6 @@ static inline int ptrace_report_syscall(unsigned long message)
    current->exit_code = 0;
    }

    - current->ptrace_message = 0;
    return fatal_signal_pending(current);
    }

    diff --git a/include/uapi/linux/ptrace.h b/include/uapi/linux/ptrace.h
    index b7af92e07d1f..195ae64a8c87 100644
    --- a/include/uapi/linux/ptrace.h
    +++ b/include/uapi/linux/ptrace.h
    @@ -114,7 +114,7 @@ struct ptrace_rseq_configuration {

    /*
    * These values are stored in task->ptrace_message
    - * by ptrace_report_syscall_* to describe the current syscall-stop.
    + * by ptrace_stop to describe the current syscall-stop.
    */
    #define PTRACE_EVENTMSG_SYSCALL_ENTRY 1
    #define PTRACE_EVENTMSG_SYSCALL_EXIT 2
    diff --git a/kernel/signal.c b/kernel/signal.c
    index c2dee5420567..a49ac7149256 100644
    --- a/kernel/signal.c
    +++ b/kernel/signal.c
    @@ -2191,7 +2191,8 @@ static void do_notify_parent_cldstop(struct task_struct *tsk,
    * If we actually decide not to stop at all because the tracer
    * is gone, we keep current->exit_code unless clear_code.
    */
    -static void ptrace_stop(int exit_code, int why, int clear_code, kernel_siginfo_t *info)
    +static void ptrace_stop(int exit_code, int why, int clear_code,
    + unsigned long message, kernel_siginfo_t *info)
    __releases(&current->sighand->siglock)
    __acquires(&current->sighand->siglock)
    {
    @@ -2237,6 +2238,7 @@ static void ptrace_stop(int exit_code, int why, int clear_code, kernel_siginfo_t
    */
    smp_wmb();

    + current->ptrace_message = message;
    current->last_siginfo = info;
    current->exit_code = exit_code;

    @@ -2315,6 +2317,7 @@ static void ptrace_stop(int exit_code, int why, int clear_code, kernel_siginfo_t
    */
    spin_lock_irq(&current->sighand->siglock);
    current->last_siginfo = NULL;
    + current->ptrace_message = 0;

    /* LISTENING can be set only during STOP traps, clear it */
    current->jobctl &= ~JOBCTL_LISTENING;
    @@ -2327,7 +2330,7 @@ static void ptrace_stop(int exit_code, int why, int clear_code, kernel_siginfo_t
    recalc_sigpending_tsk(current);
    }

    -static void ptrace_do_notify(int signr, int exit_code, int why)
    +static void ptrace_do_notify(int signr, int exit_code, int why, unsigned long message)
    {
    kernel_siginfo_t info;

    @@ -2338,17 +2341,17 @@ static void ptrace_do_notify(int signr, int exit_code, int why)
    info.si_uid = from_kuid_munged(current_user_ns(), current_uid());

    /* Let the debugger run. */
    - ptrace_stop(exit_code, why, 1, &info);
    + ptrace_stop(exit_code, why, 1, message, &info);
    }

    -void ptrace_notify(int exit_code)
    +void ptrace_notify(int exit_code, unsigned long message)
    {
    BUG_ON((exit_code & (0x7f | ~0xffff)) != SIGTRAP);
    if (unlikely(task_work_pending(current)))
    task_work_run();

    spin_lock_irq(&current->sighand->siglock);
    - ptrace_do_notify(SIGTRAP, exit_code, CLD_TRAPPED);
    + ptrace_do_notify(SIGTRAP, exit_code, CLD_TRAPPED, message);
    spin_unlock_irq(&current->sighand->siglock);
    }

    @@ -2504,10 +2507,10 @@ static void do_jobctl_trap(void)
    signr = SIGTRAP;
    WARN_ON_ONCE(!signr);
    ptrace_do_notify(signr, signr | (PTRACE_EVENT_STOP << 8),
    - CLD_STOPPED);
    + CLD_STOPPED, 0);
    } else {
    WARN_ON_ONCE(!signr);
    - ptrace_stop(signr, CLD_STOPPED, 0, NULL);
    + ptrace_stop(signr, CLD_STOPPED, 0, 0, NULL);
    current->exit_code = 0;
    }
    }
    @@ -2561,7 +2564,7 @@ static int ptrace_signal(int signr, kernel_siginfo_t *info, enum pid_type type)
    * comment in dequeue_signal().
    */
    current->jobctl |= JOBCTL_STOP_DEQUEUED;
    - ptrace_stop(signr, CLD_TRAPPED, 0, info);
    + ptrace_stop(signr, CLD_TRAPPED, 0, 0, info);

    /* We're back. Did the debugger cancel the sig? */
    signr = current->exit_code;
    @@ -2891,7 +2894,7 @@ static void signal_delivered(struct ksignal *ksig, int stepping)
    if (current->sas_ss_flags & SS_AUTODISARM)
    sas_ss_reset(current);
    if (stepping)
    - ptrace_notify(SIGTRAP);
    + ptrace_notify(SIGTRAP, 0);
    }

    void signal_setup_done(int failed, struct ksignal *ksig, int stepping)
    --
    2.29.2
    \
     
     \ /
      Last update: 2022-03-16 00:23    [W:4.046 / U:0.196 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site