From ab088de4bf3adba9982149226a9d2337a280b20b Mon Sep 17 00:00:00 2001 From: Carter Chen Date: Mon, 5 Sep 2022 02:51:45 -0500 Subject: [PATCH 112/296] brcmfmac: Fixing vulnerability Adding sanity check to make the driver doesn't handle an overflowed length. Signed-off-by: Carter Chen --- .../broadcom/brcm80211/brcmfmac/sdio.c | 56 +++++++++++-------- 1 file changed, 34 insertions(+), 22 deletions(-) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c index d9df4c37ce5c..3de7d97d0a5c 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c @@ -1615,13 +1615,20 @@ static u8 brcmf_sdio_rxglom(struct brcmf_sdio *bus, u8 rxseq) /* If there's a descriptor, generate the packet chain */ if (bus->glomd) { pfirst = pnext = NULL; - dlen = (u16) (bus->glomd->len); - dptr = bus->glomd->data; - if (!dlen || (dlen & 1)) { - brcmf_err("bad glomd len(%d), ignore descriptor\n", + /* it is a u32 len to u16 dlen, should have a sanity check here. */ + if (bus->glomd->len <= 0xFFFF) { + dlen = (u16)(bus->glomd->len); + if (!dlen || (dlen & 1)) { + brcmf_err("bad glomd len(%d), ignore descriptor\n", + dlen); + dlen = 0; + } + } else { + brcmf_err("overflowed glomd len(%d), ignore descriptor\n", dlen); dlen = 0; } + dptr = bus->glomd->data; for (totlen = num = 0; dlen; num++) { /* Get (and move past) next length */ @@ -1687,6 +1694,7 @@ static u8 brcmf_sdio_rxglom(struct brcmf_sdio *bus, u8 rxseq) /* Ok -- either we just generated a packet chain, or had one from before */ if (!skb_queue_empty(&bus->glom)) { + u32 len_glom = 0; if (BRCMF_GLOM_ON()) { brcmf_dbg(GLOM, "try superframe read, packet chain:\n"); skb_queue_walk(&bus->glom, pnext) { @@ -1697,7 +1705,14 @@ static u8 brcmf_sdio_rxglom(struct brcmf_sdio *bus, u8 rxseq) } pfirst = skb_peek(&bus->glom); - dlen = (u16) brcmf_sdio_glom_len(bus); + len_glom = brcmf_sdio_glom_len(bus); + if (len_glom > 0xFFFF) { + brcmf_err("glom_len is %d bytes, overflowed\n", + len_glom); + goto frame_error_handle; + } else { + dlen = (u16)len_glom; + } /* Do an SDIO read for the superframe. Configurable iovar to * read directly into the chained packet, or allocate a large @@ -1713,13 +1728,7 @@ static u8 brcmf_sdio_rxglom(struct brcmf_sdio *bus, u8 rxseq) if (errcode < 0) { brcmf_err("glom read of %d bytes failed: %d\n", dlen, errcode); - - sdio_claim_host(bus->sdiodev->func1); - brcmf_sdio_rxfail(bus, true, false); - bus->sdcnt.rxglomfail++; - brcmf_sdio_free_glom(bus); - sdio_release_host(bus->sdiodev->func1); - return 0; + goto frame_error_handle; } brcmf_dbg_hex_dump(BRCMF_GLOM_ON(), @@ -1756,16 +1765,9 @@ static u8 brcmf_sdio_rxglom(struct brcmf_sdio *bus, u8 rxseq) num++; } - if (errcode) { - /* Terminate frame on error */ - sdio_claim_host(bus->sdiodev->func1); - brcmf_sdio_rxfail(bus, true, false); - bus->sdcnt.rxglomfail++; - brcmf_sdio_free_glom(bus); - sdio_release_host(bus->sdiodev->func1); - bus->cur_read.len = 0; - return 0; - } + /* Terminate frame on error */ + if (errcode) + goto frame_error_handle; /* Basic SD framing looks ok - process each packet (header) */ @@ -1806,6 +1808,16 @@ static u8 brcmf_sdio_rxglom(struct brcmf_sdio *bus, u8 rxseq) bus->sdcnt.rxglomframes++; } return num; + +frame_error_handle: + sdio_claim_host(bus->sdiodev->func1); + brcmf_sdio_rxfail(bus, true, false); + bus->sdcnt.rxglomfail++; + brcmf_sdio_free_glom(bus); + sdio_release_host(bus->sdiodev->func1); + bus->cur_read.len = 0; + + return 0; } static int brcmf_sdio_dcmd_resp_wait(struct brcmf_sdio *bus, uint *condition, -- 2.25.1