[PATCH] wifi: ath10k: fix OOB write from unbounded SDIO RX bundle count

Tianchu Chen tianchu.chen at linux.dev
Thu Sep 24 06:29:58 PDT 2026


From: Tianchu Chen <flynnnchen at tencent.com>

An RX event here is one invocation of
ath10k_sdio_mbox_rxmsg_pending_handler(), triggered by the mailbox
"RX pending" interrupt.  During such an event the device announces
pending packets through lookaheads, the first one read from the
HTC register table, the following ones carried in the trailers of
the packets just fetched.  ath10k_sdio_mbox_rx_alloc()
pre-allocates one rx_pkts[] slot per announced packet, after which
the device transfers exactly that many packets over SDIO.

A lookahead whose HTC header carries a bundle count K stands for
K+1 packets.  However, only the raw lookahead count is checked
against ATH10K_SDIO_MAX_RX_MSGS; the expanded total pkt_cnt is
never compared against the size of ar_sdio->rx_pkts[] (64 entries),
the index is simply advanced and written to.  With up to 32
lookaheads per round (the trailer record limit) each claiming
K=32, the loop stores up to 32 * 33 = 1056 struct
ath10k_sdio_rx_data entries into the 64-entry array, i.e. 992
entries (~31KB) past its end, overwriting the members that follow
it in struct ath10k_sdio.

Add the missing comparison: the current lookahead and its bundled
packets must fit into the remaining rx_pkts[] slots before any of
them is allocated.

This is expected to keep behavior unchanged on most cases: The new
check drops exactly when the old code would have written past
the array and corrupt the driver state.

Discovered by Atuin - Automated Vulnerability Discovery Engine.

Fixes: 8d985555ddaa ("ath10k: enable RX bundle receive for sdio")
Cc: stable at vger.kernel.org
Assisted-by: LLM
Signed-off-by: Tianchu Chen <flynnnchen at tencent.com>
---
 drivers/net/wireless/ath/ath10k/sdio.c | 19 ++++++++++++++-----
 1 file changed, 14 insertions(+), 5 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/sdio.c b/drivers/net/wireless/ath/ath10k/sdio.c
index 65e941b527517..5dc2ad432b099 100644
--- a/drivers/net/wireless/ath/ath10k/sdio.c
+++ b/drivers/net/wireless/ath/ath10k/sdio.c
@@ -540,7 +540,7 @@ static int ath10k_sdio_mbox_rx_alloc(struct ath10k *ar,
 {
 	struct ath10k_sdio *ar_sdio = ath10k_sdio_priv(ar);
 	struct ath10k_htc_hdr *htc_hdr;
-	size_t full_len, act_len;
+	size_t full_len, act_len, bndl_cnt;
 	bool last_in_bundle;
 	int ret, i;
 	int pkt_cnt = 0;
@@ -579,14 +579,23 @@ static int ath10k_sdio_mbox_rx_alloc(struct ath10k *ar,
 			goto err;
 		}
 
-		if (ath10k_htc_get_bundle_count(
-			ar->htc.max_msgs_per_htc_bundle, htc_hdr->flags)) {
+		bndl_cnt = ath10k_htc_get_bundle_count(
+			ar->htc.max_msgs_per_htc_bundle, htc_hdr->flags);
+
+		/* One rx_pkts[] slot per lookahead plus one per bundled packet */
+		if (bndl_cnt + 1 > ATH10K_SDIO_MAX_RX_MSGS - pkt_cnt) {
+			ath10k_warn(ar,
+				    "rx bundle count %zu exceeds remaining pkt slots\n",
+				    bndl_cnt);
+			ret = -ENOMEM;
+			goto err;
+		}
+
+		if (bndl_cnt) {
 			/* HTC header indicates that every packet to follow
 			 * has the same padded length so that it can be
 			 * optimally fetched as a full bundle.
 			 */
-			size_t bndl_cnt;
-
 			ret = ath10k_sdio_mbox_alloc_bundle(ar,
 							    &ar_sdio->rx_pkts[pkt_cnt],
 							    htc_hdr,
-- 
2.51.0



More information about the ath10k mailing list