Skip to content

Commit 67850b7

Browse files
committed
Merge tag 'ptrace_stop-cleanup-for-v5.19' of git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm/user-namespace
Pull ptrace_stop cleanups from Eric Biederman: "While looking at the ptrace problems with PREEMPT_RT and the problems Peter Zijlstra was encountering with ptrace in his freezer rewrite I identified some cleanups to ptrace_stop that make sense on their own and move make resolving the other problems much simpler. The biggest issue is the habit of the ptrace code to change task->__state from the tracer to suppress TASK_WAKEKILL from waking up the tracee. No other code in the kernel does that and it is straight forward to update signal_wake_up and friends to make that unnecessary. Peter's task freezer sets frozen tasks to a new state TASK_FROZEN and then it stores them by calling "wake_up_state(t, TASK_FROZEN)" relying on the fact that all stopped states except the special stop states can tolerate spurious wake up and recover their state. The state of stopped and traced tasked is changed to be stored in task->jobctl as well as in task->__state. This makes it possible for the freezer to recover tasks in these special states, as well as serving as a general cleanup. With a little more work in that direction I believe TASK_STOPPED can learn to tolerate spurious wake ups and become an ordinary stop state. The TASK_TRACED state has to remain a special state as the registers for a process are only reliably available when the process is stopped in the scheduler. Fundamentally ptrace needs acess to the saved register values of a task. There are bunch of semi-random ptrace related cleanups that were found while looking at these issues. One cleanup that deserves to be called out is from commit 57b6de0 ("ptrace: Admit ptrace_stop can generate spuriuos SIGTRAPs"). This makes a change that is technically user space visible, in the handling of what happens to a tracee when a tracer dies unexpectedly. According to our testing and our understanding of userspace nothing cares that spurious SIGTRAPs can be generated in that case" * tag 'ptrace_stop-cleanup-for-v5.19' of git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm/user-namespace: sched,signal,ptrace: Rework TASK_TRACED, TASK_STOPPED state ptrace: Always take siglock in ptrace_resume ptrace: Don't change __state ptrace: Admit ptrace_stop can generate spuriuos SIGTRAPs ptrace: Document that wait_task_inactive can't fail ptrace: Reimplement PTRACE_KILL by always sending SIGKILL signal: Use lockdep_assert_held instead of assert_spin_locked ptrace: Remove arch_ptrace_attach ptrace/xtensa: Replace PT_SINGLESTEP with TIF_SINGLESTEP ptrace/um: Replace PT_DTRACE with TIF_SINGLESTEP signal: Replace __group_send_sig_info with send_signal_locked signal: Rename send_signal send_signal_locked
2 parents 1ec6574 + 31cae1e commit 67850b7

File tree

20 files changed

+140
-240
lines changed

20 files changed

+140
-240
lines changed

arch/ia64/include/asm/ptrace.h

-4
Original file line numberDiff line numberDiff line change
@@ -139,10 +139,6 @@ static inline long regs_return_value(struct pt_regs *regs)
139139
#define arch_ptrace_stop_needed() \
140140
(!test_thread_flag(TIF_RESTORE_RSE))
141141

142-
extern void ptrace_attach_sync_user_rbs (struct task_struct *);
143-
#define arch_ptrace_attach(child) \
144-
ptrace_attach_sync_user_rbs(child)
145-
146142
#define arch_has_single_step() (1)
147143
#define arch_has_block_step() (1)
148144

arch/ia64/kernel/ptrace.c

-57
Original file line numberDiff line numberDiff line change
@@ -617,63 +617,6 @@ void ia64_sync_krbs(void)
617617
unw_init_running(do_sync_rbs, ia64_sync_kernel_rbs);
618618
}
619619

