In February 2024, a subtle yet potentially dangerous bug was patched in the Linux kernel's nftables subsystem, tagged as CVE-2024-26924. The vulnerability affected the "pipapo" set backend for nftables and could lead to use-after-free situations and kernel crashes—something that, in the wrong hands, could be leveraged for denial of service or possibly privilege escalation.

In this article, we'll break down what happened under the hood, explain the underlying problem in simple language, and show you what the exploitable condition looked like—with code, technical details, and practical consequences. This is an exclusive, easy-to-understand look at a kernel bug that could have brought down systems.

Background: What Is Set Pipapo in nftables?

nftables is the modern Linux framework for packet filtering, NAT, and firewalling, superseding the iptables project. At its core, sets are a way to efficiently match lists of values (like IP addresses or port numbers) in firewall rules.

The "pipapo" set type is one of the internal data structures used for fast set lookups. When a user or program adds/removes a set element (say, a new banned IP), the kernel code needs to manage these elements efficiently, allowing for timeouts, concurrent changes, and safe memory handling.

The Vulnerability: Live Element Freed and Stale Pointers

The bug was in how elements were removed from pipapo sets—especially under rapid, repeated add/delete actions with large numbers of elements.

Immediately delete the same element (del_elem("000000X")), before the timeout expires.

3. If you've rapidly added and removed many such elements, you could trigger a race where the removal mechanism frees a "live" (still valid and referenced) element—leaving behind a pointer to freed memory.

This left the kernel with dangling/stale pointers. If code later tries to look up that element, it could refer to memory that has already been freed, leading to a crash—which security tools like KASAN (Kernel Address Sanitizer) would detect.

Why?

The removal function did not handle cases where several elements had the same key (e.g., same value/IP), but only some were expired or deactivated. The search for what to delete could unlink or free the wrong element, sometimes one that's still in use elsewhere in the set. Result: use-after-free.

Here's a simplified code snippet to illustrate the issue

// Pseudocode for problematic removal logic
for_each_element_with_key(k) {
    if (element is marked inactive in current generation) {
        remove_link(element);     // Might unmap the wrong one!
        free(element);            // Could free a live object
        break;
    }
}
// No check that the key matches the *deactivated* element precisely!

The fix added strict checking to make sure that the element being unmapped and freed was _exactly_ the one marked as inactive, and not some other live mapping with the same key.

Bug Details: KASAN Splat and Reproduction

When this race happened, tools like KASAN would report a "splat"—a runtime memory bug. Developers found the problem with back-to-back add/remove tests, illustrated by this bug report from Pablo Neira Ayuso:

add_elem("00000000") timeout 100 ms
...
add_elem("000000X") timeout 100 ms
del_elem("000000X")
...
add_elem("00005000") timeout 100 ms

1) nft_pipapo_remove() removes element 000000X
Then, KASAN shows a splat.

Exploitation: What Could Go Wrong?

A local user—or maybe even a containerized process with netlink permissions—could quickly add and remove set elements with duplicate keys in rapid succession. By timing these operations (and setting timeouts), users might trigger deletion of live kernel memory, resulting in:

- Kernel crash/panic (DoS)

Firewall rules becoming inconsistent or broken

While the primary risk is DoS (crashing/restarting the host), attackers could, in theory, combine further exploitation primitives (like information leaks or other kernel bugs) to escalate privileges.

Note: Without netlink or cap_net_admin privileges, non-root users cannot exploit this directly.

Patch & Fix

The fix, landed in Linux 6.7.4 and mainline kernel commit 7f3bf1dda, ensures that _only the correct inactive element_ is removed, and adds internal check/warn points.

Example from the real kernel patch

if (nft_set_elem_active(e, genmask)) {
    // Was wrongly matching live element
    continue;
}
if (memcmp(e->key, key, set->klen)) {
    // Not full key match, keep searching
    continue;
}
// Only unmapped and free correct element now

See the patch diff here.

References

- CVE-2024-26924 NVD entry
- Linux kernel netfilter patch commit
- Original kernel patch discussion (lore.kernel.org)

Conclusion

CVE-2024-26924 reminds us that even well-audited subsystems like Linux netfilter can harbor subtle race conditions—especially where complex, multigenerational data structures are managed under pressure from userland. Left unfixed, these bugs can crash entire servers or induce other subtle breakage.

Patch your kernels! If you're using nftables and sets with timeouts, upgrade to kernel 6.7.4+ or apply vendor updates immediately. If you manage shared hosting, VPN, or container infrastructure, inspect your exposure—unprivileged containers with network capabilities could accidentally (or deliberately) hit this path.

Feel free to explore the code, read the commit, and test your defenses.

Timeline

Published on: 04/25/2024 06:15:57 UTC
Last modified on: 07/03/2024 01:50:00 UTC