⬢ DragonFlyBSD Kernel Audit
DF-5607 / fix.diff
← back to finding ↓ download raw
--- a/sys/platform/vkernel64/x86_64/exception.c	2026-10-08 15:08:18.200358517 +0000
+++ b/sys/platform/vkernel64/x86_64/exception.c	2026-10-08 15:08:26.636249987 +0000
@@ -58,6 +58,9 @@
 int _ucodesel = GSEL(GUCODE_SEL, SEL_UPL);
 int _udatasel = GSEL(GUDATA_SEL, SEL_UPL);
 
+/* per-pthread re-entrancy guard (cothreads run with %gs == 0) */
+static __thread int exc_nesting;
+
 static void exc_segfault(int signo, siginfo_t *info, void *ctx);
 #ifdef DDB
 static void exc_debugger(int signo, siginfo_t *info, void *ctx);
@@ -263,12 +266,39 @@
 exc_segfault(int signo, siginfo_t *info, void *ctxp)
 {
 	ucontext_t *ctx = ctxp;
+	struct sigaction sa;
+	sigset_t ss;
 	int save;
 
+	if (exc_nesting) {
+		/*
+		 * Fault inside the fault path (e.g. a cothread, which
+		 * runs with %gs == 0 per tls_set_gs(0), cothread.c:149,
+		 * faulting on kern_trap's mycpu load).  SA_NODEFER +
+		 * empty sa_mask would recurse until the host kills us
+		 * with no diagnostic; die honestly instead.
+		 */
+		static char msg[] =
+		    "vkernel: recursive fault in exc_segfault\n";
+
+		write(2, msg, sizeof(msg) - 1);
+		bzero(&sa, sizeof(sa));
+		sigemptyset(&sa.sa_mask);
+		sa.sa_handler = SIG_DFL;
+		sigaction(signo, &sa, NULL);
+		sigemptyset(&ss);
+		sigaddset(&ss, signo);
+		sigprocmask(SIG_UNBLOCK, &ss, NULL);
+		raise(signo);
+		/* NOT REACHED */
+		_exit(127);
+	}
+	exc_nesting = 1;
 	save = errno;
 	kern_trap((struct trapframe *)&ctx->uc_mcontext.mc_rdi);
 	splz();
 	errno = save;
+	exc_nesting = 0;
 }
 
 #ifdef DDB