Skip to content

Commit

Permalink
x86 ptrace: block-step fix
Browse files Browse the repository at this point in the history
The enable_single_step() logic bails out early if TF is already set.
That skips some of the bookkeeping that keeps things straight.
This makes PTRACE_SINGLEBLOCK break the behavior of a user task
that was already setting TF itself in user mode.

Fix the bookkeeping to notice the old TF setting as it should.

Test case at: http://sources.redhat.com/cgi-bin/cvsweb.cgi/~checkout~/tests/ptrace-tests/tests/step-jump-cont-strict.c?cvsroot=systemtap

Signed-off-by: Roland McGrath <roland@redhat.com>
  • Loading branch information
Roland McGrath committed Jul 16, 2008
1 parent a3cf859 commit 6718d0d
Showing 1 changed file with 16 additions and 6 deletions.
22 changes: 16 additions & 6 deletions arch/x86/kernel/step.c
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ static int is_setting_trap_flag(struct task_struct *child, struct pt_regs *regs)
static int enable_single_step(struct task_struct *child)
{
struct pt_regs *regs = task_pt_regs(child);
unsigned long oflags;

/*
* Always set TIF_SINGLESTEP - this guarantees that
Expand All @@ -113,11 +114,7 @@ static int enable_single_step(struct task_struct *child)
*/
set_tsk_thread_flag(child, TIF_SINGLESTEP);

/*
* If TF was already set, don't do anything else
*/
if (regs->flags & X86_EFLAGS_TF)
return 0;
oflags = regs->flags;

/* Set TF on the kernel stack.. */
regs->flags |= X86_EFLAGS_TF;
Expand All @@ -126,9 +123,22 @@ static int enable_single_step(struct task_struct *child)
* ..but if TF is changed by the instruction we will trace,
* don't mark it as being "us" that set it, so that we
* won't clear it by hand later.
*
* Note that if we don't actually execute the popf because
* of a signal arriving right now or suchlike, we will lose
* track of the fact that it really was "us" that set it.
*/
if (is_setting_trap_flag(child, regs))
if (is_setting_trap_flag(child, regs)) {
clear_tsk_thread_flag(child, TIF_FORCED_TF);
return 0;
}

/*
* If TF was already set, check whether it was us who set it.
* If not, we should never attempt a block step.
*/
if (oflags & X86_EFLAGS_TF)
return test_tsk_thread_flag(child, TIF_FORCED_TF);

set_tsk_thread_flag(child, TIF_FORCED_TF);

Expand Down

0 comments on commit 6718d0d

Please sign in to comment.