DF-1122 / fix.diff
diff --git a/sys/dev/netif/iwn/if_iwn.c b/sys/dev/netif/iwn/if_iwn.c --- a/sys/dev/netif/iwn/if_iwn.c +++ b/sys/dev/netif/iwn/if_iwn.c @@ -3264,8 +3264,30 @@ bus_dmamap_sync(sc->rxq.data_dmat, data->map, BUS_DMASYNC_POSTREAD); qid = le16toh(ba->qid); - txq = &sc->txq[ba->qid]; - tap = sc->qid2tap[ba->qid]; + /* + * The firmware supplies the queue id in the Compressed BlockAck + * notification. Bounds-check it against sc->ntxqs (the size of both + * sc->txq[] and sc->qid2tap[], which are IWN*_NTXQUEUES entries) and + * use the byte-swapped `qid` consistently -- the old code indexed the + * arrays with the RAW ba->qid and dereferenced tap without a NULL + * check, so a notification with qid>=ntxqs was an OOB array read and a + * notification for a TID whose aggregation was torn down (qid2tap[] + * NULLed by iwn_ampdu_tx_stop) was a NULL-deref panic. + */ + if (qid >= sc->ntxqs) { + DPRINTF(sc, IWN_DEBUG_XMIT, + "%s: compressed_ba qid %d out of range (ntxqs %d)\n", + __func__, qid, sc->ntxqs); + return; + } + txq = &sc->txq[qid]; + tap = sc->qid2tap[qid]; + if (tap == NULL) { + DPRINTF(sc, IWN_DEBUG_XMIT, + "%s: compressed_ba qid %d has no aggregate tap\n", + __func__, qid); + return; + } tid = tap->txa_tid; wn = (void *)tap->txa_ni; |