> kgdb/kdb and the perf event system both present garbage status in dr6 > then subsequently write this status into the thread.debugreg6 variable, > then in some cases call hw_breakpoint_restore() which writes this > status back into the dr6 hardware register. >
I wanted to note here that this is the kgdb perf handler. What's a serious problem here (and other perf handlers do this too) is that kgdb has receive ONE breakpoint exception when this handler is called, then inside this handler he sets ALL exception bits for any user defined exceptions then sends this value to get stuffed back into the dr6 register, so for each breakpoint that happens, it will trigger a cascade of checks in the hw_breakpoint.c handler most hitting NULL bp structures when this value gets read back out of dr6. If one of them fires off and debugreg6 has gotten zapped -- POW -- system crash. > arch/x86/kernel/kgdb.c > static void kgdb_hw_overflow_handler(struct perf_event *event, > struct perf_sample_data *data, struct pt_regs *regs) > { > struct task_struct *tsk = current; > int i; > > for (i = 0; i < 4; i++) > if (breakinfo[i].enabled) > tsk->thread.debugreg6 |= (DR_TRAP0 << i); > } > > arch/x86/kernel/kgdb.c > static void kgdb_correct_hw_break(void) > { > ... snip ... > > if (!dbg_is_early) > hw_breakpoint_restore(); > > ... snip ... > } > > arch/x86/kernel/hw_breakpoint.c > void hw_breakpoint_restore(void) > { > set_debugreg(__this_cpu_read(cpu_debugreg[0]), 0); > set_debugreg(__this_cpu_read(cpu_debugreg[1]), 1); > set_debugreg(__this_cpu_read(cpu_debugreg[2]), 2); > set_debugreg(__this_cpu_read(cpu_debugreg[3]), 3); > set_debugreg(current->thread.debugreg6, 6); > set_debugreg(__this_cpu_read(cpu_dr7), 7); > } > So it goes like this: INT1 exception #1 -> kgdb/perf -> set status bits for ALL exceptions I registered (1,2,3,4) -> stuff it back into dr6 -> INT1 exception #2 -> pickup bogus status in dr6 -> call handlers for (1,2,3,4) -> Oops someone changed thread.debugreg6 (kgdb,perf,kdb,gdb,os, current moved) -> CRASH Jeff -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/