* [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 [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-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
* 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
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
all inboxes | Powered by JetHome®