CVE-2024-26953 is a recently resolved vulnerability affecting the Linux kernel's IPsec ESP implementation. The bug centers on improper handling of page memory from the kernel's page_pool system, leading to serious memory leaks and potential system crashes, particularly when using IPsec with GRE tunnels and page pools enabled. This article will break down the issue, demonstrate how it occurs, show a simplified proof of exploit, and review the patch that fixes the problem.
What Happened?
- The kernel's ESP code (used for encrypted network tunnels) sometimes "reorganizes" socket buffers (skb).
When doing so, it tries to free memory pages from the old skb by calling put_page.
- However, if those pages were allocated from a specialized page_pool (used for high-performance networking), simply calling put_page() will not actually recycle the memory correctly—*instead, it causes a resource leak preserved in the pool*.
GRE tunnels on top (not hardware-offloaded)
- A NIC/driver using a page_pool (common in modern high-speed interfaces)
When traffic is pushed through this stack, the kernel will eventually dump an error like this
BUG: Bad page state in process ksoftirqd/16 pfn:1451b6
page:00000000de2b8d32 refcount: mapcount: mapping:000000000000000 index:x1451b600 pfn:x1451b6
flags: x200000000000000(node=|zone=2)
...
page dumped because: page_pool leak
...
Call Trace:
<TASK>
dump_stack_lvl+x36/x50
bad_page+x70/xf
free_unref_page_prepare+x27a/x460
free_unref_page+x38/x120
esp_ssg_unref.isra.+x15f/x200
esp_output_tail+x66d/x780
esp_xmit+x2c5/x360
...
Exploiting the Issue
While this is not directly a remote code execution bug, it could be remotely triggered by a remote attacker sending large quantities of IPsec-encrypted GRE packets via an affected Linux router, especially if NIC drivers use the page_pool mechanism.
Where's the Issue?
The problem exists in the ESP output code: in certain cases, the memory cleanup is performed without caring whether the page originated from a page pool.
Problematic Code (prior to the patch)
// This is illustrative, not full code
for (i = ; i < nr_frags; i++) {
put_page(skb_shinfo(skb)->frags[i].page);
}
*This releases/puts a reference on every page. But for page pool pages, this isn’t enough!*
Why Isn't put_page() Sufficient?
- page_pool is a memory management system for networking: pages are pinned to avoid costly alloc/free operations.
- To correctly recycle them, you must use page_pool_put_full_page(), which handles the necessary logic to avoid leaks.
The Fix: skb_page_unref Wrapper
The Linux kernel fix introduces a general-purpose wrapper—skb_page_unref()—that checks whether a page belongs to a page pool and, if so, uses the correct function.
The Patch
Commit title: net: esp: fix bad handling of pages from page_pool
Fixes:
- https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=bfdf6ff952898ac47048dce81da54b776e89919
Key idea: Replace raw put_page() calls with the new skb_page_unref() function.
// Pseudocode for the fix
static inline void skb_page_unref(struct page *page, bool allow_direct)
{
if (unlikely(page_pool_is_page_pfmemalloc(page)))
page_pool_put_full_page(page, allow_direct);
else
put_page(page);
}
The code using it now becomes
for (i = ; i < nr_frags; i++) {
skb_page_unref(skb_shinfo(skb)->frags[i].page, false);
}
Reference:
- Linux kernel patch discussion
- Netdev mailing list patch submission
Proof of Concept (PoC): Simulating the Leak
A script to stress the code path and see the leak in action is complex (requires hardware/network setup). But conceptually, the flow is:
Send large packets from one host to another through the tunnel repeatedly.
You will observe: Memory usage rising, eventually causing "page_pool leak" warnings and possible system crash.
Real-World Impact
- Cloud Providers / Datacenters: Linux routers/firewalls using high-speed NICs and IPsec+GRE risk sudden kernel crashes under traffic.
- Edge routers/gateways: VPN-heavy environments with modern drivers can be forced down by attackers.
Mitigation:
Fixed in: Linux 6.8-rc5+ (and backported to stable kernels)
- First patch submission: Feb 20, 2024 – Nicolas Dichtel
- CVE assignment: CVE-2024-26953 NVD entry
Conclusion
CVE-2024-26953 is a great example of how complex new kernel subsystems (like page pools) can have subtle interactions with existing protocols (IPsec, GRE). The bug shows how high-performance networking can have unexpected pitfalls, especially in code paths involving memory management.
Admins: Patch your kernels! Anyone running high-performance Linux networking with IPsec tunnels could otherwise be at risk of sudden and unexplained outages.
Further Reading
- Original Patch (linux-netdev)
- Kernel.org commit
- page_pool documentation
- CVE-2024-26953 at NVD
Timeline
Published on: 05/01/2024 06:15:11 UTC
Last modified on: 05/04/2025 09:00:34 UTC