* [PATCH net v2] ipv6: raw: fix use-after-free in rawv6_send_hdrinc()
@ 2026-10-26 4:48 Zhou Qiuyue
2026-10-26 6:09 ` Hangbin Liu
2026-10-28 7:50 ` netdev-bot+sashiko
0 siblings, 2 replies; 8+ messages in thread
From: Zhou Qiuyue @ 2026-10-26 4:48 UTC (permalink / raw)
To: netdev
Cc: David Ahern, Ido Schimmel, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Hangbin Liu,
linux-kernel, stable
rawv6_send_hdrinc() caches the route before handing the skb to
l3mdev_ip6_out(). The VRF output path may replace skb->dst and release
the original route, leaving the cached pointer stale.
The function later dereferences that pointer for statistics accounting
and as the output device passed to NF_HOOK(). Its RCU read-side critical
section starts after l3mdev_ip6_out(), so it cannot prevent the old route
from being reclaimed in between.
Reload the route from the current skb destination after
l3mdev_ip6_out() returns.
KASAN reports a slab-use-after-free in rawv6_sendmsg(), with the route
allocated by ip6_dst_alloc(), freed by dst_destroy() from rcu_core(), and
the related RCU callback queued from vrf_l3_out().
Fixes: 4c1feac58e06 ("net: vrf: Flip IPv6 output path from FIB lookup hook to out hook")
Cc: stable@vger.kernel.org
Signed-off-by: Zhou Qiuyue <n0ps1edzz@gmail.com>
---
Changes in v2:
- Rebased onto the current net tree at 7076f684d513.
- Regenerated the patch with git-format-patch so it applies cleanly.
- Corrected the Fixes tag to the commit that made the IPv6 VRF path reachable.
- Shortened the code comment and added the required recipients.
v1: https://lore.kernel.org/r/6adad51d.8fc0b0c9.1ec657.1868@mx.google.com
Thank you to Hangbin Liu for reviewing v1 and pointing out the submission
issues.
net/ipv6/raw.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c
index b965258cf..bdea82543 100644
--- a/net/ipv6/raw.c
+++ b/net/ipv6/raw.c
@@ -654,6 +654,9 @@ static int rawv6_send_hdrinc(struct sock *sk, struct msghdr *msg, int length,
if (unlikely(!skb))
return 0;
+ /* l3mdev_ip6_out() may have replaced the skb dst. */
+ rt = dst_rt6_info(skb_dst(skb));
+
/* Acquire rcu_read_lock() in case we need to use rt->rt6i_idev
* in the error path. Since skb has been freed, the dst could
* have been queued for deletion.
base-commit: 7076f684d5132e6a6145e1da2fa74771ecd052e5
--
2.50.1.windows.1
^ permalink raw reply related [flat|nested] 8+ messages in thread* Re: [PATCH net v2] ipv6: raw: fix use-after-free in rawv6_send_hdrinc() 2026-10-26 4:48 [PATCH net v2] ipv6: raw: fix use-after-free in rawv6_send_hdrinc() Zhou Qiuyue @ 2026-10-26 6:09 ` Hangbin Liu 2026-10-26 15:07 ` Antoine Tenart 2026-10-28 7:50 ` netdev-bot+sashiko 1 sibling, 1 reply; 8+ messages in thread From: Hangbin Liu @ 2026-10-26 6:09 UTC (permalink / raw) To: Zhou Qiuyue Cc: netdev, David Ahern, Ido Schimmel, David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni, Simon Horman, linux-kernel, stable On Mon, Oct 26, 2026 at 12:48:08PM +0800, Zhou Qiuyue wrote: > rawv6_send_hdrinc() caches the route before handing the skb to > l3mdev_ip6_out(). The VRF output path may replace skb->dst and release > the original route, leaving the cached pointer stale. > > The function later dereferences that pointer for statistics accounting > and as the output device passed to NF_HOOK(). Its RCU read-side critical > section starts after l3mdev_ip6_out(), so it cannot prevent the old route > from being reclaimed in between. > > Reload the route from the current skb destination after > l3mdev_ip6_out() returns. > > KASAN reports a slab-use-after-free in rawv6_sendmsg(), with the route > allocated by ip6_dst_alloc(), freed by dst_destroy() from rcu_core(), and > the related RCU callback queued from vrf_l3_out(). > > Fixes: 4c1feac58e06 ("net: vrf: Flip IPv6 output path from FIB lookup hook to out hook") > Cc: stable@vger.kernel.org > Signed-off-by: Zhou Qiuyue <n0ps1edzz@gmail.com> > --- > Changes in v2: > - Rebased onto the current net tree at 7076f684d513. > - Regenerated the patch with git-format-patch so it applies cleanly. > - Corrected the Fixes tag to the commit that made the IPv6 VRF path reachable. > - Shortened the code comment and added the required recipients. > > v1: https://lore.kernel.org/r/6adad51d.8fc0b0c9.1ec657.1868@mx.google.com > > Thank you to Hangbin Liu for reviewing v1 and pointing out the submission > issues. > > net/ipv6/raw.c | 3 +++ > 1 file changed, 3 insertions(+) > > diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c > index b965258cf..bdea82543 100644 > --- a/net/ipv6/raw.c > +++ b/net/ipv6/raw.c > @@ -654,6 +654,9 @@ static int rawv6_send_hdrinc(struct sock *sk, struct msghdr *msg, int length, > if (unlikely(!skb)) > return 0; > > + /* l3mdev_ip6_out() may have replaced the skb dst. */ > + rt = dst_rt6_info(skb_dst(skb)); > + > /* Acquire rcu_read_lock() in case we need to use rt->rt6i_idev > * in the error path. Since skb has been freed, the dst could > * have been queued for deletion. > > base-commit: 7076f684d5132e6a6145e1da2fa74771ecd052e5 > -- > 2.50.1.windows.1 > Reviewed-by: Hangbin Liu <liuhangbin@kylinos.cn> ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH net v2] ipv6: raw: fix use-after-free in rawv6_send_hdrinc() 2026-10-26 6:09 ` Hangbin Liu @ 2026-10-26 15:07 ` Antoine Tenart 2026-10-27 1:38 ` Hangbin Liu 0 siblings, 1 reply; 8+ messages in thread From: Antoine Tenart @ 2026-10-26 15:07 UTC (permalink / raw) To: Hangbin Liu Cc: Zhou Qiuyue, netdev, David Ahern, Ido Schimmel, David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni, Simon Horman, linux-kernel, stable On Mon, Oct 26, 2026 at 02:09:23PM +0800, Hangbin Liu wrote: > On Mon, Oct 26, 2026 at 12:48:08PM +0800, Zhou Qiuyue wrote: > > diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c > > index b965258cf..bdea82543 100644 > > --- a/net/ipv6/raw.c > > +++ b/net/ipv6/raw.c > > @@ -654,6 +654,9 @@ static int rawv6_send_hdrinc(struct sock *sk, struct msghdr *msg, int length, > > if (unlikely(!skb)) > > return 0; > > > > + /* l3mdev_ip6_out() may have replaced the skb dst. */ > > + rt = dst_rt6_info(skb_dst(skb)); > > + > > /* Acquire rcu_read_lock() in case we need to use rt->rt6i_idev > > * in the error path. Since skb has been freed, the dst could > > * have been queued for deletion. > > Reviewed-by: Hangbin Liu <liuhangbin@kylinos.cn> Doesn't this change the device seen by the nf hook / used for the stats? ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH net v2] ipv6: raw: fix use-after-free in rawv6_send_hdrinc() 2026-10-26 15:07 ` Antoine Tenart @ 2026-10-27 1:38 ` Hangbin Liu 2026-10-27 9:43 ` Antoine Tenart 0 siblings, 1 reply; 8+ messages in thread From: Hangbin Liu @ 2026-10-27 1:38 UTC (permalink / raw) To: Antoine Tenart Cc: Zhou Qiuyue, netdev, David Ahern, Ido Schimmel, David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni, Simon Horman, linux-kernel, stable On Mon, Oct 26, 2026 at 04:07:40PM +0100, Antoine Tenart wrote: > On Mon, Oct 26, 2026 at 02:09:23PM +0800, Hangbin Liu wrote: > > On Mon, Oct 26, 2026 at 12:48:08PM +0800, Zhou Qiuyue wrote: > > > diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c > > > index b965258cf..bdea82543 100644 > > > --- a/net/ipv6/raw.c > > > +++ b/net/ipv6/raw.c > > > @@ -654,6 +654,9 @@ static int rawv6_send_hdrinc(struct sock *sk, struct msghdr *msg, int length, > > > if (unlikely(!skb)) > > > return 0; > > > > > > + /* l3mdev_ip6_out() may have replaced the skb dst. */ > > > + rt = dst_rt6_info(skb_dst(skb)); > > > + > > > /* Acquire rcu_read_lock() in case we need to use rt->rt6i_idev > > > * in the error path. Since skb has been freed, the dst could > > > * have been queued for deletion. > > > > Reviewed-by: Hangbin Liu <liuhangbin@kylinos.cn> > > Doesn't this change the device seen by the nf hook / used for the stats? Should we still use the old/released rt->dst.dev after the VRF output path replace skb->dst? vrf_ip6_out_redirect() said it allows the nf hook use vrf device. Thanks Hangbin ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH net v2] ipv6: raw: fix use-after-free in rawv6_send_hdrinc() 2026-10-27 1:38 ` Hangbin Liu @ 2026-10-27 9:43 ` Antoine Tenart 2026-10-28 1:27 ` Hangbin Liu 0 siblings, 1 reply; 8+ messages in thread From: Antoine Tenart @ 2026-10-27 9:43 UTC (permalink / raw) To: Hangbin Liu Cc: Zhou Qiuyue, netdev, David Ahern, Ido Schimmel, David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni, Simon Horman, linux-kernel, stable On Tue, Oct 27, 2026 at 09:38:34AM +0800, Hangbin Liu wrote: > On Mon, Oct 26, 2026 at 04:07:40PM +0100, Antoine Tenart wrote: > > On Mon, Oct 26, 2026 at 02:09:23PM +0800, Hangbin Liu wrote: > > > On Mon, Oct 26, 2026 at 12:48:08PM +0800, Zhou Qiuyue wrote: > > > > diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c > > > > index b965258cf..bdea82543 100644 > > > > --- a/net/ipv6/raw.c > > > > +++ b/net/ipv6/raw.c > > > > @@ -654,6 +654,9 @@ static int rawv6_send_hdrinc(struct sock *sk, struct msghdr *msg, int length, > > > > if (unlikely(!skb)) > > > > return 0; > > > > > > > > + /* l3mdev_ip6_out() may have replaced the skb dst. */ > > > > + rt = dst_rt6_info(skb_dst(skb)); > > > > + > > > > /* Acquire rcu_read_lock() in case we need to use rt->rt6i_idev > > > > * in the error path. Since skb has been freed, the dst could > > > > * have been queued for deletion. > > > > > > Reviewed-by: Hangbin Liu <liuhangbin@kylinos.cn> > > > > Doesn't this change the device seen by the nf hook / used for the stats? > > Should we still use the old/released rt->dst.dev after the VRF output > path replace skb->dst? vrf_ip6_out_redirect() said it allows the nf hook > use vrf device. Right, but then in the direct path the NF_INET_LOCAL_OUT hook would be run twice with the same dev. Looking at other call sites for l3mdev_ip6_out, it's not clear either, __ip6_local_out reloads the dev while ip6_xmit does not. I'm not sure what is the expected behavior. Regardless of that, the change in behavior (if right) would be worth mentioning in the commit log. ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH net v2] ipv6: raw: fix use-after-free in rawv6_send_hdrinc() 2026-10-27 9:43 ` Antoine Tenart @ 2026-10-28 1:27 ` Hangbin Liu 2026-10-28 14:37 ` David Ahern 0 siblings, 1 reply; 8+ messages in thread From: Hangbin Liu @ 2026-10-28 1:27 UTC (permalink / raw) To: Antoine Tenart, David Ahern Cc: Zhou Qiuyue, netdev, Ido Schimmel, David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni, Simon Horman, linux-kernel, stable On Tue, Oct 27, 2026 at 10:43:48AM +0100, Antoine Tenart wrote: > On Tue, Oct 27, 2026 at 09:38:34AM +0800, Hangbin Liu wrote: > > On Mon, Oct 26, 2026 at 04:07:40PM +0100, Antoine Tenart wrote: > > > On Mon, Oct 26, 2026 at 02:09:23PM +0800, Hangbin Liu wrote: > > > > On Mon, Oct 26, 2026 at 12:48:08PM +0800, Zhou Qiuyue wrote: > > > > > diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c > > > > > index b965258cf..bdea82543 100644 > > > > > --- a/net/ipv6/raw.c > > > > > +++ b/net/ipv6/raw.c > > > > > @@ -654,6 +654,9 @@ static int rawv6_send_hdrinc(struct sock *sk, struct msghdr *msg, int length, > > > > > if (unlikely(!skb)) > > > > > return 0; > > > > > > > > > > + /* l3mdev_ip6_out() may have replaced the skb dst. */ > > > > > + rt = dst_rt6_info(skb_dst(skb)); > > > > > + > > > > > /* Acquire rcu_read_lock() in case we need to use rt->rt6i_idev > > > > > * in the error path. Since skb has been freed, the dst could > > > > > * have been queued for deletion. > > > > > > > > Reviewed-by: Hangbin Liu <liuhangbin@kylinos.cn> > > > > > > Doesn't this change the device seen by the nf hook / used for the stats? > > > > Should we still use the old/released rt->dst.dev after the VRF output > > path replace skb->dst? vrf_ip6_out_redirect() said it allows the nf hook > > use vrf device. > > Right, but then in the direct path the NF_INET_LOCAL_OUT hook would be > run twice with the same dev. Looking at other call sites for > l3mdev_ip6_out, it's not clear either, __ip6_local_out reloads the dev > while ip6_xmit does not. I'm not sure what is the expected behavior. Hmm, me neither. David might know. Thanks Hangbin > > Regardless of that, the change in behavior (if right) would be worth > mentioning in the commit log. ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH net v2] ipv6: raw: fix use-after-free in rawv6_send_hdrinc() 2026-10-28 1:27 ` Hangbin Liu @ 2026-10-28 14:37 ` David Ahern 0 siblings, 0 replies; 8+ messages in thread From: David Ahern @ 2026-10-28 14:37 UTC (permalink / raw) To: Hangbin Liu, Antoine Tenart Cc: Zhou Qiuyue, netdev, Ido Schimmel, David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni, Simon Horman, linux-kernel, stable On 10/27/26 7:27 PM, Hangbin Liu wrote: > On Tue, Oct 27, 2026 at 10:43:48AM +0100, Antoine Tenart wrote: >> On Tue, Oct 27, 2026 at 09:38:34AM +0800, Hangbin Liu wrote: >>> On Mon, Oct 26, 2026 at 04:07:40PM +0100, Antoine Tenart wrote: >>>> On Mon, Oct 26, 2026 at 02:09:23PM +0800, Hangbin Liu wrote: >>>>> On Mon, Oct 26, 2026 at 12:48:08PM +0800, Zhou Qiuyue wrote: >>>>>> diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c >>>>>> index b965258cf..bdea82543 100644 >>>>>> --- a/net/ipv6/raw.c >>>>>> +++ b/net/ipv6/raw.c >>>>>> @@ -654,6 +654,9 @@ static int rawv6_send_hdrinc(struct sock *sk, struct msghdr *msg, int length, >>>>>> if (unlikely(!skb)) >>>>>> return 0; >>>>>> >>>>>> + /* l3mdev_ip6_out() may have replaced the skb dst. */ >>>>>> + rt = dst_rt6_info(skb_dst(skb)); >>>>>> + >>>>>> /* Acquire rcu_read_lock() in case we need to use rt->rt6i_idev >>>>>> * in the error path. Since skb has been freed, the dst could >>>>>> * have been queued for deletion. >>>>> >>>>> Reviewed-by: Hangbin Liu <liuhangbin@kylinos.cn> >>>> >>>> Doesn't this change the device seen by the nf hook / used for the stats? >>> >>> Should we still use the old/released rt->dst.dev after the VRF output >>> path replace skb->dst? vrf_ip6_out_redirect() said it allows the nf hook >>> use vrf device. >> >> Right, but then in the direct path the NF_INET_LOCAL_OUT hook would be >> run twice with the same dev. Looking at other call sites for >> l3mdev_ip6_out, it's not clear either, __ip6_local_out reloads the dev >> while ip6_xmit does not. I'm not sure what is the expected behavior. > > Hmm, me neither. David might know. > I do not recall the original behavior; that was many years ago. ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH net v2] ipv6: raw: fix use-after-free in rawv6_send_hdrinc() 2026-10-26 4:48 [PATCH net v2] ipv6: raw: fix use-after-free in rawv6_send_hdrinc() Zhou Qiuyue 2026-10-26 6:09 ` Hangbin Liu @ 2026-10-28 7:50 ` netdev-bot+sashiko 1 sibling, 0 replies; 8+ messages in thread From: netdev-bot+sashiko @ 2026-10-28 7:50 UTC (permalink / raw) To: n0ps1edzz Cc: netdev, dsahern, idosch, davem, edumazet, kuba, pabeni, horms, hangbin.liu, linux-kernel, stable Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider. Critical: 0 · High: 0 · Medium: 1 · Low: 0 If you believe none of the issues are legitimate, please reply to each issue of Medium severity or higher and explain why the AI is wrong. If any of them are legitimate and you plan to respin, please let patchwork know by including "pw-bot: cr" as a separate line at the end of your reply (one such reply per series is enough). - [Medium] In VRF redirect mode, rawv6_send_hdrinc() (net/ipv6/raw.c) no longer charges per-interface IPv6 SNMP counters to the slave interface. -- ipv6: raw: fix use-after-free in rawv6_send_hdrinc() This patch reloads rt from skb_dst(skb) after l3mdev_ip6_out() returns in rawv6_send_hdrinc(). The VRF output path can replace the skb dst and release the original route, which leaves the cached pointer stale. It fixes a KASAN slab-use-after-free reported in rawv6_sendmsg(). > diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c > index b965258cf9e5f..bdea825434ea7 100644 > --- a/net/ipv6/raw.c > +++ b/net/ipv6/raw.c > @@ -654,6 +654,9 @@ static int rawv6_send_hdrinc(struct sock *sk, struct msghdr *msg, int length, > if (unlikely(!skb)) > return 0; > > + /* l3mdev_ip6_out() may have replaced the skb dst. */ > + rt = dst_rt6_info(skb_dst(skb)); > + [Severity: Medium] Does this reload move the per-interface IPv6 counters off the slave device in VRF redirect mode? When the VRF device has a non-default qdisc and the packet is not xfrm-transformed, vrf_ip6_out() calls vrf_ip6_out_redirect(), which swaps in the VRF's private route: drivers/net/vrf.c:vrf_ip6_out_redirect() { ... skb_dst_drop(skb); skb_dst_set(skb, &rt6->dst); ... } That vrf->rt6 comes from ip6_dst_alloc() in vrf_rt6_create(). rt6_info_init() zeroes everything after dst, and rt6i_idev is never set afterwards. So after this reload, rt->rt6i_idev is NULL when the function gets here: IP6_INC_STATS(net, rt->rt6i_idev, IPSTATS_MIB_OUTREQUESTS); ... IP6_INC_STATS(net, rt->rt6i_idev, IPSTATS_MIB_OUTDISCARDS); _DEVINC handles a NULL idev by skipping the per-device counter, so this does not crash. Only the netns-wide counter gets bumped. The second LOCAL_OUT pass in vrf_process_v6_outbound()->vrf_ip6_local_out() does no OUTREQUESTS accounting either. As a result, raw IPV6_HDRINCL packets sent on a VRF slave in this mode would not show up in /proc/net/dev_snmp6/<slave> Ip6OutRequests or Ip6OutDiscards, and no other device counts them. The other IPv6 senders count OUTREQUESTS against the original route's idev before the l3mdev diversion. ip6_xmit() does it before l3mdev_ip6_out(). __ip6_make_skb() does it before ip6_local_out(), and that covers raw sockets without HDRINCL too. Would it work to follow the ip6_xmit() pattern instead? That means taking rcu_read_lock() before l3mdev_ip6_out() and counting OUTREQUESTS while the skb still holds its reference on the original rt. dst_release() frees through call_rcu_hurry(dst_destroy_rcu), and that callback is also where rt6i_idev is dropped. So the original rt and its idev should stay valid inside the read-side section. This would fix the use-after-free without changing which device gets the stats. > /* Acquire rcu_read_lock() in case we need to use rt->rt6i_idev > * in the error path. Since skb has been freed, the dst could > * have been queued for deletion. -- Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20261026044808.613-1-n0ps1edzz%40gmail.com ^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2026-10-28 14:37 UTC | newest] Thread overview: 8+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-10-26 4:48 [PATCH net v2] ipv6: raw: fix use-after-free in rawv6_send_hdrinc() Zhou Qiuyue 2026-10-26 6:09 ` Hangbin Liu 2026-10-26 15:07 ` Antoine Tenart 2026-10-27 1:38 ` Hangbin Liu 2026-10-27 9:43 ` Antoine Tenart 2026-10-28 1:27 ` Hangbin Liu 2026-10-28 14:37 ` David Ahern 2026-10-28 7:50 ` netdev-bot+sashiko
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox