git: 22ddc9eb1d7a - main - fwip: Fix M_PKTHDR loss in fwip_async_output broadcast path

From: Adrian Chadd <adrian_at_FreeBSD.org>
Date: Sun, 05 Jul 2026 18:34:14 UTC
The branch main has been updated by adrian:

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

commit 22ddc9eb1d7a4fffe78b0692bdc4ec03e1d04ac4
Author:     Abdelkader Boudih <freebsd@seuros.com>
AuthorDate: 2026-07-05 18:26:05 +0000
Commit:     Adrian Chadd <adrian@FreeBSD.org>
CommitDate: 2026-07-05 18:34:02 +0000

    fwip: Fix M_PKTHDR loss in fwip_async_output broadcast path
    
    M_PREPEND in the broadcast branch may call m_prepend(9) which allocates
    a new head mbuf and calls m_move_pkthdr(), stripping M_PKTHDR from the
    old mbuf.
    
    xfer->mbuf was set before M_PREPEND, so it pointed at the
    deheadered old mbuf. bus_dmamap_load_mbuf(9) asserts M_PKTHDR and
    panics.
    
    Reviewed by:    zlei, adrian
    Differential Revision:  https://reviews.freebsd.org/D57495
---
 sys/dev/firewire/if_fwip.c | 22 +++++++++++++++-------
 1 file changed, 15 insertions(+), 7 deletions(-)

diff --git a/sys/dev/firewire/if_fwip.c b/sys/dev/firewire/if_fwip.c
index 0f37ce6a8e41..bdbe76e2caf4 100644
--- a/sys/dev/firewire/if_fwip.c
+++ b/sys/dev/firewire/if_fwip.c
@@ -539,13 +539,6 @@ fwip_async_output(struct fwip_softc *fwip, if_t ifp)
 		 * it adds the link-level encapsulation.
 		 */
 
-		/*
-		 * Put the mbuf in the xfer early in case we hit an
-		 * error case below - fwip_output_callback will free
-		 * the mbuf.
-		 */
-		xfer->mbuf = m;
-
 		/*
 		 * We use the arp result (if any) to add a suitable firewire
 		 * packet header before handing off to the bus.
@@ -561,7 +554,18 @@ fwip_async_output(struct fwip_softc *fwip, if_t ifp)
 			 */
 			uint32_t *p;
 
+			/*
+			 * M_PREPEND may move M_PKTHDR to a new head mbuf.
+			 * Keep xfer->mbuf NULL until it succeeds.
+			 */
+			xfer->mbuf = NULL;
 			M_PREPEND(m, 2*sizeof(uint32_t), M_NOWAIT);
+			if (m == NULL) {
+				if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
+				fwip_output_callback(xfer);
+				continue;
+			}
+			xfer->mbuf = m;
 			p = mtod(m, uint32_t *);
 			fp->mode.stream.len = m->m_pkthdr.len;
 			fp->mode.stream.chtag = broadcast_channel;
@@ -584,6 +588,10 @@ fwip_async_output(struct fwip_softc *fwip, if_t ifp)
 			struct fw_device *fd;
 			struct fw_eui64 eui;
 
+			/*
+			 * Error paths below let the callback free m.
+			 */
+			xfer->mbuf = m;
 			eui.hi = ntohl(destfw->sender_unique_ID_hi);
 			eui.lo = ntohl(destfw->sender_unique_ID_lo);
 			if (fwip->last_dest.hi != eui.hi ||