HIGH Introduced in 4.7
ip6_tunnel Xmit DoubleFree
CVE-2026-89563
CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H
KernelScan AI8.7HIGH
01Description
In the Linux kernel, the following vulnerability has been resolved: ip6_tunnel: use skb_cow_head() in ip6_tnl_xmit() ip6_tnl_xmit() may need to expand headroom before it can push the outer IPv6 and optional encap headers. It currently does that with skb_realloc_headroom(), copies skb->sk ownership, consumes the original skb, and then continues processing with the replacement skb kept only in its local variable. That is safe only if the helper cannot fail afterwards. But this helper still has post-reallocation error exits. collect_md tunnels reject non-NONE encap after the replacement, and ip6_tnl_encap() can also fail later. In those cases the helper returns an error to its callers while the caller still only has the original skb pointer. Both ip6_tnl_start_xmit() and the IPv6 GRE paths free the caller skb on error, so they can end up freeing an skb that ip6_tnl_xmit() already consumed. Use skb_cow_head() instead. It provides the required headroom and writability without privately replacing the caller-owned skb, so later error returns cannot leave callers with a stale pointer. The Ethernet users, ip6gretap and ip6erspan, clear IFF_TX_SKB_SHARING and already call skb_cow_head() before entering ip6_tnl_xmit(). They do not rely on the removed skb_shared() reallocation. This also makes the IPv6 tunnel path consistent with ip_tunnel_xmit().
02KernelScan AI Analysis
Risk summary
A double-free in the IPv6 tunnel transmit path allows a local unprivileged user (via user namespace CAP_NET_ADMIN) to corrupt kernel heap memory, potentially achieving kernel code execution and container escape. Any system with IPv6 tunneling enabled and unprivileged user namespace access is at risk. The vulnerability is exploitable with a single packet sent through a misconfigured tunnel device.
Vulnerability analysis
When transmitting a packet through an IPv6 tunnel, the kernel may need to expand the packet's headroom. The original code did this by allocating a replacement buffer, transferring ownership, and consuming the original — but stored the replacement only in a local variable. If a later validity check fails (for example, the tunnel is configured with incompatible encapsulation parameters, or the encapsulation step itself errors out), the function returns an error to its callers, which still hold the pointer to the already-freed original buffer and proceed to free it again, causing a double-free. The fix replaces the reallocation with an in-place headroom expansion that never swaps out the caller's buffer pointer, so any subsequent error return leaves callers with a valid reference. The vulnerable path is reachable locally by any user who can send packets through a configured IPv6 tunnel device; configuring the tunnel with the triggering parameters requires CAP_NET_ADMIN, which an unprivileged user can obtain through user namespaces, making this exploitable from containers and other unprivileged contexts.
Lifecycle
03Fix Versions
| Branch | Introduced | Fixed in | Patch commit |
|---|---|---|---|
| mainline | 4.7 | 7.3-rc1 | 87f21b59ddc6 |
| 5.10 | 4.7 | 5.10.270 | 6e8eff8ed13b |
| 6.1 | 4.7 | 6.1.188 | 629d5557e635 |
| 6.12 | 4.7 | 6.12.109 | 37df5bc6b5cc |
| 6.18 | 4.7 | 6.18.50 | b36dfd6e8cff |
| 7.2 | 4.7 | 7.2.4 | 8fc56ca49fc0 |
| 5.15 | 4.7 | 5.15.221 | dc1a319a4815 |
| 6.6 | 4.7 | 6.6.157 | defa0adeff13 |
| cip/6.12 | 4.7 | 6.12.111-cip32 | 37df5bc6b5cc |