⬢ DragonFlyBSD Kernel Audit
DF-3882 / fix.diff
← back to finding ↓ download raw
--- a/sys/dev/drm/drm_dp_mst_topology.c	2026-09-16 21:03:55.846742995 +0000
+++ b/sys/dev/drm/drm_dp_mst_topology.c	2026-09-16 21:04:11.754541465 +0000
@@ -2320,6 +2355,7 @@
 	if (mgr->down_rep_recv.have_eomt) {
 		struct drm_dp_sideband_msg_tx *txmsg;
 		struct drm_dp_mst_branch *mstb;
+		struct drm_dp_sideband_msg_reply_body reply;
 		int slot = -1;
 		mstb = drm_dp_get_mst_branch_device(mgr,
 						    mgr->down_rep_recv.initial_hdr.lct,
@@ -2350,19 +2386,33 @@
 			return 0;
 		}
 
-		drm_dp_sideband_parse_reply(&mgr->down_rep_recv, &txmsg->reply);
-		if (txmsg->reply.reply_type == 1) {
-			DRM_DEBUG_KMS("Got NAK reply: req 0x%02x, reason 0x%02x, nak data 0x%02x\n", txmsg->reply.req_type, txmsg->reply.u.nak.reason, txmsg->reply.u.nak.nak_data);
+		/*
+		 * Parse into a local body: the sender can time out in
+		 * drm_dp_mst_wait_tx_reply() and kfree(txmsg) while we are
+		 * outside qlock.  txmsg is only written below, after slot
+		 * ownership has been re-validated under qlock.
+		 */
+		drm_dp_sideband_parse_reply(&mgr->down_rep_recv, &reply);
+		if (reply.reply_type == 1) {
+			DRM_DEBUG_KMS("Got NAK reply: req 0x%02x, reason 0x%02x, nak data 0x%02x\n", reply.req_type, reply.u.nak.reason, reply.u.nak.nak_data);
 		}
 
 		memset(&mgr->down_rep_recv, 0, sizeof(struct drm_dp_sideband_msg_rx));
-		drm_dp_put_mst_branch_device(mstb);
 
 		mutex_lock(&mgr->qlock);
-		txmsg->state = DRM_DP_SIDEBAND_TX_RX;
-		mstb->tx_slots[slot] = NULL;
+		if (mstb->tx_slots[slot] == txmsg) {
+			/* sender has not taken the timeout path yet */
+			txmsg->reply = reply;
+			txmsg->state = DRM_DP_SIDEBAND_TX_RX;
+			mstb->tx_slots[slot] = NULL;
+		} else {
+			DRM_DEBUG_KMS("reply raced with tx timeout, dropped\n");
+		}
 		mutex_unlock(&mgr->qlock);
 
+		/* mstb reference held until after its last use above */
+		drm_dp_put_mst_branch_device(mstb);
+
 		wake_up_all(&mgr->tx_waitq);
 	}
 	return ret;