620-
/*
621-
* After PTRACE_ATTACH, a thread's register backing store area in user
622-
* space is assumed to contain correct data whenever the thread is
623-
* stopped. arch_ptrace_stop takes care of this on tracing stops.
624-
* But if the child was already stopped for job control when we attach
625-
* to it, then it might not ever get into ptrace_stop by the time we
626-
* want to examine the user memory containing the RBS.
627-
*/
628-
void
629-
ptrace_attach_sync_user_rbs (struct task_struct *child)
630-
{
631-
int stopped = 0;
632-
struct unw_frame_info info;
633-
634-
/*
635-
* If the child is in TASK_STOPPED, we need to change that to
636-
* TASK_TRACED momentarily while we operate on it. This ensures
637-
* that the child won't be woken up and return to user mode while
638-
* we are doing the sync. (It can only be woken up for SIGKILL.)
639-
*/
640-
641-
read_lock(&tasklist_lock);
642-
if (child->sighand) {
643-
spin_lock_irq(&child->sighand->siglock);
644-
if (READ_ONCE(child->__state) == TASK_STOPPED &&
645-
!test_and_set_tsk_thread_flag(child, TIF_RESTORE_RSE)) {
646-
set_notify_resume(child);
647-
648-
WRITE_ONCE(child->__state, TASK_TRACED);
649-
stopped = 1;
650-
}
651-
spin_unlock_irq(&child->sighand->siglock);
652-
}
653-
read_unlock(&tasklist_lock);
654-
655-
if (!stopped)
656-
return;
657-
658-
unw_init_from_blocked_task(&info, child);
659-
do_sync_rbs(&info, ia64_sync_user_rbs);
660-
661-
/*
662-
* Now move the child back into TASK_STOPPED if it should be in a
663-
* job control stop, so that SIGCONT can be used to wake it up.
664-
*/
665-
read_lock(&tasklist_lock);
666-
if (child->sighand) {
667-
spin_lock_irq(&child->sighand->siglock);
668-
if (READ_ONCE(child->__state) == TASK_TRACED &&
669-
(child->signal->flags & SIGNAL_STOP_STOPPED)) {
670-
WRITE_ONCE(child->__state, TASK_STOPPED);
671-
}
672-
spin_unlock_irq(&child->sighand->siglock);
673-
}
674-
read_unlock(&tasklist_lock);
675-
}
676-
677620
/*
678621
* Write f32-f127 back to task->thread.fph if it has been modified.
679622
*/

arch/um/include/asm/thread_info.h

+2
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ static inline struct thread_info *current_thread_info(void)
6060
#define TIF_RESTORE_SIGMASK 7
6161
#define TIF_NOTIFY_RESUME 8
6262
#define TIF_SECCOMP 9 /* secure computing */
63+
#define TIF_SINGLESTEP 10 /* single stepping userspace */
6364

6465
#define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE)
6566
#define _TIF_SIGPENDING (1 << TIF_SIGPENDING)
@@ -68,5 +69,6 @@ static inline struct thread_info *current_thread_info(void)
6869
#define _TIF_MEMDIE (1 << TIF_MEMDIE)
6970
#define _TIF_SYSCALL_AUDIT (1 << TIF_SYSCALL_AUDIT)
7071
#define _TIF_SECCOMP (1 << TIF_SECCOMP)
72+
#define _TIF_SINGLESTEP (1 << TIF_SINGLESTEP)
7173

7274
#endif

