Page MenuHomeFreeBSD

D11785.diff
No OneTemporary

D11785.diff

Index: sys/dev/usb/wlan/if_upgt.c
===================================================================
--- sys/dev/usb/wlan/if_upgt.c
+++ sys/dev/usb/wlan/if_upgt.c
@@ -118,7 +118,7 @@
static struct mbuf *
upgt_rxeof(struct usb_xfer *, struct upgt_data *, int *);
static struct mbuf *
- upgt_rx(struct upgt_softc *, uint8_t *, int, int *);
+ upgt_rx(struct upgt_softc *, uint8_t *, uint16_t, int *);
static void upgt_txeof(struct usb_xfer *, struct upgt_data *);
static int upgt_eeprom_read(struct upgt_softc *);
static int upgt_eeprom_parse(struct upgt_softc *);
@@ -306,7 +306,9 @@
DPRINTF(sc, UPGT_DEBUG_FW, "memory address rx start=0x%08x\n",
sc->sc_memaddr_rx_start);
- upgt_mem_init(sc);
+ error = upgt_mem_init(sc);
+ if (error)
+ goto fail4;
/* Load the firmware. */
error = upgt_fw_load(sc);
@@ -1043,7 +1045,7 @@
struct ieee80211com *ic = &sc->sc_ic;
struct upgt_eeprom_header *eeprom_header;
struct upgt_eeprom_option *eeprom_option;
- uint16_t option_len;
+ uint32_t option_len;
uint16_t option_type;
uint16_t preamble_len;
int option_end = 0;
@@ -1058,7 +1060,9 @@
/* sanity check */
if (eeprom_option >= (struct upgt_eeprom_option *)
- (sc->sc_eeprom + UPGT_EEPROM_SIZE)) {
+ (sc->sc_eeprom + UPGT_EEPROM_SIZE) ||
+ eeprom_option < (struct upgt_eeprom_option *)
+ sc->sc_eeprom) {
return (EINVAL);
}
@@ -1345,7 +1349,7 @@
struct upgt_lmac_header *header;
struct upgt_lmac_eeprom *eeprom;
uint8_t h1_type;
- uint16_t h2_type;
+ uint16_t h2_type, pkglen;
int actlen, sumlen;
usbd_xfer_status(xfer, &actlen, &sumlen, NULL, NULL);
@@ -1378,13 +1382,22 @@
eeprom = (struct upgt_lmac_eeprom *)(data->buf + 4);
uint16_t eeprom_offset = le16toh(eeprom->offset);
uint16_t eeprom_len = le16toh(eeprom->len);
+ int buf_offset = sizeof(struct upgt_lmac_eeprom) + 4;
+ if (eeprom_len > actlen - buf_offset ||
+ eeprom_len > sizeof(sc->sc_eeprom) - eeprom_offset) {
+ device_printf(sc->sc_dev,
+ "%s: wrong eeprom length (%u) / offset (%u)!\n",
+ __func__, eeprom_len, eeprom_offset);
+ return (NULL);
+ }
+
DPRINTF(sc, UPGT_DEBUG_FW,
"received EEPROM block (offset=%d, len=%d)\n",
eeprom_offset, eeprom_len);
memcpy(sc->sc_eeprom + eeprom_offset,
- data->buf + sizeof(struct upgt_lmac_eeprom) + 4,
+ data->buf + buf_offset,
eeprom_len);
/* EEPROM data has arrived in time, wakeup. */
@@ -1398,8 +1411,16 @@
h1_type == UPGT_H1_TYPE_RX_DATA_MGMT) {
DPRINTF(sc, UPGT_DEBUG_RECV, "%s: received 802.11 RX data\n",
__func__);
- m = upgt_rx(sc, data->buf + 4, le16toh(header->header1.len),
- rssi);
+
+ pkglen = le16toh(header->header1.len);
+ if (actlen - 4 < pkglen) {
+ device_printf(sc->sc_dev,
+ "%s: actlen - 4 (%d) < pkglen (%d)!\n",
+ __func__, actlen - 4, pkglen);
+ return (NULL);
+ }
+
+ m = upgt_rx(sc, data->buf + 4, pkglen, rssi);
} else if (h1_type == UPGT_H1_TYPE_CTRL &&
h2_type == UPGT_H2_TYPE_STATS) {
DPRINTF(sc, UPGT_DEBUG_STAT, "%s: received statistic data\n",
@@ -1433,7 +1454,7 @@
}
static struct mbuf *
-upgt_rx(struct upgt_softc *sc, uint8_t *data, int pkglen, int *rssi)
+upgt_rx(struct upgt_softc *sc, uint8_t *data, uint16_t pkglen, int *rssi)
{
struct ieee80211com *ic = &sc->sc_ic;
struct upgt_lmac_rx_desc *rxdesc;
@@ -1449,9 +1470,21 @@
/* access RX packet descriptor */
rxdesc = (struct upgt_lmac_rx_desc *)data;
+ if (pkglen < IEEE80211_ACK_LEN) {
+ device_printf(sc->sc_dev,
+ "%s: frame is too short! (pkglen %d)\n",
+ __func__, pkglen);
+ return (NULL);
+ }
+
+ if (pkglen >= MCLBYTES - ETHER_ALIGN) {
+ device_printf(sc->sc_dev,
+ "%s: A current mbuf storage is small (%d)\n",
+ __func__, pkglen + ETHER_ALIGN);
+ return (NULL);
+ }
+
/* create mbuf which is suitable for strict alignment archs */
- KASSERT((pkglen + ETHER_ALIGN) < MCLBYTES,
- ("A current mbuf storage is small (%d)", pkglen + ETHER_ALIGN));
m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
if (m == NULL) {
device_printf(sc->sc_dev, "could not create RX mbuf\n");
@@ -1701,6 +1734,15 @@
{
int i;
+ if ((uint64_t)(sc->sc_memaddr_frame_start + MCLBYTES) >
+ sc->sc_memaddr_frame_end) {
+ device_printf(sc->sc_dev,
+ "%s: start (%u) + MCLBYTES > end (%u)!\n",
+ __func__, sc->sc_memaddr_frame_start,
+ sc->sc_memaddr_frame_end);
+ return (EINVAL);
+ }
+
for (i = 0; i < UPGT_MEMORY_MAX_PAGES; i++) {
sc->sc_memory.page[i].used = 0;
@@ -1716,6 +1758,14 @@
sc->sc_memory.page[i - 1].addr + MCLBYTES;
}
+ /* Memory wrap check. */
+ if (sc->sc_memaddr_frame_start > sc->sc_memory.page[i].addr) {
+ device_printf(sc->sc_dev,
+ "%s: frame_start (%u) is too large!\n",
+ __func__, sc->sc_memaddr_frame_start);
+ return (EINVAL);
+ }
+
if (sc->sc_memory.page[i].addr + MCLBYTES >=
sc->sc_memaddr_frame_end)
break;
@@ -1753,17 +1803,19 @@
/*
* Seek to beginning of Boot Record Area (BRA).
*/
- for (offset = 0; offset < fw->datasize; offset += sizeof(*uc)) {
+ for (offset = 0;
+ offset + sizeof(*uc) <= fw->datasize;
+ offset += sizeof(*uc)) {
uc = (const uint32_t *)((const uint8_t *)fw->data + offset);
if (*uc == 0)
break;
}
- for (; offset < fw->datasize; offset += sizeof(*uc)) {
+ for (; offset + sizeof(*uc) <= fw->datasize; offset += sizeof(*uc)) {
uc = (const uint32_t *)((const uint8_t *)fw->data + offset);
if (*uc != 0)
break;
}
- if (offset == fw->datasize) {
+ if (offset + sizeof(*uc) > fw->datasize) {
device_printf(sc->sc_dev,
"firmware Boot Record Area not found\n");
error = EIO;
@@ -1776,13 +1828,21 @@
/*
* Parse Boot Record Area (BRA) options.
*/
- while (offset < fw->datasize && bra_end == 0) {
+ while (offset <= fw->datasize - sizeof(*bra_opt) && bra_end == 0) {
/* get current BRA option */
p = (const uint8_t *)fw->data + offset;
bra_opt = (const struct upgt_fw_bra_option *)p;
bra_option_type = le32toh(bra_opt->type);
bra_option_len = le32toh(bra_opt->len) * sizeof(*uc);
+ if (bra_option_len > (size_t)(fw->datasize - offset -
+ sizeof(*bra_opt)) ||
+ bra_option_len / sizeof(*uc) != le32toh(bra_opt->len)) {
+ device_printf(sc->sc_dev, "bra_option_len overflow\n");
+ error = EINVAL;
+ goto fail;
+ }
+
switch (bra_option_type) {
case UPGT_BRA_TYPE_FW:
DPRINTF(sc, UPGT_DEBUG_FW, "UPGT_BRA_TYPE_FW len=%d\n",
@@ -1821,6 +1881,18 @@
"UPGT_BRA_TYPE_EXPIF len=%d\n", bra_option_len);
break;
case UPGT_BRA_TYPE_DESCR:
+ if (sizeof(*descr) > fw->datasize - offset -
+ sizeof(*bra_opt) ||
+ sizeof(*descr) > bra_option_len) {
+ device_printf(sc->sc_dev, "%s: no place for"
+ "'struct upgt_fw_bra_descr' (%zu / %u)\n",
+ __func__,
+ fw->datasize - offset - sizeof(*bra_opt),
+ bra_option_len);
+ error = EIO;
+ goto fail;
+ }
+
DPRINTF(sc, UPGT_DEBUG_FW,
"UPGT_BRA_TYPE_DESCR len=%d\n", bra_option_len);
@@ -2111,14 +2183,28 @@
struct upgt_data *data)
{
struct ieee80211vap *vap = ni->ni_vap;
- int error = 0, len;
+ int error = 0;
struct ieee80211_frame *wh;
struct ieee80211_key *k;
struct upgt_lmac_mem *mem;
struct upgt_lmac_tx_desc *txdesc;
+ uint32_t len;
UPGT_ASSERT_LOCKED(sc);
+ /* Calculate frame size. */
+ len = sizeof(*mem) + sizeof(*txdesc) + m->m_pkthdr.len;
+ /* We need to align the frame to a 4 byte boundary. */
+ len = (len + 3) & ~3;
+
+ if (len > MCLBYTES) {
+ device_printf(sc->sc_dev,
+ "%s: the frame %p is too big (%d)\n",
+ __func__, m, m->m_pkthdr.len);
+ error = EINVAL;
+ goto done;
+ }
+
upgt_set_led(sc, UPGT_LED_BLINK);
/*
@@ -2175,19 +2261,14 @@
/* copy frame below our TX descriptor header */
m_copydata(m, 0, m->m_pkthdr.len,
data->buf + (sizeof(*mem) + sizeof(*txdesc)));
- /* calculate frame size */
- len = sizeof(*mem) + sizeof(*txdesc) + m->m_pkthdr.len;
- /* we need to align the frame to a 4 byte boundary */
- len = (len + 3) & ~3;
/* calculate frame checksum */
mem->chksum = upgt_chksum_le((uint32_t *)txdesc, len - sizeof(*mem));
data->ni = ni;
data->m = m;
data->buflen = len;
- DPRINTF(sc, UPGT_DEBUG_XMIT, "%s: TX start data sending (%d bytes)\n",
+ DPRINTF(sc, UPGT_DEBUG_XMIT, "%s: TX start data sending (%u bytes)\n",
__func__, len);
- KASSERT(len <= MCLBYTES, ("mbuf is small for saving data"));
upgt_bulk_tx(sc, data);
done:

File Metadata

Mime Type
text/plain
Expires
Sun, Mar 15, 10:50 AM (9 h, 40 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
29697372
Default Alt Text
D11785.diff (8 KB)

Event Timeline