diff options
author | Stefan Sperling <stsp@cvs.openbsd.org> | 2017-08-12 14:07:34 +0000 |
---|---|---|
committer | Stefan Sperling <stsp@cvs.openbsd.org> | 2017-08-12 14:07:34 +0000 |
commit | 66e99b0a29bb44203a4c09e32e7a9e0ce9decb96 (patch) | |
tree | 617d09b087dd67aacc14e54ab4feef3c47dd2eb3 | |
parent | f89d333c234ee914febf2481df997dd9112dbf85 (diff) |
Fix Coverity CID 1453280:
iwm(4) firmware could cause an out of bounds read of the ic->ic_channels
array by lying about the channel a frame was received on. This array index
is now properly bounds-checked. Not an errata-worthy fix, since the firmware
has full DMA access anyway.
While here, I noticed another problem: Stop assigning a firmware-derived value
to ni->ni_chan. The Rx interrupt handler has no business tweaking that pointer.
ok mpi@
-rw-r--r-- | sys/dev/pci/if_iwm.c | 19 |
1 files changed, 9 insertions, 10 deletions
diff --git a/sys/dev/pci/if_iwm.c b/sys/dev/pci/if_iwm.c index 7dc3a4564c0..ea2dc3b203b 100644 --- a/sys/dev/pci/if_iwm.c +++ b/sys/dev/pci/if_iwm.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_iwm.c,v 1.204 2017/07/23 13:51:11 stsp Exp $ */ +/* $OpenBSD: if_iwm.c,v 1.205 2017/08/12 14:07:33 stsp Exp $ */ /* * Copyright (c) 2014, 2016 genua gmbh <info@genua.de> @@ -3340,7 +3340,6 @@ iwm_rx_rx_mpdu(struct iwm_softc *sc, struct iwm_rx_packet *pkt, struct ieee80211com *ic = &sc->sc_ic; struct ieee80211_frame *wh; struct ieee80211_node *ni; - struct ieee80211_channel *c = NULL; struct ieee80211_rxinfo rxi; struct mbuf *m; struct iwm_rx_phy_info *phy_info; @@ -3348,7 +3347,7 @@ iwm_rx_rx_mpdu(struct iwm_softc *sc, struct iwm_rx_packet *pkt, int device_timestamp; uint32_t len; uint32_t rx_pkt_status; - int rssi; + int rssi, chanidx; bus_dmamap_sync(sc->sc_dmat, data->map, 0, IWM_RBUF_SIZE, BUS_DMASYNC_POSTREAD); @@ -3393,15 +3392,15 @@ iwm_rx_rx_mpdu(struct iwm_softc *sc, struct iwm_rx_packet *pkt, if (iwm_rx_addbuf(sc, IWM_RBUF_SIZE, sc->rxq.cur) != 0) return; - if (le32toh(phy_info->channel) < nitems(ic->ic_channels)) - c = &ic->ic_channels[le32toh(phy_info->channel)]; + ni = ieee80211_find_rxnode(ic, wh); + + chanidx = phy_info->channel; + if (chanidx < 0 || chanidx >= nitems(ic->ic_channels)) + chanidx = ieee80211_chan2ieee(ic, ni->ni_chan); memset(&rxi, 0, sizeof(rxi)); rxi.rxi_rssi = rssi; rxi.rxi_tstamp = device_timestamp; - ni = ieee80211_find_rxnode(ic, wh); - if (c) - ni->ni_chan = c; #if NBPFILTER > 0 if (sc->sc_drvbpf != NULL) { @@ -3413,8 +3412,8 @@ iwm_rx_rx_mpdu(struct iwm_softc *sc, struct iwm_rx_packet *pkt, if (phy_info->phy_flags & htole16(IWM_PHY_INFO_FLAG_SHPREAMBLE)) tap->wr_flags |= IEEE80211_RADIOTAP_F_SHORTPRE; tap->wr_chan_freq = - htole16(ic->ic_channels[phy_info->channel].ic_freq); - chan_flags = ic->ic_channels[phy_info->channel].ic_flags; + htole16(ic->ic_channels[chanidx].ic_freq); + chan_flags = ic->ic_channels[chanidx].ic_flags; if (ic->ic_curmode != IEEE80211_MODE_11N) chan_flags &= ~IEEE80211_CHAN_HT; tap->wr_chan_flags = htole16(chan_flags); |