⬢ DragonFlyBSD Kernel Audit
DF-5722 / fix.diff
← back to finding ↓ download raw
--- a/sys/platform/pc64/x86_64/db_interface.c
+++ b/sys/platform/pc64/x86_64/db_interface.c
@@ -102,6 +102,7 @@ static jmp_buf	db_global_jmpbuf;
 static int	db_global_jmpbuf_valid;
+static int	db_saved_critcount;
 
 /*
  *  kdb_trap - field a TRACE or BPT trap
  */
 int
 kdb_trap(int type, int code, struct x86_64_saved_state *regs)
 {
 	volatile int ddb_mode = !(boothowto & RB_GDB);
@@ -158,7 +159,9 @@ kdb_trap(int type, int code, struct x86_64_saved_state *regs)
 	/*
 	 * XXX We really should switch to a local stack here.
 	 */
 	ddb_regs = *regs;
 
 	crit_enter();
+	db_saved_critcount = curthread->td_critcount;
 	db_printf("\nCPU%d stopping CPUs: 0x%08jx\n",
 		  mycpu->gd_cpuid,
 		  (uintmax_t)CPUMASK_LOWMASK(mycpu->gd_other_cpus));
@@ -198,7 +201,10 @@ kdb_trap(int type, int code, struct x86_64_saved_state *regs)
 		restart_cpus(stopped_cpus);
 	}
 
 	db_printf(" restarted\n");
-	crit_exit();
+	/*
+	 * Force-restore the interrupted context's critical section count:
+	 * debugger paths (polled console, IPI handling) can lose a count
+	 * when the session was entered from interrupt context, which
+	 * otherwise underflows here and panics with
+	 * "td_critcount is/would-go negative".
+	 */
+	curthread->td_critcount = db_saved_critcount;
 
 	regs->tf_rip    = ddb_regs.tf_rip;
```