mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH net v3] ipv6: rpl: fix NULL dereference of idev in ipv6_rpl_srh_rcv()
@ 2026-08-17 13:26 Andrea Mayer
  2026-08-20 12:28 ` Simon Horman
                   ` (2 more replies)
  0 siblings, 3 replies; 5+ messages in thread
From: Andrea Mayer @ 2026-08-17 13:26 UTC (permalink / raw)
  To: netdev
  Cc: linux-kernel, dsahern, davem, edumazet, kuba, pabeni, horms,
	idosch, alex.aring, justin.iurman, bestswngs, stefano.salsano,
	xmei5, Andrea Mayer, stable

ipv6_rpl_srh_rcv() dereferences idev from __in6_dev_get() without a NULL
check when reading idev->cnf.rpl_seg_enabled.

When the device's MTU drops below IPV6_MIN_MTU, addrconf_ifdown() clears
dev->ip6_ptr through RCU_INIT_POINTER(). A packet that passed the idev
check in ip6_rcv_core() can then reach ipv6_rpl_srh_rcv() with
dev->ip6_ptr already NULL.

Reproduced by flooding the receiving interface with ping6 traffic while
flapping its MTU between 1500 and 1200:

 BUG: KASAN: null-ptr-deref in ipv6_rpl_srh_rcv+0xb3/0x1070
 Read of size 4 at addr 00000000000006b4 by task ping6/394

 CPU: 2 UID: 0 PID: 394 Comm: ping6 Not tainted 7.2.0-rc7-micro-vm-dev-00095-g24ef02f934ee #240 PREEMPT(full)
 Call Trace:
  <IRQ>
  kasan_report+0xc6/0x100
  ipv6_rpl_srh_rcv+0xb3/0x1070
  ip6_protocol_deliver_rcu+0x759/0x9a0
  ip6_input_finish+0xa8/0x1b0
  ip6_input+0xe1/0x490
  ipv6_rcv+0x33d/0x460
  __netif_receive_skb_one_core+0xd6/0x130
  process_backlog+0x2cc/0xa00
  __napi_poll.constprop.0+0x56/0x270
  net_rx_action+0x327/0x730
  handle_softirqs+0x11e/0x630
  do_softirq+0xb3/0xf0
  </IRQ>

Both ipv6_rpl_srh_rcv() and ipv6_srh_rcv() are called only from
ipv6_rthdr_rcv(), which already has an idev lookup.

Fix the NULL dereference on the RPL path by checking idev in
ipv6_rthdr_rcv(), before it calls either function. The callees take idev as
an argument and no longer call __in6_dev_get(), so the packet is now
dropped in one place, with SKB_DROP_REASON_IPV6DISABLED on both paths.

Fixes: 8610c7c6e3bd ("net: ipv6: add support for rpl sr exthdr")
Cc: stable@vger.kernel.org
Signed-off-by: Andrea Mayer <andrea.mayer@uniroma2.it>
Tested-by: Xiang Mei <xmei5@asu.edu>
---
v3:
  - move the idev NULL check into ipv6_rthdr_rcv() and use the same drop
    reason on the seg6 and RPL paths (David Ahern)
  - pass idev to ipv6_srh_rcv() and ipv6_rpl_srh_rcv(), and check it for
    NULL in ipv6_rthdr_rcv() only for the seg6 and RPL types
  - add Xiang Mei's Tested-by tag
v2: https://lore.kernel.org/netdev/20260518140630.24280-1-andrea.mayer@uniroma2.it/
  - use SKB_DROP_REASON_IPV6DISABLED as drop reason (Eric Dumazet)
v1: https://lore.kernel.org/netdev/20260428224816.11223-1-andrea.mayer@uniroma2.it/
---
 net/ipv6/exthdrs.c | 26 ++++++++++++--------------
 1 file changed, 12 insertions(+), 14 deletions(-)

diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c
index 9c677eb1d1a6..51941ad656a3 100644
--- a/net/ipv6/exthdrs.c
+++ b/net/ipv6/exthdrs.c
@@ -368,23 +368,16 @@ static void seg6_update_csum(struct sk_buff *skb)
 			   (__be32 *)addr);
 }
 
