diff options
author | Stefan Sperling <stsp@cvs.openbsd.org> | 2017-07-21 13:14:42 +0000 |
---|---|---|
committer | Stefan Sperling <stsp@cvs.openbsd.org> | 2017-07-21 13:14:42 +0000 |
commit | 3b753cdc1adfab074a22774184373368b85d7789 (patch) | |
tree | f103537dd998f5a04ef5b14b8fc32aaeeff53e77 /sys/dev/usb/if_rsu.c | |
parent | ca022e3b984a1be96dbefdc758af30d6fe7fcb0e (diff) |
Fix frame length bounds checks in rsu(4).
Due to signedness issues the existing checks didn't work as intended.
Problem reported by Ilja Van Sprundel.
ok deraadt@
Diffstat (limited to 'sys/dev/usb/if_rsu.c')
-rw-r--r-- | sys/dev/usb/if_rsu.c | 21 |
1 files changed, 16 insertions, 5 deletions
diff --git a/sys/dev/usb/if_rsu.c b/sys/dev/usb/if_rsu.c index a88fab44bad..01ad9e569b7 100644 --- a/sys/dev/usb/if_rsu.c +++ b/sys/dev/usb/if_rsu.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_rsu.c,v 1.38 2017/03/26 15:31:15 deraadt Exp $ */ +/* $OpenBSD: if_rsu.c,v 1.39 2017/07/21 13:14:41 stsp Exp $ */ /*- * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr> @@ -1056,12 +1056,13 @@ rsu_event_survey(struct rsu_softc *sc, uint8_t *buf, int len) struct ieee80211_frame *wh; struct ndis_wlan_bssid_ex *bss; struct mbuf *m; - int pktlen; + uint32_t pktlen, ieslen; if (__predict_false(len < sizeof(*bss))) return; bss = (struct ndis_wlan_bssid_ex *)buf; - if (__predict_false(len < sizeof(*bss) + letoh32(bss->ieslen))) + ieslen = letoh32(bss->ieslen); + if (ieslen > len - sizeof(*bss)) return; DPRINTFN(2, ("found BSS %s: len=%d chan=%d inframode=%d " @@ -1071,7 +1072,7 @@ rsu_event_survey(struct rsu_softc *sc, uint8_t *buf, int len) letoh32(bss->networktype), letoh32(bss->privacy))); /* Build a fake beacon frame to let net80211 do all the parsing. */ - pktlen = sizeof(*wh) + letoh32(bss->ieslen); + pktlen = sizeof(*wh) + ieslen; if (__predict_false(pktlen > MCLBYTES)) return; MGETHDR(m, M_DONTWAIT, MT_DATA); @@ -1093,7 +1094,7 @@ rsu_event_survey(struct rsu_softc *sc, uint8_t *buf, int len) IEEE80211_ADDR_COPY(wh->i_addr2, bss->macaddr); IEEE80211_ADDR_COPY(wh->i_addr3, bss->macaddr); *(uint16_t *)wh->i_seq = 0; - memcpy(&wh[1], (uint8_t *)&bss[1], letoh32(bss->ieslen)); + memcpy(&wh[1], (uint8_t *)&bss[1], ieslen); /* Finalize mbuf. */ m->m_pkthdr.len = m->m_len = pktlen; @@ -1207,6 +1208,8 @@ rsu_rx_multi_event(struct rsu_softc *sc, uint8_t *buf, int len) cmdsz = letoh16(cmd->len); if (__predict_false(len < sizeof(*cmd) + cmdsz)) break; + if (cmdsz > len) + break; /* Process firmware event. */ rsu_rx_event(sc, cmd->code, (uint8_t *)&cmd[1], cmdsz); @@ -1402,6 +1405,7 @@ rsu_rxeof(struct usbd_xfer *xfer, void *priv, usbd_status status) struct rsu_rx_data *data = priv; struct rsu_softc *sc = data->sc; struct r92s_rx_stat *stat; + struct ifnet *ifp = &sc->sc_ic.ic_if; int len; if (__predict_false(status != USBD_NORMAL_COMPLETION)) { @@ -1416,8 +1420,15 @@ rsu_rxeof(struct usbd_xfer *xfer, void *priv, usbd_status status) if (__predict_false(len < sizeof(*stat))) { DPRINTF(("xfer too short %d\n", len)); + ifp->if_ierrors++; + goto resubmit; + } + if (len > RSU_RXBUFSZ) { + DPRINTF(("xfer too large %d\n", len)); + ifp->if_ierrors++; goto resubmit; } + /* Determine if it is a firmware C2H event or an 802.11 frame. */ stat = (struct r92s_rx_stat *)data->buf; if ((letoh32(stat->rxdw1) & 0x1ff) == 0x1ff) |