[BUG] hw_breakpoint_handler corrupts dr6 status on stack hw_breakpoint.c: 480:0

From: Jeff Merkey
Date: Wed Jan 13 2016 - 12:45:30 EST


The do_debug code in traps.c places the contents of the dr6 register
into the args->err pointer which is passed through the notify-die
handlers to hw_breakpoint_handler/

traps.c 629:0
if (notify_die(DIE_DEBUG, "debug", regs, (long)&dr6, error_code,
SIGTRAP) == NOTIFY_STOP)
goto exit;

The busted handler subsequently clears the bits on the stack
destroying the state of dr6
as to which breakpoint just occurred.

hw_breakpoint.c 480:0
/*
* Reset the 'i'th TRAP bit in dr6 to denote completion of
* exception handling
*/
(*dr6_p) &= ~(DR_TRAP0 << i);
/*

Subsequent int1 handlers called by notify_die also receive this
argument passed after hw_breakpoint_handler has corrupted it, and
cannot ascertain the source of the breakpoint from the dr6 value.
Other int1 handlers that are registered must locally hook traps.c to
cache there own copy of this value since the handler in
hw_breakpoint.c corrupts it.

A patch to fix this is non-trivial because the entire subsystem has
been coded around this wierd behavior that prevents kernel debuggers
from obtaining and unaltered version of dr6 since the register is
zeroed out in traps.c before being converted into a stack variable
that gets passed around to the various consumers of the breakpoint API
(after it corrupts it of course).

Jeff