A security issue (now tracked as CVE-2025-21865) was recently discovered in the Linux kernel’s GTP (GPRS Tunneling Protocol) implementation. This bug highlights a potential risk of list corruption and kernel crashes related to device cleanup routines in network namespaces. Here's what you need to know, why it matters, and the technical nitty-gritty with code and an example scenario.

What is the Vulnerability?

The flaw exists in the gtp_net_exit_batch_rtnl() function, which is responsible for cleaning up GTP devices when a network namespace is dismantled. Specifically, the code could call a device's cleanup function (->dellink()) twice for the same device under certain conditions, leading to a list_del corruption splat if list debug checks are enabled (CONFIG_DEBUG_LIST=y). This can crash the kernel and potentially enable denial of service or privilege escalation in custom settings.

Affected Kernel: Linux 6.x (before the patch)

- Component: drivers/net/gtp.c (GPRS Tunneling Protocol)

Reported by: Brad Spengler

- Fixed in: See kernel commit eb28fd76ca

TL;DR

If a GTP device is created with a UDP socket in a different netns (network namespace) than the device itself, the kernel cleanup can hit the same device twice in two different loops, resulting in double cleanup and a use-after-free scenario in the device linked list.

3. During cleanup of B, it finds the same device again—calls destructor again.

Result:
Calling gtp_dellink() twice isn’t *supposed* to break things, but with CONFIG_DEBUG_LIST enabled, the kernel detects corruption—kernel panic!

The vulnerable function (before patch)

static void gtp_net_exit_batch_rtnl(struct list_head *net_list)
{
    struct gtp_net *gn;
    struct net *net;

    list_for_each_entry(net, net_list, exit_list) {
        gn = net_generic(net, gtp_net_id);
        // Vulnerable: calls for_each_netdev(), might hit same device as above
        for_each_netdev(net, dev) {
            gtp_dellink(dev, NULL);
        }
    }
}

- for_each_netdev() will catch devices in the namespace—including those that other namespaces can also “see.”

What’s the Real Fix?
Don’t clean up devices here—let the standard netdev cleanup do its job (as with similar code for bareudp, geneve, ip tunnels).

Patched version

static void gtp_net_exit_batch_rtnl(struct list_head *net_list)
{
    // No more for_each_netdev
    // Leave cleanup to default handlers
}

Here’s what you could see with list debugging enabled and the bug triggered

list_del corruption, ffff888aaa62c00->next (...) is LIST_POISON1 (...)
kernel BUG at lib/list_debug.c:58!
Oops: invalid opcode: 000 [#1] PREEMPT SMP KASAN
...
RIP: __list_del_entry_valid_or_report+x141/x200 lib/list_debug.c:58
...
Call Trace:
 [<...>] list_del include/linux/list.h:262 [inline]

That’s a hard crash – not good for reliability!

Exploit Scenario

Although this bug isn't trivially exploitable for code execution, a local attacker with privileges to create network namespaces and attach GTP devices can use this to crash the kernel (DoS). With creative heap shaping and additional bugs, it could sometimes be leveraged further (e.g., for privilege escalation), but this is not the primary impact.

> Attack prerequisites:
> - Ability to create network namespaces and run privileged operations (CAP_NET_ADMIN)
> - Kernel compiled with GTP support (CONFIG_GTP)
> - (Optional for crash) Kernel with CONFIG_DEBUG_LIST or KASAN

Here’s a simple exploit meant to trigger the bug and cause a crash (test ONLY on disposable VMs!)

ip netns add A
ip netns add B

# Create GTP device in B, but its UDP socket in A
# (In practice, this requires a tool like gtp-link from iproute2/net-next)
ip netns exec B ip link add gtp type gtp \
    fd 3 # pass fd from A, or use custom script to achieve cross-netns fd

# Clean up namespaces and watch the kernel crash!
ip netns del A
ip netns del B

> See iproute2 gtp-link for more background.

Note: Current iproute2 tooling might need patches for exact reproduction, but kernel devs have shown this is possible.

References

- Original kernel patch: net: gtp: Fix list corruption in gtp_net_exit_batch_rtnl()
- LWN coverage of net namespace bugs
- GTP protocol explained: Wikipedia
- linux-netdev mailing list discussion

> For the CVE number and details, see CVE-2025-21865 at Mitre *(may take some hours to be populated)*

Conclusion

CVE-2025-21865 is a great example of how nuanced network namespace cleanup code in the kernel can lead to high-impact bugs—from hard-to-debug kernel crashes to potential security escape vectors if left unchecked.

Sysadmins: Patch your kernels!

- Kernel devs: Avoid custom GTP/UDP socket/namespace logic without deep review.

For more details:
- Kernel patch commit
- Upstream bug report on lore.kernel.org


*Stay tuned for more in-depth Linux kernel coverage, analysis, and safer code tips!*

Timeline

Published on: 03/12/2025 10:15:19 UTC
Last modified on: 03/24/2025 15:41:36 UTC