-static int ipv6_srh_rcv(struct sk_buff *skb)
+static int ipv6_srh_rcv(struct sk_buff *skb, struct inet6_dev *idev)
 {
 	struct inet6_skb_parm *opt = IP6CB(skb);
 	struct net *net = dev_net(skb->dev);
 	struct ipv6_sr_hdr *hdr;
-	struct inet6_dev *idev;
 	struct in6_addr *addr;
 	int accept_seg6;
 
 	hdr = (struct ipv6_sr_hdr *)skb_transport_header(skb);
 
-	idev = __in6_dev_get(skb->dev);
-	if (!idev) {
-		kfree_skb(skb);
-		return -1;
-	}
-
 	accept_seg6 = min(READ_ONCE(net->ipv6.devconf_all->seg6_enabled),
 			  READ_ONCE(idev->cnf.seg6_enabled));
 
@@ -485,12 +478,11 @@ static int ipv6_srh_rcv(struct sk_buff *skb)
 	return -1;
 }
 
-static int ipv6_rpl_srh_rcv(struct sk_buff *skb)
+static int ipv6_rpl_srh_rcv(struct sk_buff *skb, struct inet6_dev *idev)
 {
 	struct ipv6_rpl_sr_hdr *hdr, *ohdr, *chdr;
 	struct inet6_skb_parm *opt = IP6CB(skb);
 	struct net *net = dev_net(skb->dev);
-	struct inet6_dev *idev;
 	struct ipv6hdr *oldhdr;
 	unsigned int chdr_len;
 	unsigned char *buf;
@@ -499,8 +491,6 @@ static int ipv6_rpl_srh_rcv(struct sk_buff *skb)
 	u64 n = 0;
 	u32 r;
 
-	idev = __in6_dev_get(skb->dev);
-
 	accept_rpl_seg = min(READ_ONCE(net->ipv6.devconf_all->rpl_seg_enabled),
 			     READ_ONCE(idev->cnf.rpl_seg_enabled));
 	if (!accept_rpl_seg) {
@@ -689,10 +679,14 @@ static int ipv6_rthdr_rcv(struct sk_buff *skb)
 	switch (hdr->type) {
 	case IPV6_SRCRT_TYPE_4:
 		/* segment routing */
-		return ipv6_srh_rcv(skb);
+		if (!idev)
+			goto disabled;
+		return ipv6_srh_rcv(skb, idev);
 	case IPV6_SRCRT_TYPE_3:
 		/* rpl segment routing */
-		return ipv6_rpl_srh_rcv(skb);
+		if (!idev)
+			goto disabled;
+		return ipv6_rpl_srh_rcv(skb, idev);
 	default:
 		break;
 	}
@@ -837,6 +831,10 @@ static int ipv6_rthdr_rcv(struct sk_buff *skb)
 	icmpv6_param_prob(skb, ICMPV6_HDR_FIELD,
 			  (&hdr->type) - skb_network_header(skb));
 	return -1;
+
+disabled:
+	kfree_skb_reason(skb, SKB_DROP_REASON_IPV6DISABLED);
+	return -1;
 }
 
 static const struct inet6_protocol rthdr_protocol = {
-- 
2.43.0


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH net v3] ipv6: rpl: fix NULL dereference of idev in ipv6_rpl_srh_rcv()
  2026-08-17 13:26 [PATCH net v3] ipv6: rpl: fix NULL dereference of idev in ipv6_rpl_srh_rcv() Andrea Mayer
@ 2026-08-20 12:28 ` Simon Horman
  2026-08-20 19:30 ` patchwork-bot+netdevbpf
  2026-09-15  6:03 ` Hangbin Liu
  2 siblings, 0 replies; 5+ messages in thread
From: Simon Horman @ 2026-08-20 12:28 UTC (permalink / raw)
  To: Andrea Mayer
  Cc: netdev, linux-kernel, dsahern, davem, edumazet, kuba, pabeni,
	idosch, alex.aring, justin.iurman, bestswngs, stefano.salsano,
	xmei5, stable

On Mon, Aug 17, 2026 at 03:26:44PM +0200, Andrea Mayer wrote:
> ipv6_rpl_srh_rcv() dereferences idev from __in6_dev_get() without a NULL
> check when reading idev->cnf.rpl_seg_enabled.
> 
> When the device's MTU drops below IPV6_MIN_MTU, addrconf_ifdown() clears
> dev->ip6_ptr through RCU_INIT_POINTER(). A packet that passed the idev
> check in ip6_rcv_core() can then reach ipv6_rpl_srh_rcv() with
> dev->ip6_ptr already NULL.
> 
> Reproduced by flooding the receiving interface with ping6 traffic while
> flapping its MTU between 1500 and 1200:
> 
>  BUG: KASAN: null-ptr-deref in ipv6_rpl_srh_rcv+0xb3/0x1070
>  Read of size 4 at addr 00000000000006b4 by task ping6/394
> 
>  CPU: 2 UID: 0 PID: 394 Comm: ping6 Not tainted 7.2.0-rc7-micro-vm-dev-00095-g24ef02f934ee #240 PREEMPT(full)
>  Call Trace:
>   <IRQ>
>   kasan_report+0xc6/0x100
>   ipv6_rpl_srh_rcv+0xb3/0x1070
>   ip6_protocol_deliver_rcu+0x759/0x9a0
>   ip6_input_finish+0xa8/0x1b0
>   ip6_input+0xe1/0x490
>   ipv6_rcv+0x33d/0x460
>   __netif_receive_skb_one_core+0xd6/0x130
>   process_backlog+0x2cc/0xa00
>   __napi_poll.constprop.0+0x56/0x270
>   net_rx_action+0x327/0x730
>   handle_softirqs+0x11e/0x630
>   do_softirq+0xb3/0xf0
>   </IRQ>
> 
> Both ipv6_rpl_srh_rcv() and ipv6_srh_rcv() are called only from
> ipv6_rthdr_rcv(), which already has an idev lookup.
> 
> Fix the NULL dereference on the RPL path by checking idev in
> ipv6_rthdr_rcv(), before it calls either function. The callees take idev as
> an argument and no longer call __in6_dev_get(), so the packet is now
> dropped in one place, with SKB_DROP_REASON_IPV6DISABLED on both paths.
> 
> Fixes: 8610c7c6e3bd ("net: ipv6: add support for rpl sr exthdr")
> Cc: stable@vger.kernel.org
> Signed-off-by: Andrea Mayer <andrea.mayer@uniroma2.it>
> Tested-by: Xiang Mei <xmei5@asu.edu>
> ---
> v3:
>   - move the idev NULL check into ipv6_rthdr_rcv() and use the same drop
>     reason on the seg6 and RPL paths (David Ahern)
>   - pass idev to ipv6_srh_rcv() and ipv6_rpl_srh_rcv(), and check it for
>     NULL in ipv6_rthdr_rcv() only for the seg6 and RPL types
>   - add Xiang Mei's Tested-by tag
> v2: https://lore.kernel.org/netdev/20260518140630.24280-1-andrea.mayer@uniroma2.it/
>   - use SKB_DROP_REASON_IPV6DISABLED as drop reason (Eric Dumazet)
> v1: https://lore.kernel.org/netdev/20260428224816.11223-1-andrea.mayer@uniroma2.it/

Reviewed-by: Simon Horman <horms@kernel.org>


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH net v3] ipv6: rpl: fix NULL dereference of idev in ipv6_rpl_srh_rcv()
  2026-08-17 13:26 [PATCH net v3] ipv6: rpl: fix NULL dereference of idev in ipv6_rpl_srh_rcv() Andrea Mayer
  2026-08-20 12:28 ` Simon Horman
@ 2026-08-20 19:30 ` patchwork-bot+netdevbpf
  2026-09-15  6:03 ` Hangbin Liu
  2 siblings, 0 replies; 5+ messages in thread
From: patchwork-bot+netdevbpf @ 2026-08-20 19:30 UTC (permalink / raw)
  To: Andrea Mayer
  Cc: netdev, linux-kernel, dsahern, davem, edumazet, kuba, pabeni,
	horms, idosch, alex.aring, justin.iurman, bestswngs,
	stefano.salsano, xmei5, stable

Hello:

This patch was applied to netdev/net.git (main)
by Jakub Kicinski <kuba@kernel.org>:

On Mon, 17 Aug 2026 15:26:44 +0200 you wrote:
> ipv6_rpl_srh_rcv() dereferences idev from __in6_dev_get() without a NULL
> check when reading idev->cnf.rpl_seg_enabled.
> 
> When the device's MTU drops below IPV6_MIN_MTU, addrconf_ifdown() clears
> dev->ip6_ptr through RCU_INIT_POINTER(). A packet that passed the idev
> check in ip6_rcv_core() can then reach ipv6_rpl_srh_rcv() with
> dev->ip6_ptr already NULL.
> 
> [...]

Here is the summary with links:
  - [net,v3] ipv6: rpl: fix NULL dereference of idev in ipv6_rpl_srh_rcv()
    https://git.kernel.org/netdev/net/c/f826df95332c

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] 5+ messages in thread

