Messages in this thread | | | From | Kyle Huey <> | Date | Mon, 26 Oct 2020 09:14:13 -0700 | Subject | Re: [REGRESSION] x86/debug: After PTRACE_SINGLESTEP DR_STEP is no longer reported in dr6 |
| |
On Mon, Oct 26, 2020 at 9:05 AM Peter Zijlstra <peterz@infradead.org> wrote: > > On Mon, Oct 26, 2020 at 04:55:21PM +0100, Peter Zijlstra wrote: > > On Mon, Oct 26, 2020 at 07:33:08AM -0700, Kyle Huey wrote: > > > After resuming a ptracee with PTRACE_SINGLESTEP, in the following > > > ptrace stop retrieving the dr6 value for the tracee gets a value that > > > does not include DR_STEP (it is in fact always DR6_RESERVED). I > > > bisected this to the 13cb73490f475f8e7669f9288be0bcfa85399b1f merge. I > > > did not bisect further. > > > > > > I don't see any handling to ever set DR_STEP in virtual_dr6, so I > > > think this code is just broken. > > > > > > Sorry for not testing this when I was CCd on the original patch series :) > > > > Urgh, now I have to try and remember how all that worked again ... > > > > I suspect it's either one (or both) of the last two: > > > > f4956cf83ed1 ("x86/debug: Support negative polarity DR6 bits") > > d53d9bc0cf78 ("x86/debug: Change thread.debugreg6 to thread.virtual_dr6") > > > > > > Just to clarify, the sequence is something like: > > > > - tracer: ptrace(PTRACE_SINGLESTEP) > > - tracee: #DB, DR6 contains DR_STEP > > - tracer: ptrace_get_debugreg(6) > > > > ? > > > > You're right that that would be broken, let me try and figure out what > > the best way would be 'fix' that. > > > > Also, can you confirm that pthread_set_debugreg(6) should not do > > anything useful? > > > Does something like this make sense? > > > diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c > index 3c70fb34028b..0e7641ac19a8 100644 > --- a/arch/x86/kernel/traps.c > +++ b/arch/x86/kernel/traps.c > @@ -799,6 +799,13 @@ static __always_inline unsigned long debug_read_clear_dr6(void) > */ > current->thread.virtual_dr6 = 0; > > + /* > + * If PTRACE requested SINGLE(BLOCK)STEP, make sure to reflect that in > + * the ptrace visible DR6 copy. > + */ > + if (test_thread_flag(TIF_BLOCKSTEP) || test_thread_flag(TIF_SINGLESTEP)) > + current->thread.virtual_dr6 |= dr6 & DR_STEP; > + > /* > * The SDM says "The processor clears the BTF flag when it > * generates a debug exception." Clear TIF_BLOCKSTEP to keep
I don't think the `& DR_STEP` should be necessary, that bit should be set by the hardware, I believe.
Also if a program sets TF on itself in EFLAGS and generates a trap it should still have DR_STEP set in the ptrace-visible dr6, which this won't do.
Is there a reason not to always copy dr6 into virtual_dr6 here, regardless of TIF_SINGLESTEP/etc?
- Kyle
| |