History

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.

Eric W. Biederman committed 4 years ago

Commit 336d4b81 parent 355f8413 files · +16 −16Browse files

Unified · Split

3 files
  1. include/linux/ptrace.h +3 −6
  2. include/uapi/linux/ptrace.h +1 −1
  3. kernel/signal.c +12 −9
include/linux/ptrace.h+3−6
@@ -60,7 +60,7 @@ extern int ptrace_writedata(struct task_struct *tsk, char __user *src, unsigned · 59 unmodified lines
60extern void ptrace_disable(struct task_struct *);60extern void ptrace_disable(struct task_struct *);
61extern int ptrace_request(struct task_struct *child, long request,61extern int ptrace_request(struct task_struct *child, long request,
62 unsigned long addr, unsigned long data);62 unsigned long addr, unsigned long data);
63extern void ptrace_notify(int exit_code);63extern void ptrace_notify(int exit_code, unsigned long message);
64extern void __ptrace_link(struct task_struct *child,64extern void __ptrace_link(struct task_struct *child,
65 struct task_struct *new_parent,65 struct task_struct *new_parent,
66 const struct cred *ptracer_cred);66 const struct cred *ptracer_cred);
@@ -155,8 +155,7 @@ static inline bool ptrace_event_enabled(struct task_struct *task, int event) · 88 unmodified lines
155static inline void ptrace_event(int event, unsigned long message)155static inline void ptrace_event(int event, unsigned long message)
156{156{
157 if (unlikely(ptrace_event_enabled(current, event))) {157 if (unlikely(ptrace_event_enabled(current, event))) {
158 current->ptrace_message = message;158 ptrace_notify((event << 8) | SIGTRAP, message);
159 ptrace_notify((event << 8) | SIGTRAP);
160 } else if (event == PTRACE_EVENT_EXEC) {159 } else if (event == PTRACE_EVENT_EXEC) {
161 /* legacy EXEC report via SIGTRAP */160 /* legacy EXEC report via SIGTRAP */
162 if ((current->ptrace & (PT_PTRACED|PT_SEIZED)) == PT_PTRACED)161 if ((current->ptrace & (PT_PTRACED|PT_SEIZED)) == PT_PTRACED)
@@ -424,8 +423,7 @@ static inline int ptrace_report_syscall(unsigned long message) · 261 unmodified lines
424 if (!(ptrace & PT_PTRACED))423 if (!(ptrace & PT_PTRACED))
425 return 0;424 return 0;
426 425
427 current->ptrace_message = message;426 ptrace_notify(SIGTRAP | ((ptrace & PT_TRACESYSGOOD) ? 0x80 : 0), message);
428 ptrace_notify(SIGTRAP | ((ptrace & PT_TRACESYSGOOD) ? 0x80 : 0));
429 427
430 /*428 /*
431 * this isn't the same as continuing with a signal, but it will do429 * 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) · 5 unmodified lines
437 current->exit_code = 0;435 current->exit_code = 0;
438 }436 }
439 437
440 current->ptrace_message = 0;
441 return fatal_signal_pending(current);438 return fatal_signal_pending(current);
442}439}
443 440
include/uapi/linux/ptrace.h+1−1
@@ -114,7 +114,7 @@ struct ptrace_rseq_configuration { · 113 unmodified lines
114 114
115/*115/*
116 * These values are stored in task->ptrace_message116 * These values are stored in task->ptrace_message
117 * by ptrace_report_syscall_* to describe the current syscall-stop.117 * by ptrace_stop to describe the current syscall-stop.
118 */118 */
119#define PTRACE_EVENTMSG_SYSCALL_ENTRY 1119#define PTRACE_EVENTMSG_SYSCALL_ENTRY 1
120#define PTRACE_EVENTMSG_SYSCALL_EXIT 2120#define PTRACE_EVENTMSG_SYSCALL_EXIT 2
kernel/signal.c+12−9
@@ -2191,7 +2191,8 @@ static void do_notify_parent_cldstop(struct task_struct *tsk, · 2190 unmodified lines
2191 * If we actually decide not to stop at all because the tracer2191 * If we actually decide not to stop at all because the tracer
2192 * is gone, we keep current->exit_code unless clear_code.2192 * is gone, we keep current->exit_code unless clear_code.
2193 */2193 */
2194static void ptrace_stop(int exit_code, int why, int clear_code, kernel_siginfo_t *info)2194static void ptrace_stop(int exit_code, int why, int clear_code,
2195 unsigned long message, kernel_siginfo_t *info)
2195 __releases(&current->sighand->siglock)2196 __releases(&current->sighand->siglock)
2196 __acquires(&current->sighand->siglock)2197 __acquires(&current->sighand->siglock)
2197{2198{
@@ -2237,6 +2238,7 @@ static void ptrace_stop(int exit_code, int why, int clear_code, kernel_siginfo_t · 39 unmodified lines
2237 */2238 */
2238 smp_wmb();2239 smp_wmb();
2239 2240
2241 current->ptrace_message = message;
2240 current->last_siginfo = info;2242 current->last_siginfo = info;
2241 current->exit_code = exit_code;2243 current->exit_code = exit_code;
2242 2244
@@ -2315,6 +2317,7 @@ static void ptrace_stop(int exit_code, int why, int clear_code, kernel_siginfo_t · 72 unmodified lines
2315 */2317 */
2316 spin_lock_irq(&current->sighand->siglock);2318 spin_lock_irq(&current->sighand->siglock);
2317 current->last_siginfo = NULL;2319 current->last_siginfo = NULL;
2320 current->ptrace_message = 0;
2318 2321
2319 /* LISTENING can be set only during STOP traps, clear it */2322 /* LISTENING can be set only during STOP traps, clear it */
2320 current->jobctl &= ~JOBCTL_LISTENING;2323 current->jobctl &= ~JOBCTL_LISTENING;
@@ -2327,7 +2330,7 @@ static void ptrace_stop(int exit_code, int why, int clear_code, kernel_siginfo_t · 6 unmodified lines
2327 recalc_sigpending_tsk(current);2330 recalc_sigpending_tsk(current);
2328}2331}
2329 2332
2330static void ptrace_do_notify(int signr, int exit_code, int why)2333static void ptrace_do_notify(int signr, int exit_code, int why, unsigned long message)
2331{2334{
2332 kernel_siginfo_t info;2335 kernel_siginfo_t info;
2333 2336
@@ -2338,17 +2341,17 @@ static void ptrace_do_notify(int signr, int exit_code, int why) · 4 unmodified lines
2338 info.si_uid = from_kuid_munged(current_user_ns(), current_uid());2341 info.si_uid = from_kuid_munged(current_user_ns(), current_uid());
2339 2342
2340 /* Let the debugger run. */2343 /* Let the debugger run. */
2341 ptrace_stop(exit_code, why, 1, &info);2344 ptrace_stop(exit_code, why, 1, message, &info);
2342}2345}
2343 2346
2344void ptrace_notify(int exit_code)2347void ptrace_notify(int exit_code, unsigned long message)
2345{2348{
2346 BUG_ON((exit_code & (0x7f | ~0xffff)) != SIGTRAP);2349 BUG_ON((exit_code & (0x7f | ~0xffff)) != SIGTRAP);
2347 if (unlikely(task_work_pending(current)))2350 if (unlikely(task_work_pending(current)))
2348 task_work_run();2351 task_work_run();
2349 2352
2350 spin_lock_irq(&current->sighand->siglock);2353 spin_lock_irq(&current->sighand->siglock);
2351 ptrace_do_notify(SIGTRAP, exit_code, CLD_TRAPPED);2354 ptrace_do_notify(SIGTRAP, exit_code, CLD_TRAPPED, message);
2352 spin_unlock_irq(&current->sighand->siglock);2355 spin_unlock_irq(&current->sighand->siglock);
2353}2356}
2354 2357
@@ -2504,10 +2507,10 @@ static void do_jobctl_trap(void) · 149 unmodified lines
2504 signr = SIGTRAP;2507 signr = SIGTRAP;
2505 WARN_ON_ONCE(!signr);2508 WARN_ON_ONCE(!signr);
2506 ptrace_do_notify(signr, signr | (PTRACE_EVENT_STOP << 8),2509 ptrace_do_notify(signr, signr | (PTRACE_EVENT_STOP << 8),
2507 CLD_STOPPED);2510 CLD_STOPPED, 0);
2508 } else {2511 } else {
2509 WARN_ON_ONCE(!signr);2512 WARN_ON_ONCE(!signr);
2510 ptrace_stop(signr, CLD_STOPPED, 0, NULL);2513 ptrace_stop(signr, CLD_STOPPED, 0, 0, NULL);
2511 current->exit_code = 0;2514 current->exit_code = 0;
2512 }2515 }
2513}2516}
@@ -2561,7 +2564,7 @@ static int ptrace_signal(int signr, kernel_siginfo_t *info, enum pid_type type) · 47 unmodified lines
2561 * comment in dequeue_signal().2564 * comment in dequeue_signal().
2562 */2565 */
2563 current->jobctl |= JOBCTL_STOP_DEQUEUED;2566 current->jobctl |= JOBCTL_STOP_DEQUEUED;
2564 ptrace_stop(signr, CLD_TRAPPED, 0, info);2567 ptrace_stop(signr, CLD_TRAPPED, 0, 0, info);
2565 2568
2566 /* We're back. Did the debugger cancel the sig? */2569 /* We're back. Did the debugger cancel the sig? */
2567 signr = current->exit_code;2570 signr = current->exit_code;
@@ -2891,7 +2894,7 @@ static void signal_delivered(struct ksignal *ksig, int stepping) · 323 unmodified lines
2891 if (current->sas_ss_flags & SS_AUTODISARM)2894 if (current->sas_ss_flags & SS_AUTODISARM)
2892 sas_ss_reset(current);2895 sas_ss_reset(current);
2893 if (stepping)2896 if (stepping)
2894 ptrace_notify(SIGTRAP);2897 ptrace_notify(SIGTRAP, 0);
2895}2898}
2896 2899
2897void signal_setup_done(int failed, struct ksignal *ksig, int stepping)2900void signal_setup_done(int failed, struct ksignal *ksig, int stepping)