[PATCH] ipv6: icmp: use skb_dst_dev_net_rcu() for echo reply and unreach

From: Haoran Wang

Date: Mon Oct 19 2026 - 09:25:42 EST


ip6_err_gen_icmpv6_unreach() and icmpv6_echo_reply() derive the network
namespace from the ingress device with dev_net_rcu(skb->dev).

/* ip6_err_gen_icmpv6_unreach, net/ipv6/icmp.c:885 */
rt = rt6_lookup(dev_net_rcu(skb->dev), &ipv6_hdr(skb2)->saddr, ...);

/* icmpv6_echo_reply, net/ipv6/icmp.c:923 */
struct net *net = dev_net_rcu(skb->dev);

Under a VRF, skb->dev is the VRF master device, so dev_net_rcu(skb->dev)
returns the netns of the master rather than the netns the packet is
destined to. The route lookup for the unreach and the send policy for
the echo reply (ratelimit, IPsec, route) then run against the wrong
namespace. The rt6_lookup may miss the route to the source, leaving
skb2->dev unset, and the echo reply is emitted/routed per the ingress
netns instead of the destination netns.

The IPv4 ICMP echo path already uses the destination netns via
skb_dst_dev_net_rcu(skb) (net/ipv4/icmp.c:1123 and :1267), and the IPv6
echo path still uses dev_net_rcu(skb->dev).

Use skb_dst_dev_net_rcu(skb) at both IPv6 sites so the namespace is
taken from the skb destination, matching the IPv4 path.

Signed-off-by: Haoran Wang <haoranwangsec@xxxxxxxxx>
---
net/ipv6/icmp.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c
index efb23807a..de4f39ca0 100644
--- a/net/ipv6/icmp.c
+++ b/net/ipv6/icmp.c
@@ -882,7 +882,7 @@ int ip6_err_gen_icmpv6_unreach(struct sk_buff *skb, int nhs, int type,
skb_pull(skb2, nhs);
skb_reset_network_header(skb2);

- rt = rt6_lookup(dev_net_rcu(skb->dev), &ipv6_hdr(skb2)->saddr,
+ rt = rt6_lookup(skb_dst_dev_net_rcu(skb), &ipv6_hdr(skb2)->saddr,
NULL, 0, skb, 0);

if (rt && rt->dst.dev)
@@ -920,7 +920,7 @@ EXPORT_SYMBOL(ip6_err_gen_icmpv6_unreach);

static enum skb_drop_reason icmpv6_echo_reply(struct sk_buff *skb)
{
- struct net *net = dev_net_rcu(skb->dev);
+ struct net *net = skb_dst_dev_net_rcu(skb);
struct sock *sk;
struct inet6_dev *idev;
struct ipv6_pinfo *np;