* Re: [PATCH net v3] ipv6: rpl: fix NULL dereference of idev in ipv6_rpl_srh_rcv()
  2026-08-17 13:26 [PATCH net v3] ipv6: rpl: fix NULL dereference of idev in ipv6_rpl_srh_rcv() Andrea Mayer
  2026-08-20 12:28 ` Simon Horman
  2026-08-20 19:30 ` patchwork-bot+netdevbpf
@ 2026-09-15  6:03 ` Hangbin Liu
  2026-09-15 12:24   ` Hangbin Liu
  2 siblings, 1 reply; 5+ messages in thread
From: Hangbin Liu @ 2026-09-15  6:03 UTC (permalink / raw)
  To: Andrea Mayer
  Cc: netdev, linux-kernel, dsahern, davem, edumazet, kuba, pabeni,
	horms, idosch, alex.aring, justin.iurman, bestswngs,
	stefano.salsano, xmei5, stable

Hi Andrea,

While reviewing the SRv6 code, I noticed you added an `idev` check in
`ipv6_rthdr_rcv()`. I’m wondering whether it makes sense to also halt
processing for `IPV6_SRCRT_TYPE_2` when `!idev`, given that IPv6 is
disabled on that device.

If so, could we drop the skb early at the entry point of `ipv6_rthdr_rcv()`?
The downside is that subsequent processing and `__IP6_INC_STATS()` would be
skipped.

