git: ebf66b2a3b39 - stable/13 - bridge: Fix a potential memory leak in bridge_enqueue()

From: Mark Johnston <markj_at_FreeBSD.org>
Date: Mon, 19 Dec 2022 15:41:32 UTC
The branch stable/13 has been updated by markj:

URL: https://cgit.FreeBSD.org/src/commit/?id=ebf66b2a3b393bd060012c4684bbd525a5da745c

commit ebf66b2a3b393bd060012c4684bbd525a5da745c
Author:     Mark Johnston <markj@FreeBSD.org>
AuthorDate: 2022-12-11 16:40:12 +0000
Commit:     Mark Johnston <markj@FreeBSD.org>
CommitDate: 2022-12-19 14:56:46 +0000

    bridge: Fix a potential memory leak in bridge_enqueue()
    
    A comment at the beginning of the function notes that we may be
    transmitting multiple fragments as distinct packets.  So, the function
    loops over all fragments, transmitting each mbuf chain.  If if_transmit
    fails, we need to free all of the fragments, but m_freem() only frees an
    mbuf chain - it doesn't follow m_nextpkt.
    
    Change the error handler to free each untransmitted packet fragment, and
    count each fragment as a separate error since we increment OPACKETS once
    per fragment when transmission is successful.
    
    Reviewed by:    zlei, kp
    MFC after:      1 week
    Sponsored by:   Klara, Inc.
    Differential Revision:  https://reviews.freebsd.org/D37635
    
    (cherry picked from commit 51088797305c8aba43e8ded60b99eef5baa14071)
---
 sys/net/if_bridge.c | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/sys/net/if_bridge.c b/sys/net/if_bridge.c
index e644f1db55c2..0473245a1abd 100644
--- a/sys/net/if_bridge.c
+++ b/sys/net/if_bridge.c
@@ -2028,8 +2028,13 @@ bridge_enqueue(struct bridge_softc *sc, struct ifnet *dst_ifp, struct mbuf *m)
 
 		M_ASSERTPKTHDR(m); /* We shouldn't transmit mbuf without pkthdr */
 		if ((err = dst_ifp->if_transmit(dst_ifp, m))) {
-			m_freem(m0);
-			if_inc_counter(sc->sc_ifp, IFCOUNTER_OERRORS, 1);
+			int n;
+
+			for (m = m0, n = 1; m != NULL; m = m0, n++) {
+				m0 = m->m_nextpkt;
+				m_freem(m);
+			}
+			if_inc_counter(sc->sc_ifp, IFCOUNTER_OERRORS, n);
 			break;
 		}