⬢ DragonFlyBSD Kernel Audit
DF-5732 / fix.diff
← back to finding ↓ download raw
diff --git a/sys/ddb/ddb.h b/sys/ddb/ddb.h
index 1111111..2222222 100644
--- a/sys/ddb/ddb.h
+++ b/sys/ddb/ddb.h
@@ -93,6 +93,12 @@ db_addr_t		db_disasm (db_addr_t loc, boolean_t altfmt, db_regs_t *regs);
 int		db_expression (db_expr_t *valuep);
 int		db_get_variable (db_expr_t *valuep);
 
+/*
+ * DDB no-fault guard (see sys/platform/pc64/x86_64/db_interface.c).
+ * Used by trap() to recover DDB memory probes quietly instead of
+ * routing them through trap_fatal().
+ */
+boolean_t	db_nofault_pending (void);
+void		db_nofault_take (void) __dead2;
diff --git a/sys/platform/pc64/x86_64/db_interface.c b/sys/platform/pc64/x86_64/db_interface.c
index 1111111..2222222 100644
--- a/sys/platform/pc64/x86_64/db_interface.c
+++ b/sys/platform/pc64/x86_64/db_interface.c
@@ -140,6 +140,22 @@ kdb_trap(int type, int code, struct trapframe *regs)
 	}
 }
 
+/*
+ * Accessors for trap(): let a fault covered by the DDB no-fault guard
+ * (db_read_bytes()/db_write_bytes() probing bad memory from a ddb
+ * command) recover QUIETLY via the guard's longjmp, instead of first
+ * running trap_fatal() (crash banner, register disclosure, leaked
+ * gd_trap_nesting_level, corrupted session-resume state).
+ */
+boolean_t
+db_nofault_pending(void)
+{
+	return (db_nofault != NULL);
+}
+
+void
+db_nofault_take(void)
+{
+	jmp_buf *no_fault = db_nofault;
+
+	db_nofault = NULL;
+	longjmp(*no_fault, 1);
+}
+
 /*
  * This handles unexpected traps in ddb commands, including calls to
  * non-ddb functions.  db_nofault only applies to memory accesses by
diff --git a/sys/platform/pc64/x86_64/trap.c b/sys/platform/pc64/x86_64/trap.c
index 1111111..2222222 100644
--- a/sys/platform/pc64/x86_64/trap.c
+++ b/sys/platform/pc64/x86_64/trap.c
@@ -413,8 +413,17 @@ trap(struct trapframe *frame)
 
 #ifdef DDB
         /*
-	 * We need to allow T_DNA faults when the debugger is active since
-	 * some dumping paths do large bcopy() which use the floating
-	 * point registers for faster copying.
+	 * If the faulting access is covered by DDB's db_nofault guard
+	 * (db_read_bytes()/db_write_bytes() probing bad memory from a ddb
+	 * command), take the guard's longjmp BEFORE anything else: running
+	 * trap_fatal() first turns a quietly-recoverable debugger probe into
+	 * a spurious crash banner, leaks gd_trap_nesting_level (the longjmp
+	 * skips the decrement below), and corrupts the session-resume path.
+	 */
+	if (db_active && frame->tf_trapno != T_DNA && db_nofault_pending())
+		db_nofault_take();
+
+	/*
+	 * We need to allow T_DNA faults when the debugger is active since
+	 * some dumping paths do large bcopy() which use the floating
+	 * point registers for faster copying.
 	 */
 	if (db_active && frame->tf_trapno != T_DNA) {
 		eva = (frame->tf_trapno == T_PAGEFLT ? frame->tf_addr : 0);
diff --git a/sys/platform/vkernel64/x86_64/db_interface.c b/sys/platform/vkernel64/x86_64/db_interface.c
index 1111111..2222222 100644
--- a/sys/platform/vkernel64/x86_64/db_interface.c
+++ b/sys/platform/vkernel64/x86_64/db_interface.c
@@ -140,6 +140,22 @@ kdb_trap(int type, int code, struct trapframe *regs)
 	}
 }
 
+boolean_t
+db_nofault_pending(void)
+{
+	return (db_nofault != NULL);
+}
+
+void
+db_nofault_take(void)
+{
+	jmp_buf *no_fault = db_nofault;
+
+	db_nofault = NULL;
+	longjmp(*no_fault, 1);
+}
+
 /*
  * This handles unexpected traps in ddb commands, including calls to
  * non-ddb functions.  db_nofault only applies to memory accesses by
diff --git a/sys/platform/vkernel64/x86_64/trap.c b/sys/platform/vkernel64/x86_64/trap.c
index 1111111..2222222 100644
--- a/sys/platform/vkernel64/x86_64/trap.c
+++ b/sys/platform/vkernel64/x86_64/trap.c
@@ -1,1 +1,1 @@
(apply the same db_nofault_pending()/db_nofault_take() pre-check in the
 vkernel64 trap() DDB funnel, mirroring pc64)