⬢ DragonFlyBSD Kernel Audit
DF-5587 / fix.diff
← back to finding ↓ download raw
--- a/sys/platform/vkernel64/x86_64/exception.c
+++ b/sys/platform/vkernel64/x86_64/exception.c
@@ -58,6 +58,8 @@
 int _ucodesel = GSEL(GUCODE_SEL, SEL_UPL);
 int _udatasel = GSEL(GUDATA_SEL, SEL_UPL);
 
+static int exc_nesting;	/* exc_segfault re-entrancy guard */
+
 static void exc_segfault(int signo, siginfo_t *info, void *ctx);
 #ifdef DDB
 static void exc_debugger(int signo, siginfo_t *info, void *ctx);
@@ -266,7 +268,26 @@
 	int save;
 
 	save = errno;
+	if (atomic_fetchadd_int(&exc_nesting, 1) != 0) {
+		/*
+		 * Fault inside the fault path (e.g. a cothread, which runs
+		 * with %gs == 0, 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);
+		signal(SIGSEGV, SIG_DFL);
+		signal(SIGBUS, SIG_DFL);
+		signal(SIGTRAP, SIG_DFL);
+		signal(SIGFPE, SIG_DFL);
+		raise(signo);
+		/* NOT REACHED */
+	}
 	kern_trap((struct trapframe *)&ctx->uc_mcontext.mc_rdi);
+	atomic_subtract_int(&exc_nesting, 1);
 	splz();
 	errno = save;
 }