arch/um/kernel/exec.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ void start_thread(struct pt_regs *regs, unsigned long eip, unsigned long esp)
4343
{
4444
PT_REGS_IP(regs) = eip;
4545
PT_REGS_SP(regs) = esp;
46-
current->ptrace &= ~PT_DTRACE;
46+
clear_thread_flag(TIF_SINGLESTEP);
4747
#ifdef SUBARCH_EXECVE1
4848
SUBARCH_EXECVE1(regs->regs);
4949
#endif

arch/um/kernel/process.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -336,7 +336,7 @@ int singlestepping(void * t)
336336
{
337337
struct task_struct *task = t ? t : current;
338338

339-
if (!(task->ptrace & PT_DTRACE))
339+
if (!test_thread_flag(TIF_SINGLESTEP))
340340
return 0;
341341

342342
if (task->thread.singlestep_syscall)

arch/um/kernel/ptrace.c

+4-4
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212
void user_enable_single_step(struct task_struct *child)
1313
{
14-
child->ptrace |= PT_DTRACE;
14+
set_tsk_thread_flag(child, TIF_SINGLESTEP);
1515
child->thread.singlestep_syscall = 0;
1616

1717
#ifdef SUBARCH_SET_SINGLESTEPPING
@@ -21,7 +21,7 @@ void user_enable_single_step(struct task_struct *child)
2121

2222
void user_disable_single_step(struct task_struct *child)
2323
{
24-
child->ptrace &= ~PT_DTRACE;
24+
clear_tsk_thread_flag(child, TIF_SINGLESTEP);
2525
child->thread.singlestep_syscall = 0;
2626

2727
#ifdef SUBARCH_SET_SINGLESTEPPING
@@ -120,7 +120,7 @@ static void send_sigtrap(struct uml_pt_regs *regs, int error_code)
120120
}
121121

122122
/*
123-
* XXX Check PT_DTRACE vs TIF_SINGLESTEP for singlestepping check and
123+
* XXX Check TIF_SINGLESTEP for singlestepping check and
124124
* PT_PTRACED vs TIF_SYSCALL_TRACE for syscall tracing check
125125
*/
126126
int syscall_trace_enter(struct pt_regs *regs)
@@ -144,7 +144,7 @@ void syscall_trace_leave(struct pt_regs *regs)
144144
audit_syscall_exit(regs);
145145

146146
/* Fake a debug trap */
147-
if (ptraced & PT_DTRACE)
147+
if (test_thread_flag(TIF_SINGLESTEP))
148148
send_sigtrap(&regs->regs, 0);
149149

150150
if (!test_thread_flag(TIF_SYSCALL_TRACE))

arch/um/kernel/signal.c

+2-2
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ static void handle_signal(struct ksignal *ksig, struct pt_regs *regs)
5353
unsigned long sp;
5454
int err;
5555

56-
if ((current->ptrace & PT_DTRACE) && (current->ptrace & PT_PTRACED))
56+
if (test_thread_flag(TIF_SINGLESTEP) && (current->ptrace & PT_PTRACED))
5757
singlestep = 1;
5858

5959
/* Did we come from a system call? */
@@ -128,7 +128,7 @@ void do_signal(struct pt_regs *regs)
128128
* on the host. The tracing thread will check this flag and
129129
* PTRACE_SYSCALL if necessary.
130130
*/
131-
if (current->ptrace & PT_DTRACE)
131+
if (test_thread_flag(TIF_SINGLESTEP))
132132
current->thread.singlestep_syscall =
133133
is_syscall(PT_REGS_IP(&current->thread.regs));
134134

arch/x86/kernel/step.c

+1-2
Original file line numberDiff line numberDiff line change
@@ -180,8 +180,7 @@ void set_task_blockstep(struct task_struct *task, bool on)
180180
*
181181
* NOTE: this means that set/clear TIF_BLOCKSTEP is only safe if
182182
* task is current or it can't be running, otherwise we can race
183-
* with __switch_to_xtra(). We rely on ptrace_freeze_traced() but
184-
* PTRACE_KILL is not safe.
183+
* with __switch_to_xtra(). We rely on ptrace_freeze_traced().
185184
*/
186185
local_irq_disable();
187186
debugctl = get_debugctlmsr();

arch/xtensa/kernel/ptrace.c

+2-2
Original file line numberDiff line numberDiff line change
@@ -224,12 +224,12 @@ const struct user_regset_view *task_user_regset_view(struct task_struct *task)
224224

225225
void user_enable_single_step(struct task_struct *child)
226226
{
227-
child->ptrace |= PT_SINGLESTEP;
227+
set_tsk_thread_flag(child, TIF_SINGLESTEP);
228228
}
229229

230230
void user_disable_single_step(struct task_struct *child)
231231
{
232-
child->ptrace &= ~PT_SINGLESTEP;
232+
clear_tsk_thread_flag(child, TIF_SINGLESTEP);
233233
}
234234

235235
/*

arch/xtensa/kernel/signal.c

+2-2
Original file line numberDiff line numberDiff line change
@@ -472,7 +472,7 @@ static void do_signal(struct pt_regs *regs)
472472
/* Set up the stack frame */
473473
ret = setup_frame(&ksig, sigmask_to_save(), regs);
474474
signal_setup_done(ret, &ksig, 0);
475-
if (current->ptrace & PT_SINGLESTEP)
475+
if (test_thread_flag(TIF_SINGLESTEP))
476476
task_pt_regs(current)->icountlevel = 1;
477477

478478
return;
@@ -498,7 +498,7 @@ static void do_signal(struct pt_regs *regs)
498498
/* If there's no signal to deliver, we just restore the saved mask. */
499499
restore_saved_sigmask();
500500

501-
if (current->ptrace & PT_SINGLESTEP)
501+
if (test_thread_flag(TIF_SINGLESTEP))
502502
task_pt_regs(current)->icountlevel = 1;
503503
return;
504504
}

drivers/tty/tty_jobctrl.c

+2-2
Original file line numberDiff line numberDiff line change
@@ -215,8 +215,8 @@ int tty_signal_session_leader(struct tty_struct *tty, int exit_session)
215215
spin_unlock_irq(&p->sighand->siglock);
216216
continue;
217217
}
218-
__group_send_sig_info(SIGHUP, SEND_SIG_PRIV, p);
219-
__group_send_sig_info(SIGCONT, SEND_SIG_PRIV, p);
218+
send_signal_locked(SIGHUP, SEND_SIG_PRIV, p, PIDTYPE_TGID);
219+
send_signal_locked(SIGCONT, SEND_SIG_PRIV, p, PIDTYPE_TGID);
220220
put_pid(p->signal->tty_old_pgrp); /* A noop */
221221
spin_lock(&tty->ctrl.lock);
222222
tty_pgrp = get_pid(tty->ctrl.pgrp);

include/linux/ptrace.h

-7
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ extern int ptrace_access_vm(struct task_struct *tsk, unsigned long addr,
3030

3131
#define PT_SEIZED 0x00010000 /* SEIZE used, enable new behavior */
3232
#define PT_PTRACED 0x00000001
33-
#define PT_DTRACE 0x00000002 /* delayed trace (used on um) */
3433

3534
#define PT_OPT_FLAG_SHIFT 3
3635
/* PT_TRACE_* event enable flags */
@@ -47,12 +46,6 @@ extern int ptrace_access_vm(struct task_struct *tsk, unsigned long addr,
4746
#define PT_EXITKILL (PTRACE_O_EXITKILL << PT_OPT_FLAG_SHIFT)
4847
#define PT_SUSPEND_SECCOMP (PTRACE_O_SUSPEND_SECCOMP << PT_OPT_FLAG_SHIFT)
4948

50-
/* single stepping state bits (used on ARM and PA-RISC) */
51-
#define PT_SINGLESTEP_BIT 31
52-
#define PT_SINGLESTEP (1<<PT_SINGLESTEP_BIT)
53-
#define PT_BLOCKSTEP_BIT 30
54-
#define PT_BLOCKSTEP (1<<PT_BLOCKSTEP_BIT)
55-
5649
extern long arch_ptrace(struct task_struct *child, long request,
5750
unsigned long addr, unsigned long data);
5851
extern int ptrace_readdata(struct task_struct *tsk, unsigned long src, char __user *dst, int len);

include/linux/sched.h

+4-6
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ struct task_group;
103103
/* Convenience macros for the sake of set_current_state: */
104104
#define TASK_KILLABLE (TASK_WAKEKILL | TASK_UNINTERRUPTIBLE)
105105
#define TASK_STOPPED (TASK_WAKEKILL | __TASK_STOPPED)
106-
#define TASK_TRACED (TASK_WAKEKILL | __TASK_TRACED)
106+
#define TASK_TRACED __TASK_TRACED
107107

108108
#define TASK_IDLE (TASK_UNINTERRUPTIBLE | TASK_NOLOAD)
109109

@@ -118,11 +118,9 @@ struct task_group;
118118

119119
#define task_is_running(task) (READ_ONCE((task)->__state) == TASK_RUNNING)
120120

121-
#define task_is_traced(task) ((READ_ONCE(task->__state) & __TASK_TRACED) != 0)
122-
123-
#define task_is_stopped(task) ((READ_ONCE(task->__state) & __TASK_STOPPED) != 0)
124-
125-
#define task_is_stopped_or_traced(task) ((READ_ONCE(task->__state) & (__TASK_STOPPED | __TASK_TRACED)) != 0)
121+
#define task_is_traced(task) ((READ_ONCE(task->jobctl) & JOBCTL_TRACED) != 0)
122+
#define task_is_stopped(task) ((READ_ONCE(task->jobctl) & JOBCTL_STOPPED) != 0)
123+
#define task_is_stopped_or_traced(task) ((READ_ONCE(task->jobctl) & (JOBCTL_STOPPED | JOBCTL_TRACED)) != 0)
126124

127125
/*
128126
* Special states are those that do not use the normal wait-loop pattern. See

include/linux/sched/jobctl.h

+8
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@ struct task_struct;
1919
#define JOBCTL_TRAPPING_BIT 21 /* switching to TRACED */
2020
#define JOBCTL_LISTENING_BIT 22 /* ptracer is listening for events */
2121
#define JOBCTL_TRAP_FREEZE_BIT 23 /* trap for cgroup freezer */
22+
#define JOBCTL_PTRACE_FROZEN_BIT 24 /* frozen for ptrace */
23+
24+
#define JOBCTL_STOPPED_BIT 26 /* do_signal_stop() */
25+
#define JOBCTL_TRACED_BIT 27 /* ptrace_stop() */
2226

2327
#define JOBCTL_STOP_DEQUEUED (1UL << JOBCTL_STOP_DEQUEUED_BIT)
2428
#define JOBCTL_STOP_PENDING (1UL << JOBCTL_STOP_PENDING_BIT)
@@ -28,6 +32,10 @@ struct task_struct;
2832
#define JOBCTL_TRAPPING (1UL << JOBCTL_TRAPPING_BIT)
2933
#define JOBCTL_LISTENING (1UL << JOBCTL_LISTENING_BIT)
3034
#define JOBCTL_TRAP_FREEZE (1UL << JOBCTL_TRAP_FREEZE_BIT)
35+
#define JOBCTL_PTRACE_FROZEN (1UL << JOBCTL_PTRACE_FROZEN_BIT)
36+
37+
#define JOBCTL_STOPPED (1UL << JOBCTL_STOPPED_BIT)
38+
#define JOBCTL_TRACED (1UL << JOBCTL_TRACED_BIT)
3139

3240
#define JOBCTL_TRAP_MASK (JOBCTL_TRAP_STOP | JOBCTL_TRAP_NOTIFY)
3341
#define JOBCTL_PENDING_MASK (JOBCTL_STOP_PENDING | JOBCTL_TRAP_MASK)

include/linux/sched/signal.h

+16-4
Original file line numberDiff line numberDiff line change
@@ -294,8 +294,10 @@ static inline int kernel_dequeue_signal(void)
294294
static inline void kernel_signal_stop(void)
295295
{
296296
spin_lock_irq(&current->sighand->siglock);
297-
if (current->jobctl & JOBCTL_STOP_DEQUEUED)
297+
if (current->jobctl & JOBCTL_STOP_DEQUEUED) {
298+
current->jobctl |= JOBCTL_STOPPED;
298299
set_special_state(TASK_STOPPED);
300+
}
299301
spin_unlock_irq(&current->sighand->siglock);
300302

301303
schedule();
@@ -444,13 +446,23 @@ extern void calculate_sigpending(void);
444446

445447
extern void signal_wake_up_state(struct task_struct *t, unsigned int state);
446448

447-
static inline void signal_wake_up(struct task_struct *t, bool resume)
449+
static inline void signal_wake_up(struct task_struct *t, bool fatal)
448450
{
449-
signal_wake_up_state(t, resume ? TASK_WAKEKILL : 0);
451+
unsigned int state = 0;
452+
if (fatal && !(t->jobctl & JOBCTL_PTRACE_FROZEN)) {
453+
t->jobctl &= ~(JOBCTL_STOPPED | JOBCTL_TRACED);
454+
state = TASK_WAKEKILL | __TASK_TRACED;
455+
}
456+
signal_wake_up_state(t, state);
450457
}
451458
static inline void ptrace_signal_wake_up(struct task_struct *t, bool resume)
452459
{
453-
signal_wake_up_state(t, resume ? __TASK_TRACED : 0);
460+
unsigned int state = 0;
461+
if (resume) {
462+
t->jobctl &= ~JOBCTL_TRACED;
463+
state = __TASK_TRACED;
464+
}
465+
signal_wake_up_state(t, state);
454466
}
455467

456468
void task_join_group_stop(struct task_struct *task);

include/linux/signal.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -282,7 +282,8 @@ extern int do_send_sig_info(int sig, struct kernel_siginfo *info,
282282
struct task_struct *p, enum pid_type type);
283283
extern int group_send_sig_info(int sig, struct kernel_siginfo *info,
284284
struct task_struct *p, enum pid_type type);
285-
extern int __group_send_sig_info(int, struct kernel_siginfo *, struct task_struct *);
285+
extern int send_signal_locked(int sig, struct kernel_siginfo *info,
286+
struct task_struct *p, enum pid_type type);
286287
extern int sigprocmask(int, sigset_t *, sigset_t *);
287288
extern void set_current_blocked(sigset_t *);
288289
extern void __set_current_blocked(const sigset_t *);

0 commit comments

Comments
 (0)