svn commit: r341990 - head/sys/dev/bwn

Mark Johnston markj at FreeBSD.org
Wed Dec 12 15:49:15 UTC 2018


Author: markj
Date: Wed Dec 12 15:49:14 2018
New Revision: 341990
URL: https://svnweb.freebsd.org/changeset/base/341990

Log:
  Fix a possible mbuf double free in bwn_dma_tx_start().
  
  If bus_dmamap_load_mbuf() fails following a defrag, the caller of
  bwn_dma_tx_start() would free the original mbuf after m_defrag() had
  already done so.  Fix this by returning the defragged mbuf to the
  caller instead.  Update bwn_pio_tx_start() similarly for consistency.
  
  Reported by:	Ilja Van Sprundel <ivansprundel at ioactive.com>
  Reviewed by:	landonf
  Tested by:	landonf
  MFC after:	3 days
  admbug:		820
  Sponsored by:	The FreeBSD Foundation
  Differential Revision:	https://reviews.freebsd.org/D18342

Modified:
  head/sys/dev/bwn/if_bwn.c

Modified: head/sys/dev/bwn/if_bwn.c
==============================================================================
--- head/sys/dev/bwn/if_bwn.c	Wed Dec 12 15:23:40 2018	(r341989)
+++ head/sys/dev/bwn/if_bwn.c	Wed Dec 12 15:49:14 2018	(r341990)
@@ -209,7 +209,7 @@ static void	bwn_pio_rx_write_2(struct bwn_pio_rxqueue 
 static void	bwn_pio_rx_write_4(struct bwn_pio_rxqueue *, uint16_t,
 		    uint32_t);
 static int	bwn_pio_tx_start(struct bwn_mac *, struct ieee80211_node *,
-		    struct mbuf *);
+		    struct mbuf **);
 static struct bwn_pio_txqueue *bwn_pio_select(struct bwn_mac *, uint8_t);
 static uint32_t	bwn_pio_write_multi_4(struct bwn_mac *,
 		    struct bwn_pio_txqueue *, uint32_t, const void *, int);
@@ -273,7 +273,7 @@ static void	bwn_ratectl_tx_complete(const struct ieee8
 static void	bwn_dma_handle_txeof(struct bwn_mac *,
 		    const struct bwn_txstatus *);
 static int	bwn_dma_tx_start(struct bwn_mac *, struct ieee80211_node *,
-		    struct mbuf *);
+		    struct mbuf **);
 static int	bwn_dma_getslot(struct bwn_dma_ring *);
 static struct bwn_dma_ring *bwn_dma_select(struct bwn_mac *,
 		    uint8_t);
@@ -1068,7 +1068,7 @@ bwn_tx_start(struct bwn_softc *sc, struct ieee80211_no
 	}
 
 	error = (mac->mac_flags & BWN_MAC_FLAG_DMA) ?
-	    bwn_dma_tx_start(mac, ni, m) : bwn_pio_tx_start(mac, ni, m);
+	    bwn_dma_tx_start(mac, ni, &m) : bwn_pio_tx_start(mac, ni, &m);
 	if (error) {
 		m_freem(m);
 		return (error);
@@ -1077,13 +1077,14 @@ bwn_tx_start(struct bwn_softc *sc, struct ieee80211_no
 }
 
 static int
-bwn_pio_tx_start(struct bwn_mac *mac, struct ieee80211_node *ni, struct mbuf *m)
+bwn_pio_tx_start(struct bwn_mac *mac, struct ieee80211_node *ni,
+    struct mbuf **mp)
 {
 	struct bwn_pio_txpkt *tp;
-	struct bwn_pio_txqueue *tq = bwn_pio_select(mac, M_WME_GETAC(m));
+	struct bwn_pio_txqueue *tq;
 	struct bwn_softc *sc = mac->mac_sc;
 	struct bwn_txhdr txhdr;
-	struct mbuf *m_new;
+	struct mbuf *m, *m_new;
 	uint32_t ctl32;
 	int error;
 	uint16_t ctl16;
@@ -1092,6 +1093,8 @@ bwn_pio_tx_start(struct bwn_mac *mac, struct ieee80211
 
 	/* XXX TODO send packets after DTIM */
 
+	m = *mp;
+	tq = bwn_pio_select(mac, M_WME_GETAC(m));
 	KASSERT(!TAILQ_EMPTY(&tq->tq_pktlist), ("%s: fail", __func__));
 	tp = TAILQ_FIRST(&tq->tq_pktlist);
 	tp->tp_ni = ni;
@@ -1111,13 +1114,14 @@ bwn_pio_tx_start(struct bwn_mac *mac, struct ieee80211
 		/*
 		 * XXX please removes m_defrag(9)
 		 */
-		m_new = m_defrag(m, M_NOWAIT);
+		m_new = m_defrag(*mp, M_NOWAIT);
 		if (m_new == NULL) {
 			device_printf(sc->sc_dev,
 			    "%s: can't defrag TX buffer\n",
 			    __func__);
 			return (ENOBUFS);
 		}
+		*mp = m_new;
 		if (m_new->m_next != NULL)
 			device_printf(sc->sc_dev,
 			    "TODO: fragmented packets for PIO\n");
@@ -1168,15 +1172,17 @@ bwn_pio_select(struct bwn_mac *mac, uint8_t prio)
 }
 
 static int
-bwn_dma_tx_start(struct bwn_mac *mac, struct ieee80211_node *ni, struct mbuf *m)
+bwn_dma_tx_start(struct bwn_mac *mac, struct ieee80211_node *ni,
+    struct mbuf **mp)
 {
 #define	BWN_GET_TXHDRCACHE(slot)					\
 	&(txhdr_cache[(slot / BWN_TX_SLOTS_PER_FRAME) * BWN_HDRSIZE(mac)])
 	struct bwn_dma *dma = &mac->mac_method.dma;
-	struct bwn_dma_ring *dr = bwn_dma_select(mac, M_WME_GETAC(m));
+	struct bwn_dma_ring *dr = bwn_dma_select(mac, M_WME_GETAC(*mp));
 	struct bwn_dmadesc_generic *desc;
 	struct bwn_dmadesc_meta *mt;
 	struct bwn_softc *sc = mac->mac_sc;
+	struct mbuf *m;
 	uint8_t *txhdr_cache = (uint8_t *)dr->dr_txhdr_cache;
 	int error, slot, backup[2] = { dr->dr_curslot, dr->dr_usedslot };
 
@@ -1185,6 +1191,7 @@ bwn_dma_tx_start(struct bwn_mac *mac, struct ieee80211
 
 	/* XXX send after DTIM */
 
+	m = *mp;
 	slot = bwn_dma_getslot(dr);
 	dr->getdesc(dr, slot, &desc, &mt);
 	KASSERT(mt->mt_txtype == BWN_DMADESC_METATYPE_HEADER,
@@ -1233,9 +1240,8 @@ bwn_dma_tx_start(struct bwn_mac *mac, struct ieee80211
 			    __func__);
 			error = ENOBUFS;
 			goto fail;
-		} else {
-			m = m_new;
 		}
+		*mp = m = m_new;
 
 		mt->mt_m = m;
 		error = bus_dmamap_load_mbuf(dma->txbuf_dtag, mt->mt_dmap,


More information about the svn-src-head mailing list