Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 256844
b: refs/heads/master
c: 544b2c9
h: refs/heads/master
v: v3
  • Loading branch information
Tejun Heo authored and Oleg Nesterov committed Jun 16, 2011
1 parent 0769f93 commit 80ed637
Show file tree
Hide file tree
Showing 6 changed files with 54 additions and 9 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: fb1d910c178ba0c5bc32d3e5a9e82e05b7aad3cd
refs/heads/master: 544b2c91a9f14f9565af1972203438b7f49afd48
1 change: 1 addition & 0 deletions trunk/include/linux/ptrace.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@

#define PTRACE_SEIZE 0x4206
#define PTRACE_INTERRUPT 0x4207
#define PTRACE_LISTEN 0x4208

/* flags in @data for PTRACE_SEIZE */
#define PTRACE_SEIZE_DEVEL 0x80000000 /* temp flag for development */
Expand Down
2 changes: 2 additions & 0 deletions trunk/include/linux/sched.h
Original file line number Diff line number Diff line change
Expand Up @@ -1813,13 +1813,15 @@ extern void thread_group_times(struct task_struct *p, cputime_t *ut, cputime_t *
#define JOBCTL_TRAP_STOP_BIT 19 /* trap for STOP */
#define JOBCTL_TRAP_NOTIFY_BIT 20 /* trap for NOTIFY */
#define JOBCTL_TRAPPING_BIT 21 /* switching to TRACED */
#define JOBCTL_LISTENING_BIT 22 /* ptracer is listening for events */

#define JOBCTL_STOP_DEQUEUED (1 << JOBCTL_STOP_DEQUEUED_BIT)
#define JOBCTL_STOP_PENDING (1 << JOBCTL_STOP_PENDING_BIT)
#define JOBCTL_STOP_CONSUME (1 << JOBCTL_STOP_CONSUME_BIT)
#define JOBCTL_TRAP_STOP (1 << JOBCTL_TRAP_STOP_BIT)
#define JOBCTL_TRAP_NOTIFY (1 << JOBCTL_TRAP_NOTIFY_BIT)
#define JOBCTL_TRAPPING (1 << JOBCTL_TRAPPING_BIT)
#define JOBCTL_LISTENING (1 << JOBCTL_LISTENING_BIT)

#define JOBCTL_TRAP_MASK (JOBCTL_TRAP_STOP | JOBCTL_TRAP_NOTIFY)
#define JOBCTL_PENDING_MASK (JOBCTL_STOP_PENDING | JOBCTL_TRAP_MASK)
Expand Down
3 changes: 2 additions & 1 deletion trunk/kernel/exit.c
Original file line number Diff line number Diff line change
Expand Up @@ -1368,7 +1368,8 @@ static int wait_task_zombie(struct wait_opts *wo, struct task_struct *p)
static int *task_stopped_code(struct task_struct *p, bool ptrace)
{
if (ptrace) {
if (task_is_stopped_or_traced(p))
if (task_is_stopped_or_traced(p) &&
!(p->jobctl & JOBCTL_LISTENING))
return &p->exit_code;
} else {
if (p->signal->flags & SIGNAL_STOP_STOPPED)
Expand Down
42 changes: 39 additions & 3 deletions trunk/kernel/ptrace.c
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,8 @@ int ptrace_check_attach(struct task_struct *child, bool ignore_state)
*/
spin_lock_irq(&child->sighand->siglock);
WARN_ON_ONCE(task_is_stopped(child));
if (task_is_traced(child) || ignore_state)
if (ignore_state || (task_is_traced(child) &&
!(child->jobctl & JOBCTL_LISTENING)))
ret = 0;
spin_unlock_irq(&child->sighand->siglock);
}
Expand Down Expand Up @@ -660,7 +661,7 @@ int ptrace_request(struct task_struct *child, long request,
{
bool seized = child->ptrace & PT_SEIZED;
int ret = -EIO;
siginfo_t siginfo;
siginfo_t siginfo, *si;
void __user *datavp = (void __user *) data;
unsigned long __user *datalp = datavp;
unsigned long flags;
Expand Down Expand Up @@ -710,8 +711,43 @@ int ptrace_request(struct task_struct *child, long request,
if (unlikely(!seized || !lock_task_sighand(child, &flags)))
break;

/*
* INTERRUPT doesn't disturb existing trap sans one
* exception. If ptracer issued LISTEN for the current
* STOP, this INTERRUPT should clear LISTEN and re-trap
* tracee into STOP.
*/
if (likely(task_set_jobctl_pending(child, JOBCTL_TRAP_STOP)))
signal_wake_up(child, 0);
signal_wake_up(child, child->jobctl & JOBCTL_LISTENING);

unlock_task_sighand(child, &flags);
ret = 0;
break;

case PTRACE_LISTEN:
/*
* Listen for events. Tracee must be in STOP. It's not
* resumed per-se but is not considered to be in TRACED by
* wait(2) or ptrace(2). If an async event (e.g. group
* stop state change) happens, tracee will enter STOP trap
* again. Alternatively, ptracer can issue INTERRUPT to
* finish listening and re-trap tracee into STOP.
*/
if (unlikely(!seized || !lock_task_sighand(child, &flags)))
break;

si = child->last_siginfo;
if (unlikely(!si || si->si_code >> 8 != PTRACE_EVENT_STOP))
break;

child->jobctl |= JOBCTL_LISTENING;

/*
* If NOTIFY is set, it means event happened between start
* of this trap and now. Trigger re-trap immediately.
*/
if (child->jobctl & JOBCTL_TRAP_NOTIFY)
signal_wake_up(child, true);

unlock_task_sighand(child, &flags);
ret = 0;
Expand Down
13 changes: 9 additions & 4 deletions trunk/kernel/signal.c
Original file line number Diff line number Diff line change
Expand Up @@ -825,9 +825,11 @@ static int check_kill_permission(int sig, struct siginfo *info,
* TRAP_STOP to notify ptracer of an event. @t must have been seized by
* ptracer.
*
* If @t is running, STOP trap will be taken. If already trapped, STOP
* trap will be eventually taken without returning to userland after the
* existing traps are finished by PTRACE_CONT.
* If @t is running, STOP trap will be taken. If trapped for STOP and
* ptracer is listening for events, tracee is woken up so that it can
* re-trap for the new event. If trapped otherwise, STOP trap will be
* eventually taken without returning to userland after the existing traps
* are finished by PTRACE_CONT.
*
* CONTEXT:
* Must be called with @task->sighand->siglock held.
Expand All @@ -838,7 +840,7 @@ static void ptrace_trap_notify(struct task_struct *t)
assert_spin_locked(&t->sighand->siglock);

task_set_jobctl_pending(t, JOBCTL_TRAP_NOTIFY);
signal_wake_up(t, 0);
signal_wake_up(t, t->jobctl & JOBCTL_LISTENING);
}

/*
Expand Down Expand Up @@ -1894,6 +1896,9 @@ static void ptrace_stop(int exit_code, int why, int clear_code, siginfo_t *info)
spin_lock_irq(&current->sighand->siglock);
current->last_siginfo = NULL;

/* LISTENING can be set only during STOP traps, clear it */
current->jobctl &= ~JOBCTL_LISTENING;

/*
* Queued signals ignored us while we were stopped for tracing.
* So check for any that we should take before resuming user mode.
Expand Down

0 comments on commit 80ed637

Please sign in to comment.