⬢ DragonFlyBSD Kernel Audit
DF-2709 / fix.diff
← back to finding ↓ download raw
--- sys/kern/kern_dmsg.c	2026-06-29 12:51:19.000000000 +0000
+++ /tmp/opencode/v26/fixtree/sys/kern/kern_dmsg.c	2026-10-24 16:53:55.813821054 +0000
@@ -92,8 +92,7 @@
 #define kdmsg_state_hold(state)	_kdmsg_state_hold(state)
 #define kdmsg_state_drop(state)	_kdmsg_state_drop(state)
 #endif
-static void _kdmsg_state_hold(kdmsg_state_t *state KDMSG_DEBUG_ARGS);
-static void _kdmsg_state_drop(kdmsg_state_t *state KDMSG_DEBUG_ARGS);
+/* DF-2709: prototypes now in <sys/dmsg.h> (exported for hammer2) */
 
 static void kdmsg_iocom_thread_rd(void *arg);
 static void kdmsg_iocom_thread_wr(void *arg);
@@ -227,10 +226,15 @@
 	    (msg->any.head.cmd & DMSGF_DELETE)) {
 		/*
 		 * iocom->conn_state has a state ref, drop it when clearing.
+		 *
+		 * DF-2709: conn_state is shared with hammer2_volconf_update()
+		 * and other readers; interlock the drop with msglk.
 		 */
+		lockmgr(&iocom->msglk, LK_EXCLUSIVE);
 		if (iocom->conn_state)
 			kdmsg_state_drop(iocom->conn_state);
 		iocom->conn_state = NULL;
+		lockmgr(&iocom->msglk, LK_RELEASE);
 		kdmsg_msg_reply(msg, 0);
 	}
 
@@ -901,6 +905,16 @@
 		msg->state = state;		/* inherits freerd ref */
 		state->parent = pstate;
 		KKASSERT(state->iocom == iocom);
+		/*
+		 * DF-2711: cap the number of transactions a peer may
+		 * have open; without a quota a peer can pin unbounded
+		 * kernel memory (~160 bytes per state).
+		 */
+		if (iocom->peer_states >= KDMSG_MAX_PEER_STATES) {
+			error = DMSG_ERR_LOSTLINK;
+			break;
+		}
+		++iocom->peer_states;
 		state->flags |= KDMSG_STATE_RBINSERTED |
 				KDMSG_STATE_SUBINSERTED |
 			        KDMSG_STATE_OPPOSITE;
@@ -1727,7 +1741,6 @@
 	kdmsg_state_drop(state);
 }
 
-static
 void
 _kdmsg_state_hold(kdmsg_state_t *state KDMSG_DEBUG_ARGS)
 {
@@ -1737,7 +1750,6 @@
 #endif
 }
 
-static
 void
 _kdmsg_state_drop(kdmsg_state_t *state KDMSG_DEBUG_ARGS)
 {
@@ -1759,8 +1771,11 @@
 	KKASSERT((state->flags & KDMSG_STATE_SUBINSERTED) == 0);
 	KKASSERT(TAILQ_EMPTY(&state->subq));
 
-	if (state != &state->iocom->state0)
+	if (state != &state->iocom->state0) {
+		if (state->flags & KDMSG_STATE_OPPOSITE)	/* DF-2711 */
+			--state->iocom->peer_states;
 		kfree(state, iocom->mmsg);
+	}
 }
 
 kdmsg_msg_t *
--- sys/vfs/hammer2/hammer2_iocom.c	2026-06-29 12:51:19.000000000 +0000
+++ /tmp/opencode/v26/fixtree/sys/vfs/hammer2/hammer2_iocom.c	2026-10-24 16:46:16.983664688 +0000
@@ -371,17 +371,26 @@
 hammer2_volconf_update(hammer2_dev_t *hmp, int index)
 {
 	kdmsg_msg_t *msg;
+	kdmsg_state_t *state;
 
-	/* XXX interlock against connection state termination */
-	kprintf("volconf update %p\n", hmp->iocom.conn_state);
-	if (hmp->iocom.conn_state) {
-		kprintf("TRANSMIT VOLCONF VIA OPEN CONN TRANSACTION\n");
-		msg = kdmsg_msg_alloc(hmp->iocom.conn_state,
+	/*
+	 * DF-2709: interlock against connection state termination.
+	 * Take a state reference under msglk so the peer-driven
+	 * kdmsg_lnk_conn_reply drop cannot free it out from under us.
+	 */
+	lockmgr(&hmp->iocom.msglk, LK_EXCLUSIVE);
+	state = hmp->iocom.conn_state;
+	if (state)
+		_kdmsg_state_hold(state);
+	lockmgr(&hmp->iocom.msglk, LK_RELEASE);
+	if (state) {
+		msg = kdmsg_msg_alloc(state,
 				      DMSG_LNK_HAMMER2_VOLCONF,
 				      NULL, NULL);
 		H2_LNK_VOLCONF(msg)->copy = hmp->voldata.copyinfo[index];
 		H2_LNK_VOLCONF(msg)->mediaid = hmp->voldata.fsid;
 		H2_LNK_VOLCONF(msg)->index = index;
 		kdmsg_msg_write(msg);
+		_kdmsg_state_drop(state);
 	}
 }