FAILED: patch "[PATCH] ipv6: rpl: fix NULL dereference of idev in ipv6_rpl_srh_rcv()" failed to apply to 6.12-stable tree
Subsystems (3)
[email protected]
maintainerThe patch below does not apply to the 6.12-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
To reproduce the conflict and resubmit, you may use the following commands:
git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-6.12.y
git checkout FETCH_HEAD
git cherry-pick -x f826df95332c07380206dbd54178b6eefb311aba
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2026090349-gone-tricky-59ac@gregkh' --subject-prefix 'PATCH 6.12.y' 'HEAD^..'
Possible dependencies:
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From f826df95332c07380206dbd54178b6eefb311aba Mon Sep 17 00:00:00 2001
From: Andrea Mayer <[email protected]>
Date: Mon, 17 Aug 2026 15:26:44 +0200
Subject: [PATCH] ipv6: rpl: fix NULL dereference of idev in ipv6_rpl_srh_rcv()
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.
net/ipv6/exthdrs.c +12 -14
@@ -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 = {
Sasha Levin
maintainerPATCH 1/2 ipv6: annotate data-races around devconf->rpl_seg_enabled
From: Yue Haibing <[email protected]>
[ Upstream commit 3a5f55500f3e93cf4d62351c753452279b088b4b ]
devconf->rpl_seg_enabled can be changed concurrently from /proc/sys/net/ipv6/conf, annotate lockless reads on it.
Stable-dep-of: f826df95332c ("ipv6: rpl: fix NULL dereference of idev in ipv6_rpl_srh_rcv()")
--- net/ipv6/exthdrs.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-)
net/ipv6/exthdrs.c +2 -4
@@ -504,10 +504,8 @@ static int ipv6_rpl_srh_rcv(struct sk_buff *skb) idev =__in6_dev_get (skb->dev); - accept_rpl_seg = net->ipv6.devconf_all->rpl_seg_enabled; -if (accept_rpl_seg > idev->cnf.rpl_seg_enabled) - accept_rpl_seg = idev->cnf.rpl_seg_enabled; - + accept_rpl_seg =min (READ_ONCE (net->ipv6.devconf_all->rpl_seg_enabled), +READ_ONCE (idev->cnf.rpl_seg_enabled));if (!accept_rpl_seg) {kfree_skb (skb);return -1 ;
Signature · 1 line
2.53.0
Sasha Levin
maintainerPATCH 2/2 ipv6: rpl: fix NULL dereference of idev in ipv6_rpl_srh_rcv()
From: Andrea Mayer <[email protected]>
[ Upstream commit f826df95332c07380206dbd54178b6eefb311aba ]
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.
--- net/ipv6/exthdrs.c | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-)
net/ipv6/exthdrs.c +12 -14
@@ -371,23 +371,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));
@@ -488,12 +481,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;
@@ -502,8 +494,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) {
@@ -692,10 +682,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 ; }
@@ -840,6 +834,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 = {
Signature · 1 line
2.53.0