DragonFlyBSD Kernel Audit
DF-0702 / fix.diff
← back to finding ↓ download raw
diff --git a/sys/net/ipfw3_basic/ip_fw3_sync.c b/sys/net/ipfw3_basic/ip_fw3_sync.c
--- a/sys/net/ipfw3_basic/ip_fw3_sync.c
+++ b/sys/net/ipfw3_basic/ip_fw3_sync.c
@@ -337,10 +337,20 @@
 
 	td = curthread->td_proc ? curthread : &thread0;
 	for (i = 0; i < fw3_sync_ctx.count; i++) {
+		/* DF-0702: so_pru_sosend consumes (frees) the mbuf on success; pass a
+		   per-iteration copy so the original survives the loop and is freed
+		   exactly once below (was: UAF on iter>=1 + double-free). */
+		struct mbuf *mc = m_copym(m, 0, M_COPYALL, M_NOWAIT);
+		if (mc == NULL) {
+			kprintf("ipfw3sync: centre sosend m_copym failed\n");
+			m_free(m);
+			return -1;
+		}
 		error = so_pru_sosend(fw3_sync_ctx.centre_socks[i],
-				NULL, NULL, m, NULL, 0 ,td);
+				NULL, NULL, mc, NULL, 0 ,td);
 		if (error) {
 			kprintf("ipfw3sync: centre sosend failed: %d\n", error);
+			m_free(m);
 			return -1;
 		}
 	}
@@ -456,13 +466,21 @@
 
 	td = curthread->td_proc ? curthread : &thread0;
 	for (i = 0; i < fw3_sync_ctx.count; i++) {
+		/* DF-0702: so_pru_sosend consumes the mbuf on success; pass a copy per
+		   iteration so the original survives (was: UAF on iter>=1). */
+		struct mbuf *mc = m_copym(m, 0, M_COPYALL, M_NOWAIT);
+		if (mc == NULL) {
+			kprintf("ipfw3sync: centre sosend m_copym failed\n");
+			break;
+		}
 		error = so_pru_sosend(fw3_sync_ctx.centre_socks[i],
-				NULL, NULL, m, NULL, 0 ,td);
+				NULL, NULL, mc, NULL, 0 ,td);
 		if (error) {
 			kprintf("ipfw3sync: centre sosend failed: %d\n", error);
-			return;
+			break;
 		}
 	}
+	m_free(m);
 	return;
 }