* [PATCH net] ipv6: ndisc: fix NULL deref in accept_untracked_na()
@ 2026-06-17 6:55 Weiming Shi
2026-06-17 8:32 ` Jiayuan Chen
` (2 more replies)
0 siblings, 3 replies; 7+ messages in thread
From: Weiming Shi @ 2026-06-17 6:55 UTC (permalink / raw)
To: David S . Miller, David Ahern, Eric Dumazet, Jakub Kicinski,
Paolo Abeni
Cc: Simon Horman, netdev, linux-kernel, Xiang Mei, Weiming Shi
accept_untracked_na() re-fetches the inet6_dev with __in6_dev_get(dev)
and dereferences idev->cnf.accept_untracked_na without a NULL check,
even though its only caller ndisc_recv_na() already fetched and
NULL-checked idev for the same device.
Both reads of dev->ip6_ptr run in the same RCU read-side critical
section, but a concurrent addrconf_ifdown() can clear dev->ip6_ptr
between them: lowering the MTU below IPV6_MIN_MTU calls addrconf_ifdown()
without the synchronize_net() that orders the unregister path, so the
re-fetch returns NULL and oopses:
BUG: KASAN: null-ptr-deref in ndisc_recv_na (net/ipv6/ndisc.c:974)
Read of size 4 at addr 0000000000000364
Call Trace:
<IRQ>
ndisc_recv_na (net/ipv6/ndisc.c:974)
icmpv6_rcv (net/ipv6/icmp.c:1193)
ip6_protocol_deliver_rcu (net/ipv6/ip6_input.c:479)
ip6_input_finish (net/ipv6/ip6_input.c:534)
ip6_input (net/ipv6/ip6_input.c:545)
ip6_mc_input (net/ipv6/ip6_input.c:635)
ipv6_rcv (net/ipv6/ip6_input.c:351)
</IRQ>
It is reachable by an unprivileged user via a network namespace.
Pass the caller's already validated idev instead of re-fetching it; the
idev stays alive for the whole RCU critical section, so it is safe even
after dev->ip6_ptr has been cleared.
Fixes: aaa5f515b16b ("net: ipv6: new accept_untracked_na option to accept na only if in-network")
Assisted-by: Claude:claude-opus-4-8
Reported-by: Xiang Mei <xmei5@asu.edu>
Signed-off-by: Weiming Shi <bestswngs@gmail.com>
---
net/ipv6/ndisc.c | 8 +++-----
1 file changed, 3 insertions(+), 5 deletions(-)
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
index e7ad13c5bd267..f867ec8d3d905 100644
--- a/net/ipv6/ndisc.c
+++ b/net/ipv6/ndisc.c
@@ -967,10 +967,8 @@ static enum skb_drop_reason ndisc_recv_ns(struct sk_buff *skb)
return reason;
}
-static int accept_untracked_na(struct net_device *dev, struct in6_addr *saddr)
+static int accept_untracked_na(struct inet6_dev *idev, struct in6_addr *saddr)
{
- struct inet6_dev *idev = __in6_dev_get(dev);
-
switch (READ_ONCE(idev->cnf.accept_untracked_na)) {
case 0: /* Don't accept untracked na (absent in neighbor cache) */
return 0;
@@ -980,7 +978,7 @@ static int accept_untracked_na(struct net_device *dev, struct in6_addr *saddr)
* same subnet as an address configured on the interface that
* received the na
*/
- return !!ipv6_chk_prefix(saddr, dev);
+ return !!ipv6_chk_prefix(saddr, idev->dev);
default:
return 0;
}
@@ -1078,7 +1076,7 @@ static enum skb_drop_reason ndisc_recv_na(struct sk_buff *skb)
*/
new_state = msg->icmph.icmp6_solicited ? NUD_REACHABLE : NUD_STALE;
if (!neigh && lladdr && idev && READ_ONCE(idev->cnf.forwarding)) {
- if (accept_untracked_na(dev, saddr)) {
+ if (accept_untracked_na(idev, saddr)) {
neigh = neigh_create(&nd_tbl, &msg->target, dev);
new_state = NUD_STALE;
}
--
2.43.0
^ permalink raw reply related [flat|nested] 7+ messages in thread* Re: [PATCH net] ipv6: ndisc: fix NULL deref in accept_untracked_na()
2026-06-17 6:55 [PATCH net] ipv6: ndisc: fix NULL deref in accept_untracked_na() Weiming Shi
@ 2026-06-17 8:32 ` Jiayuan Chen
2026-06-17 13:38 ` Weiming Shi
2026-06-19 6:24 ` Jiayuan Chen
2026-06-21 22:20 ` patchwork-bot+netdevbpf
2 siblings, 1 reply; 7+ messages in thread
From: Jiayuan Chen @ 2026-06-17 8:32 UTC (permalink / raw)
To: Weiming Shi, David S . Miller, David Ahern, Eric Dumazet,
Jakub Kicinski, Paolo Abeni
Cc: Simon Horman, netdev, linux-kernel, Xiang Mei
On 6/17/26 2:55 PM, Weiming Shi wrote:
> accept_untracked_na() re-fetches the inet6_dev with __in6_dev_get(dev)
> and dereferences idev->cnf.accept_untracked_na without a NULL check,
Does ipv6_rpl_srh_rcv have same problem?
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH net] ipv6: ndisc: fix NULL deref in accept_untracked_na()
2026-06-17 8:32 ` Jiayuan Chen
@ 2026-06-17 13:38 ` Weiming Shi
2026-06-18 4:08 ` Jiayuan Chen
0 siblings, 1 reply; 7+ messages in thread
From: Weiming Shi @ 2026-06-17 13:38 UTC (permalink / raw)
To: Jiayuan Chen, Weiming Shi, David S . Miller, David Ahern,
Eric Dumazet, Jakub Kicinski, Paolo Abeni
Cc: Simon Horman, netdev, linux-kernel, Xiang Mei
On Wed Jun 17, 2026 at 4:32 PM CST, Jiayuan Chen wrote:
>
> On 6/17/26 2:55 PM, Weiming Shi wrote:
>> accept_untracked_na() re-fetches the inet6_dev with __in6_dev_get(dev)
>> and dereferences idev->cnf.accept_untracked_na without a NULL check,
>
>
> Does ipv6_rpl_srh_rcv have same problem?
Hi,
Yes, ipv6_rpl_srh_rcv() has the same missing check. It reads
idev->cnf.rpl_seg_enabled right after __in6_dev_get(skb->dev) with no
NULL check, while seg6 and ioam6 in the same file both check it.
But I tried to trigger it and couldn't. With a guard added as an instrument,
idev never came back NULL over tens of millions of RPL packets while
flapping the MTU, so I can't say it's actually reachable.
Still, it's the only one of the three without the check. Want me to send
a patch adding it there too, for consistency?
Thanks,
Weiming Shi
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH net] ipv6: ndisc: fix NULL deref in accept_untracked_na()
2026-06-17 13:38 ` Weiming Shi
@ 2026-06-18 4:08 ` Jiayuan Chen
2026-06-19 4:05 ` Xiang Mei
0 siblings, 1 reply; 7+ messages in thread
From: Jiayuan Chen @ 2026-06-18 4:08 UTC (permalink / raw)
To: Weiming Shi, David S . Miller, David Ahern, Eric Dumazet,
Jakub Kicinski, Paolo Abeni
Cc: Simon Horman, netdev, linux-kernel, Xiang Mei
On 6/17/26 9:38 PM, Weiming Shi wrote:
> On Wed Jun 17, 2026 at 4:32 PM CST, Jiayuan Chen wrote:
>> On 6/17/26 2:55 PM, Weiming Shi wrote:
>>> accept_untracked_na() re-fetches the inet6_dev with __in6_dev_get(dev)
>>> and dereferences idev->cnf.accept_untracked_na without a NULL check,
>>
>> Does ipv6_rpl_srh_rcv have same problem?
> Hi,
>
> Yes, ipv6_rpl_srh_rcv() has the same missing check. It reads
> idev->cnf.rpl_seg_enabled right after __in6_dev_get(skb->dev) with no
> NULL check, while seg6 and ioam6 in the same file both check it.
>
> But I tried to trigger it and couldn't. With a guard added as an instrument,
> idev never came back NULL over tens of millions of RPL packets while
> flapping the MTU, so I can't say it's actually reachable.
Can you need to add mdelay to enlarge the race window to reproduce it?
I believe we need more precise traffic and timing control, instead of
aggressively ramping up traffic and load in an attempt to reproduce the
issue.
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH net] ipv6: ndisc: fix NULL deref in accept_untracked_na()
2026-06-18 4:08 ` Jiayuan Chen
@ 2026-06-19 4:05 ` Xiang Mei
0 siblings, 0 replies; 7+ messages in thread
From: Xiang Mei @ 2026-06-19 4:05 UTC (permalink / raw)
To: Jiayuan Chen
Cc: Weiming Shi, David S . Miller, David Ahern, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, netdev, linux-kernel
On Wed, Jun 17, 2026 at 9:09 PM Jiayuan Chen <jiayuan.chen@linux.dev> wrote:
>
>
> On 6/17/26 9:38 PM, Weiming Shi wrote:
> > On Wed Jun 17, 2026 at 4:32 PM CST, Jiayuan Chen wrote:
> >> On 6/17/26 2:55 PM, Weiming Shi wrote:
> >>> accept_untracked_na() re-fetches the inet6_dev with __in6_dev_get(dev)
> >>> and dereferences idev->cnf.accept_untracked_na without a NULL check,
> >>
> >> Does ipv6_rpl_srh_rcv have same problem?
> > Hi,
> >
> > Yes, ipv6_rpl_srh_rcv() has the same missing check. It reads
> > idev->cnf.rpl_seg_enabled right after __in6_dev_get(skb->dev) with no
> > NULL check, while seg6 and ioam6 in the same file both check it.
> >
> > But I tried to trigger it and couldn't. With a guard added as an instrument,
> > idev never came back NULL over tens of millions of RPL packets while
> > flapping the MTU, so I can't say it's actually reachable.
>
>
> Can you need to add mdelay to enlarge the race window to reproduce it?
>
The delay works; we insert one at
@@ -1078,6 +1079,7 @@ static enum skb_drop_reason ndisc_recv_na(struct
sk_buff *skb)
*/
new_state = msg->icmph.icmp6_solicited ? NUD_REACHABLE : NUD_STALE;
if (!neigh && lladdr && idev && READ_ONCE(idev->cnf.forwarding)) {
+ mdelay(100); /* AI-POC: widen race window vs
concurrent addrconf_ifdown() NULLing dev->ip6_ptr */
if (accept_untracked_na(dev, saddr)) {
neigh = neigh_create(&nd_tbl, &msg->target, dev);
new_state = NUD_STALE;
And our poc triggers:
```
[ 0.887292] Oops: general protection fault, probably for
non-canonical address 0xdffffc0000000068: 0000 [#1] SMP KASAN NOPTI
[ 0.887791] KASAN: null-ptr-deref in range
[0x0000000000000340-0x0000000000000347]
[ 0.888101] CPU: 1 UID: 0 PID: 146 Comm: exploit Not tainted 7.1.0+
#9 PREEMPTLAZY
[ 0.888419] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996),
BIOS rel-1.17.0-0-gb52ca86e094d-prebuilt.qemu.org 04/01/4
[ 0.888880] RIP: 0010:ndisc_recv_na+0x67b/0xf30
[ 0.889072] Code: 03 80 3c 02 00 0f 85 5f 07 00 00 49 8b af c0 00
00 00 48 b8 00 00 00 00 00 fc ff df 48 8d bd 40 03 00 00 e
[ 0.889829] RSP: 0018:ffff8881029084f8 EFLAGS: 00010202
[ 0.890043] RAX: dffffc0000000000 RBX: 1ffff110205210a8 RCX: 0000000000000001
[ 0.890340] RDX: 0000000000000068 RSI: 0000000000004d9a RDI: 0000000000000340
[ 0.890633] RBP: 0000000000000000 R08: 0000000000000004 R09: ffff888102908570
[ 0.890921] R10: ffff88800ee7f792 R11: ffff888102908580 R12: ffff88800ee7f780
[ 0.891207] R13: ffff88800ee7f778 R14: ffff88800ee7f792 R15: ffff88800f2d6000
[ 0.891511] FS: 00007b8516aec6c0(0000) GS:ffff888177d3d000(0000)
knlGS:0000000000000000
[ 0.891853] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 0.892094] CR2: 00007b8516aebb30 CR3: 000000000f164006 CR4: 0000000000772ef0
[ 0.892402] PKRU: 55555554
[ 0.892517] Call Trace:
[ 0.892627] <IRQ>
[ 0.892718] ? stack_trace_save+0x93/0xd0
[ 0.892895] ? __pfx_ndisc_recv_na+0x10/0x10
[ 0.893087] ? _raw_spin_unlock_irqrestore+0xe/0x40
[ 0.893295] ? stack_depot_save_flags+0x488/0x810
[ 0.893506] ? fib6_rule_lookup+0x40a/0x5a0
[ 0.893689] ? __napi_poll+0xa1/0x560
[ 0.893852] ? net_rx_action+0x401/0xd80
[ 0.894025] icmpv6_rcv+0x10a4/0x14e0
[ 0.894181] ip6_protocol_deliver_rcu+0xbd4/0x1340
[ 0.894391] ip6_input_finish+0x1d1/0x3a0
[ 0.894559] ip6_input+0x195/0x1d0
[ 0.894709] ? __pfx_ip6_input+0x10/0x10
[ 0.894873] ? __asan_memset+0x23/0x50
[ 0.895034] ip6_mc_input+0x26c/0x3a0
[ 0.895188] ipv6_rcv+0x31b/0x390
[ 0.895340] ? __pfx_ipv6_rcv+0x10/0x10
[ 0.895501] ? get_stack_info+0x2f/0x90
[ 0.895665] ? stack_access_ok+0xde/0x200
[ 0.895833] ? get_stack_info_noinstr+0x18/0x110
[ 0.896036] __netif_receive_skb_core.constprop.0+0xd78/0x2f00
[ 0.896286] ? common_startup_64+0x13e/0x151
[ 0.896475] ? common_startup_64+0x13e/0x151
[ 0.896655] ? __pfx_stack_trace_consume_entry+0x10/0x10
[ 0.896875] ? arch_stack_walk+0x99/0x100
[ 0.897049] ? __pfx___netif_receive_skb_core.constprop.0+0x10/0x10
[ 0.897310] ? common_startup_64+0x13e/0x151
[ 0.897498] ? stack_trace_save+0x93/0xd0
[ 0.897668] ? __pfx_stack_trace_save+0x10/0x10
[ 0.897855] ? stack_depot_save_flags+0x29/0x810
[ 0.898046] ? kasan_save_stack+0x33/0x60
[ 0.898213] ? kasan_save_track+0x14/0x30
[ 0.898389] ? kasan_save_free_info+0x3b/0x60
...
```
Weiming's patch works with a delay. The poc doesn't crash the kernel.
I noticed that you mentioned ipv6_rpl_srh_rcv. We actually have sent
one, but we later found that someone (Andrea Mayer) had sent the issue
earlier, so we just let them fix it:
https://lore.kernel.org/all/20260521200859.816b8923b5f27bba6124461e@uniroma2.it/
Xiang
> I believe we need more precise traffic and timing control, instead of
> aggressively ramping up traffic and load in an attempt to reproduce the
> issue.
>
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH net] ipv6: ndisc: fix NULL deref in accept_untracked_na()
2026-06-17 6:55 [PATCH net] ipv6: ndisc: fix NULL deref in accept_untracked_na() Weiming Shi
2026-06-17 8:32 ` Jiayuan Chen
@ 2026-06-19 6:24 ` Jiayuan Chen
2026-06-21 22:20 ` patchwork-bot+netdevbpf
2 siblings, 0 replies; 7+ messages in thread
From: Jiayuan Chen @ 2026-06-19 6:24 UTC (permalink / raw)
To: Weiming Shi, David S . Miller, David Ahern, Eric Dumazet,
Jakub Kicinski, Paolo Abeni
Cc: Simon Horman, netdev, linux-kernel, Xiang Mei
On 6/17/26 2:55 PM, Weiming Shi wrote:
> accept_untracked_na() re-fetches the inet6_dev with __in6_dev_get(dev)
> and dereferences idev->cnf.accept_untracked_na without a NULL check,
> even though its only caller ndisc_recv_na() already fetched and
> NULL-checked idev for the same device.
>
> Both reads of dev->ip6_ptr run in the same RCU read-side critical
> section, but a concurrent addrconf_ifdown() can clear dev->ip6_ptr
> between them: lowering the MTU below IPV6_MIN_MTU calls addrconf_ifdown()
> without the synchronize_net() that orders the unregister path, so the
> re-fetch returns NULL and oopses:
>
> BUG: KASAN: null-ptr-deref in ndisc_recv_na (net/ipv6/ndisc.c:974)
> Read of size 4 at addr 0000000000000364
> Call Trace:
> <IRQ>
> ndisc_recv_na (net/ipv6/ndisc.c:974)
> icmpv6_rcv (net/ipv6/icmp.c:1193)
> ip6_protocol_deliver_rcu (net/ipv6/ip6_input.c:479)
> ip6_input_finish (net/ipv6/ip6_input.c:534)
> ip6_input (net/ipv6/ip6_input.c:545)
> ip6_mc_input (net/ipv6/ip6_input.c:635)
> ipv6_rcv (net/ipv6/ip6_input.c:351)
> </IRQ>
>
> It is reachable by an unprivileged user via a network namespace.
>
> Pass the caller's already validated idev instead of re-fetching it; the
> idev stays alive for the whole RCU critical section, so it is safe even
> after dev->ip6_ptr has been cleared.
>
> Fixes: aaa5f515b16b ("net: ipv6: new accept_untracked_na option to accept na only if in-network")
> Assisted-by: Claude:claude-opus-4-8
> Reported-by: Xiang Mei <xmei5@asu.edu>
> Signed-off-by: Weiming Shi <bestswngs@gmail.com>
Reviewed-by: Jiayuan Chen <jiayuan.chen@linux.dev>
^ permalink raw reply [flat|nested] 7+ messages in thread* Re: [PATCH net] ipv6: ndisc: fix NULL deref in accept_untracked_na()
2026-06-17 6:55 [PATCH net] ipv6: ndisc: fix NULL deref in accept_untracked_na() Weiming Shi
2026-06-17 8:32 ` Jiayuan Chen
2026-06-19 6:24 ` Jiayuan Chen
@ 2026-06-21 22:20 ` patchwork-bot+netdevbpf
2 siblings, 0 replies; 7+ messages in thread
From: patchwork-bot+netdevbpf @ 2026-06-21 22:20 UTC (permalink / raw)
To: Weiming Shi
Cc: davem, dsahern, edumazet, kuba, pabeni, horms, netdev,
linux-kernel, xmei5
Hello:
This patch was applied to netdev/net.git (main)
by Jakub Kicinski <kuba@kernel.org>:
On Wed, 17 Jun 2026 14:55:13 +0800 you wrote:
> accept_untracked_na() re-fetches the inet6_dev with __in6_dev_get(dev)
> and dereferences idev->cnf.accept_untracked_na without a NULL check,
> even though its only caller ndisc_recv_na() already fetched and
> NULL-checked idev for the same device.
>
> Both reads of dev->ip6_ptr run in the same RCU read-side critical
> section, but a concurrent addrconf_ifdown() can clear dev->ip6_ptr
> between them: lowering the MTU below IPV6_MIN_MTU calls addrconf_ifdown()
> without the synchronize_net() that orders the unregister path, so the
> re-fetch returns NULL and oopses:
>
> [...]
Here is the summary with links:
- [net] ipv6: ndisc: fix NULL deref in accept_untracked_na()
https://git.kernel.org/netdev/net/c/d186e942365a
You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2026-06-21 22:20 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-17 6:55 [PATCH net] ipv6: ndisc: fix NULL deref in accept_untracked_na() Weiming Shi
2026-06-17 8:32 ` Jiayuan Chen
2026-06-17 13:38 ` Weiming Shi
2026-06-18 4:08 ` Jiayuan Chen
2026-06-19 4:05 ` Xiang Mei
2026-06-19 6:24 ` Jiayuan Chen
2026-06-21 22:20 ` patchwork-bot+netdevbpf
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox