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)