Skip to content

Commit f0813bc

Browse files
Keryerkuba-moo
authored andcommitted
net: wwan: t7xx: fix potential skb->frags overflow in RX path
When receiving data in the DPMAIF RX path, the t7xx_dpmaif_set_frag_to_skb() function adds page fragments to an skb without checking if the number of fragments has exceeded MAX_SKB_FRAGS. This could lead to a buffer overflow in skb_shinfo(skb)->frags[] array, corrupting adjacent memory and potentially causing kernel crashes or other undefined behavior. This issue was identified through static code analysis by comparing with a similar vulnerability fixed in the mt76 driver commit b102f0c ("mt76: fix array overflow on receiving too many fragments for a packet"). The vulnerability could be triggered if the modem firmware sends packets with excessive fragments. While under normal protocol conditions (MTU 3080 bytes, BAT buffer 3584 bytes), a single packet should not require additional fragments, the kernel should not blindly trust firmware behavior. Malicious, buggy, or compromised firmware could potentially craft packets with more fragments than the kernel expects. Fix this by adding a bounds check before calling skb_add_rx_frag() to ensure nr_frags does not exceed MAX_SKB_FRAGS. The check must be performed before unmapping to avoid a page leak and double DMA unmap during device teardown. Fixes: d642b01 ("net: wwan: t7xx: Add data path interface") Signed-off-by: Kery Qi <qikeyu2017@gmail.com> Link: https://patch.msgid.link/20260122170401.1986-2-qikeyu2017@gmail.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
1 parent 1742272 commit f0813bc

1 file changed

Lines changed: 7 additions & 2 deletions

File tree

drivers/net/wwan/t7xx/t7xx_hif_dpmaif_rx.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -395,25 +395,30 @@ static int t7xx_dpmaif_set_frag_to_skb(const struct dpmaif_rx_queue *rxq,
395395
struct sk_buff *skb)
396396
{
397397
unsigned long long data_bus_addr, data_base_addr;
398+
struct skb_shared_info *shinfo = skb_shinfo(skb);
398399
struct device *dev = rxq->dpmaif_ctrl->dev;
399400
struct dpmaif_bat_page *page_info;
400401
unsigned int data_len;
401402
int data_offset;
402403

403404
page_info = rxq->bat_frag->bat_skb;
404405
page_info += t7xx_normal_pit_bid(pkt_info);
405-
dma_unmap_page(dev, page_info->data_bus_addr, page_info->data_len, DMA_FROM_DEVICE);
406406

407407
if (!page_info->page)
408408
return -EINVAL;
409409

410+
if (shinfo->nr_frags >= MAX_SKB_FRAGS)
411+
return -EINVAL;
412+
413+
dma_unmap_page(dev, page_info->data_bus_addr, page_info->data_len, DMA_FROM_DEVICE);
414+
410415
data_bus_addr = le32_to_cpu(pkt_info->pd.data_addr_h);
411416
data_bus_addr = (data_bus_addr << 32) + le32_to_cpu(pkt_info->pd.data_addr_l);
412417
data_base_addr = page_info->data_bus_addr;
413418
data_offset = data_bus_addr - data_base_addr;
414419
data_offset += page_info->offset;
415420
data_len = FIELD_GET(PD_PIT_DATA_LEN, le32_to_cpu(pkt_info->header));
416-
skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, page_info->page,
421+
skb_add_rx_frag(skb, shinfo->nr_frags, page_info->page,
417422
data_offset, data_len, page_info->data_len);
418423

419424
page_info->page = NULL;

0 commit comments

Comments
 (0)