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; }