Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

net: wwan: t7xx: Fix napi rx poll issue

When driver handles the napi rx polling requests, the netdev might
have been released by the dellink logic triggered by the disconnect
operation on user plane. However, in the logic of processing skb in
polling, an invalid netdev is still being used, which causes a panic.

BUG: kernel NULL pointer dereference, address: 00000000000000f1
Oops: 0000 [#1] PREEMPT SMP NOPTI
RIP: 0010:dev_gro_receive+0x3a/0x620
[...]
Call Trace:
<IRQ>
? __die_body+0x68/0xb0
? page_fault_oops+0x379/0x3e0
? exc_page_fault+0x4f/0xa0
? asm_exc_page_fault+0x22/0x30
? __pfx_t7xx_ccmni_recv_skb+0x10/0x10 [mtk_t7xx (HASH:1400 7)]
? dev_gro_receive+0x3a/0x620
napi_gro_receive+0xad/0x170
t7xx_ccmni_recv_skb+0x48/0x70 [mtk_t7xx (HASH:1400 7)]
t7xx_dpmaif_napi_rx_poll+0x590/0x800 [mtk_t7xx (HASH:1400 7)]
net_rx_action+0x103/0x470
irq_exit_rcu+0x13a/0x310
sysvec_apic_timer_interrupt+0x56/0x90
</IRQ>

Fixes: 5545b7b9f294 ("net: wwan: t7xx: Add NAPI support")
Signed-off-by: Jinjian Song <jinjian.song@fibocom.com>
Link: https://patch.msgid.link/20250530031648.5592-1-jinjian.song@fibocom.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>

authored by

Jinjian Song and committed by
Paolo Abeni
905fe084 408da3a0

+6 -5
+6 -5
drivers/net/wwan/t7xx/t7xx_netdev.c
··· 302 302 ccmni->ctlb = ctlb; 303 303 ccmni->dev = dev; 304 304 atomic_set(&ccmni->usage, 0); 305 - ctlb->ccmni_inst[if_id] = ccmni; 305 + WRITE_ONCE(ctlb->ccmni_inst[if_id], ccmni); 306 306 307 307 ret = register_netdevice(dev); 308 308 if (ret) ··· 324 324 if (WARN_ON(ctlb->ccmni_inst[if_id] != ccmni)) 325 325 return; 326 326 327 + WRITE_ONCE(ctlb->ccmni_inst[if_id], NULL); 327 328 unregister_netdevice(dev); 328 329 } 329 330 ··· 420 419 421 420 skb_cb = T7XX_SKB_CB(skb); 422 421 netif_id = skb_cb->netif_idx; 423 - ccmni = ccmni_ctlb->ccmni_inst[netif_id]; 422 + ccmni = READ_ONCE(ccmni_ctlb->ccmni_inst[netif_id]); 424 423 if (!ccmni) { 425 424 dev_kfree_skb(skb); 426 425 return; ··· 442 441 443 442 static void t7xx_ccmni_queue_tx_irq_notify(struct t7xx_ccmni_ctrl *ctlb, int qno) 444 443 { 445 - struct t7xx_ccmni *ccmni = ctlb->ccmni_inst[0]; 444 + struct t7xx_ccmni *ccmni = READ_ONCE(ctlb->ccmni_inst[0]); 446 445 struct netdev_queue *net_queue; 447 446 448 447 if (netif_running(ccmni->dev) && atomic_read(&ccmni->usage) > 0) { ··· 454 453 455 454 static void t7xx_ccmni_queue_tx_full_notify(struct t7xx_ccmni_ctrl *ctlb, int qno) 456 455 { 457 - struct t7xx_ccmni *ccmni = ctlb->ccmni_inst[0]; 456 + struct t7xx_ccmni *ccmni = READ_ONCE(ctlb->ccmni_inst[0]); 458 457 struct netdev_queue *net_queue; 459 458 460 459 if (atomic_read(&ccmni->usage) > 0) { ··· 472 471 if (ctlb->md_sta != MD_STATE_READY) 473 472 return; 474 473 475 - if (!ctlb->ccmni_inst[0]) { 474 + if (!READ_ONCE(ctlb->ccmni_inst[0])) { 476 475 dev_warn(&t7xx_dev->pdev->dev, "No netdev registered yet\n"); 477 476 return; 478 477 }