CVE-2026-46120
Description
In the Linux kernel, the following vulnerability has been resolved:
ip6_gre: Use cached t->net in ip6erspan_changelink().
After commit 5e72ce3e3980 ("net: ipv6: Use link netns in newlink() of rtnl_link_ops"), ip6erspan_newlink() correctly resolves the per-netns ip6gre hash via link_net. ip6erspan_changelink() was not converted in that series and still uses dev_net(dev), which diverges from the device's creation netns after IFLA_NET_NS_FD migration.
This re-inserts the tunnel into the wrong per-netns hash. The original netns keeps a stale entry. When that netns is later destroyed, ip6gre_exit_rtnl_net() walks the stale entry, producing a slab-use-after-free reported by KASAN, followed by a kernel BUG at net/core/dev.c (LIST_POISON1) in unregister_netdevice_many_notify().
Reachable from an unprivileged user namespace (unshare --user --map-root-user --net).
ip6gre_changelink() earlier in the same file already uses the cached t->net; only ip6erspan_changelink() has the wrong shape.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
A use-after-free in Linux ip6erspan_changelink() when a GRE tunnel is migrated between network namespaces, allowing local privilege escalation.
Vulnerability
In the Linux kernel, a use-after-free vulnerability exists in ip6erspan_changelink() within the ip6_gre module. The function uses dev_net(dev) to resolve the per-netns hash table instead of the cached t->net. This diverges from the corrected behavior introduced in commit 5e72ce3e3980 for ip6erspan_newlink(). After a tunnel device is moved between network namespaces via IFLA_NET_NS_FD, the change link operation re‑inserts the tunnel into the wrong per-netns hash, causing a stale entry in the original namespace. Affected versions include all kernels up to the point where the fix (commit cf7fc624329e) is applied [1].
Exploitation
An attacker must have the ability to create a network namespace and an ERSPAN GRE tunnel, then migrate that tunnel to another namespace. This is reachable from an unprivileged user namespace created with unshare --user --map-root-user --net. The attacker triggers ip6erspan_changelink() (e.g., via ip link set), which uses the wrong netns to look up or re‑insert the tunnel. After the original netns is destroyed, the stale entry remains. No additional authentication or special capabilities are required beyond the ability to create a user and network namespace [1].
Impact
When the original network namespace is later destroyed, the kernel walks the stale entry in ip6gre_exit_rtnl_net(). This results in a slab‑use‑after‑free, producing a KASAN report, followed by a kernel BUG at net/core/dev.c (LIST_POISON1) in unregister_netdevice_many_notify(). An attacker can potentially exploit the use‑after‑free to escalate privileges from an unprivileged user namespace to full kernel code execution, as the vulnerability corrupts kernel memory [1].
Mitigation
The fix is present in commit cf7fc624329e76c6394653d12353e1d033adea91 of the Linux kernel stable tree. This commit changes ip6erspan_changelink() to use the cached t->net instead of dev_net(dev). Users should apply the latest stable kernel update that includes this patch. No workaround is available; the only mitigation is to apply the kernel fix. The vulnerability is not known to be listed on CISA’s Known Exploited Vulnerabilities (KEV) catalog [1].
AI Insight generated on May 28, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.
Affected products
1Patches
10311fdd26eb44ip6_gre: Use cached t->net in ip6erspan_changelink().
2 files changed · +6 −6
net/ipv6/ip6_gre.c+3 −3 modifieddiff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c index 0b736627ebaf48..93543fcb4c92ee 100644 --- a/net/ipv6/ip6_gre.c +++ b/net/ipv6/ip6_gre.c @@ -2296,10 +2296,11 @@ static int ip6erspan_changelink(struct net_device *dev, struct nlattr *tb[], struct nlattr *data[], struct netlink_ext_ack *extack) { - struct ip6gre_net *ign = net_generic(dev_net(dev), ip6gre_net_id); + struct ip6_tnl *t = netdev_priv(dev); struct __ip6_tnl_parm p; - struct ip6_tnl *t; + struct ip6gre_net *ign; + ign = net_generic(t->net, ip6gre_net_id); t = ip6gre_changelink_common(dev, tb, data, &p, extack); if (IS_ERR(t)) return PTR_ERR(t); -- cgit 1.3-korg
net/ipv6/ip6_gre.c+3 −3 modifieddiff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c index 0b736627ebaf48..93543fcb4c92ee 100644 --- a/net/ipv6/ip6_gre.c +++ b/net/ipv6/ip6_gre.c @@ -2296,10 +2296,11 @@ static int ip6erspan_changelink(struct net_device *dev, struct nlattr *tb[], struct nlattr *data[], struct netlink_ext_ack *extack) { - struct ip6gre_net *ign = net_generic(dev_net(dev), ip6gre_net_id); + struct ip6_tnl *t = netdev_priv(dev); struct __ip6_tnl_parm p; - struct ip6_tnl *t; + struct ip6gre_net *ign; + ign = net_generic(t->net, ip6gre_net_id); t = ip6gre_changelink_common(dev, tb, data, &p, extack); if (IS_ERR(t)) return PTR_ERR(t); -- cgit 1.3-korg
e70cfb40c3a9ip6_gre: Use cached t->net in ip6erspan_changelink().
2 files changed · +6 −6
net/ipv6/ip6_gre.c+3 −3 modifieddiff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c index d19d86ed43766b..6dea7caf5a777a 100644 --- a/net/ipv6/ip6_gre.c +++ b/net/ipv6/ip6_gre.c @@ -2261,10 +2261,11 @@ static int ip6erspan_changelink(struct net_device *dev, struct nlattr *tb[], struct nlattr *data[], struct netlink_ext_ack *extack) { - struct ip6gre_net *ign = net_generic(dev_net(dev), ip6gre_net_id); + struct ip6_tnl *t = netdev_priv(dev); struct __ip6_tnl_parm p; - struct ip6_tnl *t; + struct ip6gre_net *ign; + ign = net_generic(t->net, ip6gre_net_id); t = ip6gre_changelink_common(dev, tb, data, &p, extack); if (IS_ERR(t)) return PTR_ERR(t); -- cgit 1.3-korg
net/ipv6/ip6_gre.c+3 −3 modifieddiff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c index d19d86ed43766b..6dea7caf5a777a 100644 --- a/net/ipv6/ip6_gre.c +++ b/net/ipv6/ip6_gre.c @@ -2261,10 +2261,11 @@ static int ip6erspan_changelink(struct net_device *dev, struct nlattr *tb[], struct nlattr *data[], struct netlink_ext_ack *extack) { - struct ip6gre_net *ign = net_generic(dev_net(dev), ip6gre_net_id); + struct ip6_tnl *t = netdev_priv(dev); struct __ip6_tnl_parm p; - struct ip6_tnl *t; + struct ip6gre_net *ign; + ign = net_generic(t->net, ip6gre_net_id); t = ip6gre_changelink_common(dev, tb, data, &p, extack); if (IS_ERR(t)) return PTR_ERR(t); -- cgit 1.3-korg
1d324c2f43f7ip6_gre: Use cached t->net in ip6erspan_changelink().
2 files changed · +6 −6
net/ipv6/ip6_gre.c+3 −3 modifieddiff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c index 63fc8556b475e5..365b4059eb2035 100644 --- a/net/ipv6/ip6_gre.c +++ b/net/ipv6/ip6_gre.c @@ -2262,10 +2262,11 @@ static int ip6erspan_changelink(struct net_device *dev, struct nlattr *tb[], struct nlattr *data[], struct netlink_ext_ack *extack) { - struct ip6gre_net *ign = net_generic(dev_net(dev), ip6gre_net_id); + struct ip6_tnl *t = netdev_priv(dev); struct __ip6_tnl_parm p; - struct ip6_tnl *t; + struct ip6gre_net *ign; + ign = net_generic(t->net, ip6gre_net_id); t = ip6gre_changelink_common(dev, tb, data, &p, extack); if (IS_ERR(t)) return PTR_ERR(t); -- cgit 1.3-korg
net/ipv6/ip6_gre.c+3 −3 modifieddiff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c index 63fc8556b475e5..365b4059eb2035 100644 --- a/net/ipv6/ip6_gre.c +++ b/net/ipv6/ip6_gre.c @@ -2262,10 +2262,11 @@ static int ip6erspan_changelink(struct net_device *dev, struct nlattr *tb[], struct nlattr *data[], struct netlink_ext_ack *extack) { - struct ip6gre_net *ign = net_generic(dev_net(dev), ip6gre_net_id); + struct ip6_tnl *t = netdev_priv(dev); struct __ip6_tnl_parm p; - struct ip6_tnl *t; + struct ip6gre_net *ign; + ign = net_generic(t->net, ip6gre_net_id); t = ip6gre_changelink_common(dev, tb, data, &p, extack); if (IS_ERR(t)) return PTR_ERR(t); -- cgit 1.3-korg
cf7fc624329eip6_gre: Use cached t->net in ip6erspan_changelink().
2 files changed · +6 −6
net/ipv6/ip6_gre.c+3 −3 modifieddiff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c index dafcc0dcd77a53..0097d4784c7120 100644 --- a/net/ipv6/ip6_gre.c +++ b/net/ipv6/ip6_gre.c @@ -2261,10 +2261,11 @@ static int ip6erspan_changelink(struct net_device *dev, struct nlattr *tb[], struct nlattr *data[], struct netlink_ext_ack *extack) { - struct ip6gre_net *ign = net_generic(dev_net(dev), ip6gre_net_id); + struct ip6_tnl *t = netdev_priv(dev); struct __ip6_tnl_parm p; - struct ip6_tnl *t; + struct ip6gre_net *ign; + ign = net_generic(t->net, ip6gre_net_id); t = ip6gre_changelink_common(dev, tb, data, &p, extack); if (IS_ERR(t)) return PTR_ERR(t); -- cgit 1.3-korg
net/ipv6/ip6_gre.c+3 −3 modifieddiff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c index dafcc0dcd77a53..0097d4784c7120 100644 --- a/net/ipv6/ip6_gre.c +++ b/net/ipv6/ip6_gre.c @@ -2261,10 +2261,11 @@ static int ip6erspan_changelink(struct net_device *dev, struct nlattr *tb[], struct nlattr *data[], struct netlink_ext_ack *extack) { - struct ip6gre_net *ign = net_generic(dev_net(dev), ip6gre_net_id); + struct ip6_tnl *t = netdev_priv(dev); struct __ip6_tnl_parm p; - struct ip6_tnl *t; + struct ip6gre_net *ign; + ign = net_generic(t->net, ip6gre_net_id); t = ip6gre_changelink_common(dev, tb, data, &p, extack); if (IS_ERR(t)) return PTR_ERR(t); -- cgit 1.3-korg
eca62bb0569dip6_gre: Use cached t->net in ip6erspan_changelink().
2 files changed · +6 −6
net/ipv6/ip6_gre.c+3 −3 modifieddiff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c index 63ac4a8e095b95..b10d2e59d8c406 100644 --- a/net/ipv6/ip6_gre.c +++ b/net/ipv6/ip6_gre.c @@ -2299,10 +2299,11 @@ static int ip6erspan_changelink(struct net_device *dev, struct nlattr *tb[], struct nlattr *data[], struct netlink_ext_ack *extack) { - struct ip6gre_net *ign = net_generic(dev_net(dev), ip6gre_net_id); + struct ip6_tnl *t = netdev_priv(dev); struct __ip6_tnl_parm p; - struct ip6_tnl *t; + struct ip6gre_net *ign; + ign = net_generic(t->net, ip6gre_net_id); t = ip6gre_changelink_common(dev, tb, data, &p, extack); if (IS_ERR(t)) return PTR_ERR(t); -- cgit 1.3-korg
net/ipv6/ip6_gre.c+3 −3 modifieddiff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c index 63ac4a8e095b95..b10d2e59d8c406 100644 --- a/net/ipv6/ip6_gre.c +++ b/net/ipv6/ip6_gre.c @@ -2299,10 +2299,11 @@ static int ip6erspan_changelink(struct net_device *dev, struct nlattr *tb[], struct nlattr *data[], struct netlink_ext_ack *extack) { - struct ip6gre_net *ign = net_generic(dev_net(dev), ip6gre_net_id); + struct ip6_tnl *t = netdev_priv(dev); struct __ip6_tnl_parm p; - struct ip6_tnl *t; + struct ip6gre_net *ign; + ign = net_generic(t->net, ip6gre_net_id); t = ip6gre_changelink_common(dev, tb, data, &p, extack); if (IS_ERR(t)) return PTR_ERR(t); -- cgit 1.3-korg
1d324c2f43f7ip6_gre: Use cached t->net in ip6erspan_changelink().
2 files changed · +6 −6
net/ipv6/ip6_gre.c+3 −3 modifieddiff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c index 63fc8556b475e5..365b4059eb2035 100644 --- a/net/ipv6/ip6_gre.c +++ b/net/ipv6/ip6_gre.c @@ -2262,10 +2262,11 @@ static int ip6erspan_changelink(struct net_device *dev, struct nlattr *tb[], struct nlattr *data[], struct netlink_ext_ack *extack) { - struct ip6gre_net *ign = net_generic(dev_net(dev), ip6gre_net_id); + struct ip6_tnl *t = netdev_priv(dev); struct __ip6_tnl_parm p; - struct ip6_tnl *t; + struct ip6gre_net *ign; + ign = net_generic(t->net, ip6gre_net_id); t = ip6gre_changelink_common(dev, tb, data, &p, extack); if (IS_ERR(t)) return PTR_ERR(t); -- cgit 1.3-korg
net/ipv6/ip6_gre.c+3 −3 modifieddiff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c index 63fc8556b475e5..365b4059eb2035 100644 --- a/net/ipv6/ip6_gre.c +++ b/net/ipv6/ip6_gre.c @@ -2262,10 +2262,11 @@ static int ip6erspan_changelink(struct net_device *dev, struct nlattr *tb[], struct nlattr *data[], struct netlink_ext_ack *extack) { - struct ip6gre_net *ign = net_generic(dev_net(dev), ip6gre_net_id); + struct ip6_tnl *t = netdev_priv(dev); struct __ip6_tnl_parm p; - struct ip6_tnl *t; + struct ip6gre_net *ign; + ign = net_generic(t->net, ip6gre_net_id); t = ip6gre_changelink_common(dev, tb, data, &p, extack); if (IS_ERR(t)) return PTR_ERR(t); -- cgit 1.3-korg
cf7fc624329eip6_gre: Use cached t->net in ip6erspan_changelink().
2 files changed · +6 −6
net/ipv6/ip6_gre.c+3 −3 modifieddiff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c index dafcc0dcd77a53..0097d4784c7120 100644 --- a/net/ipv6/ip6_gre.c +++ b/net/ipv6/ip6_gre.c @@ -2261,10 +2261,11 @@ static int ip6erspan_changelink(struct net_device *dev, struct nlattr *tb[], struct nlattr *data[], struct netlink_ext_ack *extack) { - struct ip6gre_net *ign = net_generic(dev_net(dev), ip6gre_net_id); + struct ip6_tnl *t = netdev_priv(dev); struct __ip6_tnl_parm p; - struct ip6_tnl *t; + struct ip6gre_net *ign; + ign = net_generic(t->net, ip6gre_net_id); t = ip6gre_changelink_common(dev, tb, data, &p, extack); if (IS_ERR(t)) return PTR_ERR(t); -- cgit 1.3-korg
net/ipv6/ip6_gre.c+3 −3 modifieddiff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c index dafcc0dcd77a53..0097d4784c7120 100644 --- a/net/ipv6/ip6_gre.c +++ b/net/ipv6/ip6_gre.c @@ -2261,10 +2261,11 @@ static int ip6erspan_changelink(struct net_device *dev, struct nlattr *tb[], struct nlattr *data[], struct netlink_ext_ack *extack) { - struct ip6gre_net *ign = net_generic(dev_net(dev), ip6gre_net_id); + struct ip6_tnl *t = netdev_priv(dev); struct __ip6_tnl_parm p; - struct ip6_tnl *t; + struct ip6gre_net *ign; + ign = net_generic(t->net, ip6gre_net_id); t = ip6gre_changelink_common(dev, tb, data, &p, extack); if (IS_ERR(t)) return PTR_ERR(t); -- cgit 1.3-korg
e70cfb40c3a9ip6_gre: Use cached t->net in ip6erspan_changelink().
2 files changed · +6 −6
net/ipv6/ip6_gre.c+3 −3 modifieddiff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c index d19d86ed43766b..6dea7caf5a777a 100644 --- a/net/ipv6/ip6_gre.c +++ b/net/ipv6/ip6_gre.c @@ -2261,10 +2261,11 @@ static int ip6erspan_changelink(struct net_device *dev, struct nlattr *tb[], struct nlattr *data[], struct netlink_ext_ack *extack) { - struct ip6gre_net *ign = net_generic(dev_net(dev), ip6gre_net_id); + struct ip6_tnl *t = netdev_priv(dev); struct __ip6_tnl_parm p; - struct ip6_tnl *t; + struct ip6gre_net *ign; + ign = net_generic(t->net, ip6gre_net_id); t = ip6gre_changelink_common(dev, tb, data, &p, extack); if (IS_ERR(t)) return PTR_ERR(t); -- cgit 1.3-korg
net/ipv6/ip6_gre.c+3 −3 modifieddiff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c index d19d86ed43766b..6dea7caf5a777a 100644 --- a/net/ipv6/ip6_gre.c +++ b/net/ipv6/ip6_gre.c @@ -2261,10 +2261,11 @@ static int ip6erspan_changelink(struct net_device *dev, struct nlattr *tb[], struct nlattr *data[], struct netlink_ext_ack *extack) { - struct ip6gre_net *ign = net_generic(dev_net(dev), ip6gre_net_id); + struct ip6_tnl *t = netdev_priv(dev); struct __ip6_tnl_parm p; - struct ip6_tnl *t; + struct ip6gre_net *ign; + ign = net_generic(t->net, ip6gre_net_id); t = ip6gre_changelink_common(dev, tb, data, &p, extack); if (IS_ERR(t)) return PTR_ERR(t); -- cgit 1.3-korg
eca62bb0569dip6_gre: Use cached t->net in ip6erspan_changelink().
2 files changed · +6 −6
net/ipv6/ip6_gre.c+3 −3 modifieddiff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c index 63ac4a8e095b95..b10d2e59d8c406 100644 --- a/net/ipv6/ip6_gre.c +++ b/net/ipv6/ip6_gre.c @@ -2299,10 +2299,11 @@ static int ip6erspan_changelink(struct net_device *dev, struct nlattr *tb[], struct nlattr *data[], struct netlink_ext_ack *extack) { - struct ip6gre_net *ign = net_generic(dev_net(dev), ip6gre_net_id); + struct ip6_tnl *t = netdev_priv(dev); struct __ip6_tnl_parm p; - struct ip6_tnl *t; + struct ip6gre_net *ign; + ign = net_generic(t->net, ip6gre_net_id); t = ip6gre_changelink_common(dev, tb, data, &p, extack); if (IS_ERR(t)) return PTR_ERR(t); -- cgit 1.3-korg
net/ipv6/ip6_gre.c+3 −3 modifieddiff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c index 63ac4a8e095b95..b10d2e59d8c406 100644 --- a/net/ipv6/ip6_gre.c +++ b/net/ipv6/ip6_gre.c @@ -2299,10 +2299,11 @@ static int ip6erspan_changelink(struct net_device *dev, struct nlattr *tb[], struct nlattr *data[], struct netlink_ext_ack *extack) { - struct ip6gre_net *ign = net_generic(dev_net(dev), ip6gre_net_id); + struct ip6_tnl *t = netdev_priv(dev); struct __ip6_tnl_parm p; - struct ip6_tnl *t; + struct ip6gre_net *ign; + ign = net_generic(t->net, ip6gre_net_id); t = ip6gre_changelink_common(dev, tb, data, &p, extack); if (IS_ERR(t)) return PTR_ERR(t); -- cgit 1.3-korg
311fdd26eb44ip6_gre: Use cached t->net in ip6erspan_changelink().
2 files changed · +6 −6
net/ipv6/ip6_gre.c+3 −3 modifieddiff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c index 0b736627ebaf48..93543fcb4c92ee 100644 --- a/net/ipv6/ip6_gre.c +++ b/net/ipv6/ip6_gre.c @@ -2296,10 +2296,11 @@ static int ip6erspan_changelink(struct net_device *dev, struct nlattr *tb[], struct nlattr *data[], struct netlink_ext_ack *extack) { - struct ip6gre_net *ign = net_generic(dev_net(dev), ip6gre_net_id); + struct ip6_tnl *t = netdev_priv(dev); struct __ip6_tnl_parm p; - struct ip6_tnl *t; + struct ip6gre_net *ign; + ign = net_generic(t->net, ip6gre_net_id); t = ip6gre_changelink_common(dev, tb, data, &p, extack); if (IS_ERR(t)) return PTR_ERR(t); -- cgit 1.3-korg
net/ipv6/ip6_gre.c+3 −3 modifieddiff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c index 0b736627ebaf48..93543fcb4c92ee 100644 --- a/net/ipv6/ip6_gre.c +++ b/net/ipv6/ip6_gre.c @@ -2296,10 +2296,11 @@ static int ip6erspan_changelink(struct net_device *dev, struct nlattr *tb[], struct nlattr *data[], struct netlink_ext_ack *extack) { - struct ip6gre_net *ign = net_generic(dev_net(dev), ip6gre_net_id); + struct ip6_tnl *t = netdev_priv(dev); struct __ip6_tnl_parm p; - struct ip6_tnl *t; + struct ip6gre_net *ign; + ign = net_generic(t->net, ip6gre_net_id); t = ip6gre_changelink_common(dev, tb, data, &p, extack); if (IS_ERR(t)) return PTR_ERR(t); -- cgit 1.3-korg
Vulnerability mechanics
Root cause
"Use of dev_net(dev) instead of cached t->net in ip6erspan_changelink() causes tunnel re-insertion into the wrong per-netns hash after IFLA_NET_NS_FD migration."
Attack vector
An attacker with access to an unprivileged user namespace (e.g., via `unshare --user --map-root-user --net`) can create an ip6erspan tunnel and then migrate it to a different network namespace using `IFLA_NET_NS_FD`. When `ip6erspan_changelink()` is subsequently called, it resolves the per-netns hash using `dev_net(dev)` instead of the tunnel's creation netns (`t->net`), causing the tunnel to be re-inserted into the wrong hash. The original netns retains a stale entry; when that netns is destroyed, `ip6gre_exit_rtnl_net()` walks the stale entry, triggering a slab-use-after-free (KASAN) and a kernel BUG at `net/core/dev.c` (LIST_POISON1) [patch_id=2898532].
Affected code
The bug is in `ip6erspan_changelink()` in `net/ipv6/ip6_gre.c`. The function incorrectly uses `dev_net(dev)` to obtain the per-netns ip6gre hash, rather than the cached `t->net` pointer from the tunnel structure. The sibling function `ip6gre_changelink()` in the same file already uses the cached `t->net` [patch_id=2898532].
What the fix does
The patch moves the `struct ip6_tnl *t` declaration to the top of `ip6erspan_changelink()` and obtains the per-netns ip6gre hash via `net_generic(t->net, ip6gre_net_id)` instead of `net_generic(dev_net(dev), ip6gre_net_id)`. This ensures the hash lookup uses the tunnel's cached creation netns (`t->net`), which remains correct even after the device has been moved to a different namespace via `IFLA_NET_NS_FD`. The same pattern was already used in `ip6gre_changelink()` [patch_id=2898532].
Preconditions
- authAttacker must have access to an unprivileged user namespace with network capabilities (unshare --user --map-root-user --net)
- inputAttacker must be able to create an ip6erspan tunnel and migrate it to a different network namespace via IFLA_NET_NS_FD
- configThe original network namespace must be destroyed after the migration to trigger the use-after-free
Generated on May 28, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
5- git.kernel.org/stable/c/1d324c2f43f70c965f25c58cc3611c779adbe47envd
- git.kernel.org/stable/c/311fdd26eb4443d43b909cc67a10f3a5fd1b21b2nvd
- git.kernel.org/stable/c/cf7fc624329e76c6394653d12353e1d033adea91nvd
- git.kernel.org/stable/c/e70cfb40c3a99b232cd42c6a6a10f0d8e039dc82nvd
- git.kernel.org/stable/c/eca62bb0569de4d43a4dac06a2092a9d4ca1d702nvd
News mentions
0No linked articles in our index yet.