BTW, `ipv6_rthdr_rcv()` handles both `IPV6_SRCRT_TYPE_3/4` entry points and
the full `IPV6_SRCRT_TYPE_2` processing path. There are four separate
`switch (hdr->type)` blocks inside this function. I plan to refactor it for
clearer logic. Do you think this is feasible, or unnecessary?

Thanks
Hangbin
On Mon, Aug 17, 2026 at 03:26:44PM +0200, Andrea Mayer wrote:
> ipv6_rpl_srh_rcv() dereferences idev from __in6_dev_get() without a NULL
> check when reading idev->cnf.rpl_seg_enabled.
> 
> When the device's MTU drops below IPV6_MIN_MTU, addrconf_ifdown() clears
> dev->ip6_ptr through RCU_INIT_POINTER(). A packet that passed the idev
> check in ip6_rcv_core() can then reach ipv6_rpl_srh_rcv() with
> dev->ip6_ptr already NULL.
> 
> Reproduced by flooding the receiving interface with ping6 traffic while
> flapping its MTU between 1500 and 1200:
> 
>  BUG: KASAN: null-ptr-deref in ipv6_rpl_srh_rcv+0xb3/0x1070
>  Read of size 4 at addr 00000000000006b4 by task ping6/394
> 
>  CPU: 2 UID: 0 PID: 394 Comm: ping6 Not tainted 7.2.0-rc7-micro-vm-dev-00095-g24ef02f934ee #240 PREEMPT(full)
>  Call Trace:
>   <IRQ>
>   kasan_report+0xc6/0x100
>   ipv6_rpl_srh_rcv+0xb3/0x1070
>   ip6_protocol_deliver_rcu+0x759/0x9a0
>   ip6_input_finish+0xa8/0x1b0
>   ip6_input+0xe1/0x490
>   ipv6_rcv+0x33d/0x460
>   __netif_receive_skb_one_core+0xd6/0x130
>   process_backlog+0x2cc/0xa00
>   __napi_poll.constprop.0+0x56/0x270
>   net_rx_action+0x327/0x730
>   handle_softirqs+0x11e/0x630
>   do_softirq+0xb3/0xf0
>   </IRQ>
> 
> Both ipv6_rpl_srh_rcv() and ipv6_srh_rcv() are called only from
> ipv6_rthdr_rcv(), which already has an idev lookup.
> 
> Fix the NULL dereference on the RPL path by checking idev in
> ipv6_rthdr_rcv(), before it calls either function. The callees take idev as
> an argument and no longer call __in6_dev_get(), so the packet is now
> dropped in one place, with SKB_DROP_REASON_IPV6DISABLED on both paths.
> 
> Fixes: 8610c7c6e3bd ("net: ipv6: add support for rpl sr exthdr")
> Cc: stable@vger.kernel.org
> Signed-off-by: Andrea Mayer <andrea.mayer@uniroma2.it>
> Tested-by: Xiang Mei <xmei5@asu.edu>
> ---
> v3:
>   - move the idev NULL check into ipv6_rthdr_rcv() and use the same drop
>     reason on the seg6 and RPL paths (David Ahern)
>   - pass idev to ipv6_srh_rcv() and ipv6_rpl_srh_rcv(), and check it for
>     NULL in ipv6_rthdr_rcv() only for the seg6 and RPL types
>   - add Xiang Mei's Tested-by tag
> v2: https://lore.kernel.org/netdev/20260518140630.24280-1-andrea.mayer@uniroma2.it/
>   - use SKB_DROP_REASON_IPV6DISABLED as drop reason (Eric Dumazet)
> v1: https://lore.kernel.org/netdev/20260428224816.11223-1-andrea.mayer@uniroma2.it/
> ---
>  net/ipv6/exthdrs.c | 26 ++++++++++++--------------
>  1 file changed, 12 insertions(+), 14 deletions(-)
> 
> diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c
> index 9c677eb1d1a6..51941ad656a3 100644
> --- a/net/ipv6/exthdrs.c
> +++ b/net/ipv6/exthdrs.c
> @@ -368,23 +368,16 @@ static void seg6_update_csum(struct sk_buff *skb)
>  			   (__be32 *)addr);
>  }
>  
> -static int ipv6_srh_rcv(struct sk_buff *skb)
> +static int ipv6_srh_rcv(struct sk_buff *skb, struct inet6_dev *idev)
>  {
>  	struct inet6_skb_parm *opt = IP6CB(skb);
>  	struct net *net = dev_net(skb->dev);
>  	struct ipv6_sr_hdr *hdr;
> -	struct inet6_dev *idev;
>  	struct in6_addr *addr;
>  	int accept_seg6;
>  
>  	hdr = (struct ipv6_sr_hdr *)skb_transport_header(skb);
>  
> -	idev = __in6_dev_get(skb->dev);
> -	if (!idev) {
> -		kfree_skb(skb);
> -		return -1;
> -	}
> -
>  	accept_seg6 = min(READ_ONCE(net->ipv6.devconf_all->seg6_enabled),
>  			  READ_ONCE(idev->cnf.seg6_enabled));
>  
> @@ -485,12 +478,11 @@ static int ipv6_srh_rcv(struct sk_buff *skb)
>  	return -1;
>  }
>  
> -static int ipv6_rpl_srh_rcv(struct sk_buff *skb)
> +static int ipv6_rpl_srh_rcv(struct sk_buff *skb, struct inet6_dev *idev)
>  {
>  	struct ipv6_rpl_sr_hdr *hdr, *ohdr, *chdr;
>  	struct inet6_skb_parm *opt = IP6CB(skb);
>  	struct net *net = dev_net(skb->dev);
> -	struct inet6_dev *idev;
>  	struct ipv6hdr *oldhdr;
>  	unsigned int chdr_len;
>  	unsigned char *buf;
> @@ -499,8 +491,6 @@ static int ipv6_rpl_srh_rcv(struct sk_buff *skb)
>  	u64 n = 0;
>  	u32 r;
>  
> -	idev = __in6_dev_get(skb->dev);
> -
>  	accept_rpl_seg = min(READ_ONCE(net->ipv6.devconf_all->rpl_seg_enabled),
>  			     READ_ONCE(idev->cnf.rpl_seg_enabled));
>  	if (!accept_rpl_seg) {
> @@ -689,10 +679,14 @@ static int ipv6_rthdr_rcv(struct sk_buff *skb)
>  	switch (hdr->type) {
>  	case IPV6_SRCRT_TYPE_4:
>  		/* segment routing */
> -		return ipv6_srh_rcv(skb);
> +		if (!idev)
> +			goto disabled;
> +		return ipv6_srh_rcv(skb, idev);
>  	case IPV6_SRCRT_TYPE_3:
>  		/* rpl segment routing */
> -		return ipv6_rpl_srh_rcv(skb);
> +		if (!idev)
> +			goto disabled;
> +		return ipv6_rpl_srh_rcv(skb, idev);
>  	default:
>  		break;
>  	}
> @@ -837,6 +831,10 @@ static int ipv6_rthdr_rcv(struct sk_buff *skb)
>  	icmpv6_param_prob(skb, ICMPV6_HDR_FIELD,
>  			  (&hdr->type) - skb_network_header(skb));
>  	return -1;
> +
> +disabled:
> +	kfree_skb_reason(skb, SKB_DROP_REASON_IPV6DISABLED);
> +	return -1;
>  }
>  
>  static const struct inet6_protocol rthdr_protocol = {
> -- 
> 2.43.0
> 

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH net v3] ipv6: rpl: fix NULL dereference of idev in ipv6_rpl_srh_rcv()
  2026-09-15  6:03 ` Hangbin Liu
@ 2026-09-15 12:24   ` Hangbin Liu
  0 siblings, 0 replies; 5+ messages in thread
From: Hangbin Liu @ 2026-09-15 12:24 UTC (permalink / raw)
  To: Andrea Mayer
  Cc: netdev, linux-kernel, dsahern, davem, edumazet, kuba, pabeni,
	horms, idosch, alex.aring, justin.iurman, bestswngs,
	stefano.salsano, xmei5, stable

On Tue, Sep 15, 2026 at 02:03:12PM +0800, Hangbin Liu wrote:
> Hi Andrea,
> 
> While reviewing the SRv6 code, I noticed you added an `idev` check in
> `ipv6_rthdr_rcv()`. I’m wondering whether it makes sense to also halt
> processing for `IPV6_SRCRT_TYPE_2` when `!idev`, given that IPv6 is
> disabled on that device.
> 
> If so, could we drop the skb early at the entry point of `ipv6_rthdr_rcv()`?
> The downside is that subsequent processing and `__IP6_INC_STATS()` would be
> skipped.

Oh, another behavior change. At present, if !idev, we can still process the
IPV6_SRCRT_TYPE_2 message. And the process will be skipped if we return early.
I'm not sure if this kind of change is acceptable or not in kernel.

But on the other hand, is it correct to accept and forward SRCRT Type 2
packets on device that IPv6 is disabled?

Thanks
Hangbin

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2026-09-15 12:24 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-08-17 13:26 [PATCH net v3] ipv6: rpl: fix NULL dereference of idev in ipv6_rpl_srh_rcv() Andrea Mayer
2026-08-20 12:28 ` Simon Horman
2026-08-20 19:30 ` patchwork-bot+netdevbpf
2026-09-15  6:03 ` Hangbin Liu
2026-09-15 12:24   ` Hangbin Liu

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®