--- a/sys/dev/netif/sf/if_sf.c +++ b/sys/dev/netif/sf/if_sf.c @@ -992,6 +992,7 @@ sf_txeof(struct sf_softc *sc) int txcons, cmpprodidx, cmpconsidx; struct sf_tx_cmpdesc_type1 *cur_cmp; struct sf_tx_bufdesc_type0 *cur_tx; + int idx; struct ifnet *ifp; ifp = &sc->arpcom.ac_if; @@ -1002,10 +1003,19 @@ sf_txeof(struct sf_softc *sc) while (cmpconsidx != cmpprodidx) { cur_cmp = &sc->sf_ldata->sf_tx_clist[cmpconsidx]; - cur_tx = &sc->sf_ldata->sf_tx_dlist[cur_cmp->sf_index >> 7]; + + /* + * The completion descriptor's sf_index is a 15-bit + * byte offset DMA-written by the NIC; >> 7 it must + * index the 128-entry TX descriptor ring. A NIC that + * supplies an offset >= SF_TX_DLIST_SIZE (16384) would + * otherwise index far past the ring, feeding an OOB + * "mbuf pointer" to m_freem() and underflowing + * sf_tx_cnt. Reject and resync instead. + */ + idx = cur_cmp->sf_index >> 7; + if (idx >= SF_TX_DLIST_CNT) { + kprintf("sf%d: bogus TX completion index %d, " + "resetting\n", sc->sf_unit, idx); + ifp->if_flags &= ~IFF_RUNNING; + sf_init(sc); + return; + } + cur_tx = &sc->sf_ldata->sf_tx_dlist[idx]; if (cur_cmp->sf_txstat & SF_TXSTAT_TX_OK) IFNET_STAT_INC(ifp, opackets, 1);