flawopen.com/Teardowns/cve-2024-26642-linux-nftables-anonymous-set-timeout
CVE-2024-26642: Linux nf_tables Anonymous Set with Timeout Flag
CVE-2024-26642 (CVSS 7.8 per NIST): nf_tables_newset() accepted anonymous sets that also carried the timeout flag, a combination no userspace tool creates, which exposed rule-bound sets to element expiry and garbage collection. Linux 6.8 rejects it with -EOPNOTSUPP.
A cloakroom has two systems. Numbered hooks belong to one guest for one evening and are cleared the moment that guest leaves. Timed tickets are swept every hour by a porter who removes anything past its time. The order form lets you tick both boxes for the same coat, so a hook is now cleared when the guest leaves and also swept on the porter's schedule. Two members of staff each think they are in charge of that hook, and neither was trained for the other's timetable. The fix is simple: the form now refuses that pair of boxes.
Core Concepts & Subsystem Terms
nf_tables set- A kernel data structure of addresses, ports or other keys that nftables rules match against, created with an
NFT_MSG_NEWSETnetlink message and handled bynf_tables_newset(). Anonymous set (NFT_SET_ANONYMOUS)- An unnamed set, such as
{ 22, 80 }written inline in a rule. It is bound to that one rule and destroyed together with it in the same transaction. NFT_SET_TIMEOUT- Flag that gives set elements an expiry time. Expired elements are removed by the set's garbage-collection machinery.
NFT_SET_EVAL- Flag for sets updated from the packet path, used by legacy
meterstatements. The fix keeps anonymous + timeout + eval legal for them. CAP_NET_ADMIN in a user namespace- nf_tables accepts configuration from any process holding CAP_NET_ADMIN in its network namespace, which an unprivileged user can obtain by creating a user namespace where distributions allow it.
Root Cause Analysis
nf_tables_newset() in net/netfilter/nf_tables_api.c checked set flags only for unknown bits and for the MAP+OBJECT and EVAL+OBJECT conflicts. It accepted NFT_SET_ANONYMOUS | NFT_SET_TIMEOUT, so a set whose lifetime is tied to a single rule and transaction could also have elements that expire and are reclaimed by garbage collection. Userspace never produces this combination, and the lifetime code was not designed for it. The upstream fix rejects it with -EOPNOTSUPP unless NFT_SET_EVAL is also set. The public record does not describe the resulting memory error in detail; NIST scores it 7.8 (confidentiality, integrity and availability all high), and the kernel CNA scores it 5.5 (availability only).
Step-by-Step Attack Flow
Obtain CAP_NET_ADMIN
A local user creates a user and network namespace (where unprivileged user namespaces are enabled) and so holds CAP_NET_ADMIN over that namespace's nf_tables state.
Request the invalid set
Within a netlink batch the process sends NFT_MSG_NEWSET with NFTA_SET_FLAGS = NFT_SET_ANONYMOUS | NFT_SET_TIMEOUT and binds the set to a new rule through a lookup expression.
The kernel accepts it
nf_tables_newset() finds no forbidden flag pair and creates a rule-bound anonymous set whose elements carry expiry times.
Untested lifetime paths
Committing, aborting or deleting the rule now drives set teardown and element garbage collection together, in paths the nf_tables transaction code does not handle safely.
Source Code: Flaw vs. Secure Implementation
/* net/netfilter/nf_tables_api.c: nf_tables_newset(), before the fix */
if (nla[NFTA_SET_FLAGS] != NULL) {
flags = ntohl(nla_get_be32(nla[NFTA_SET_FLAGS]));
if (flags & ~(NFT_SET_ANONYMOUS | NFT_SET_CONSTANT |
NFT_SET_INTERVAL | NFT_SET_TIMEOUT |
NFT_SET_MAP | NFT_SET_EVAL |
NFT_SET_OBJECT | NFT_SET_CONCAT | NFT_SET_EXPR))
return -EOPNOTSUPP;
/* Only one of these operations is supported */
if ((flags & (NFT_SET_MAP | NFT_SET_OBJECT)) ==
(NFT_SET_MAP | NFT_SET_OBJECT))
return -EOPNOTSUPP;
if ((flags & (NFT_SET_EVAL | NFT_SET_OBJECT)) ==
(NFT_SET_EVAL | NFT_SET_OBJECT))
return -EOPNOTSUPP;
/* BUG: NFT_SET_ANONYMOUS | NFT_SET_TIMEOUT is accepted. A rule-bound
* anonymous set now also gets per-element expiry and garbage
* collection, a combination nft never creates and the set
* lifetime code was not written for. */
}
/* net/netfilter/nf_tables_api.c: nf_tables_newset(), commit 16603605b667 */
if (nla[NFTA_SET_FLAGS] != NULL) {
flags = ntohl(nla_get_be32(nla[NFTA_SET_FLAGS]));
if (flags & ~(NFT_SET_ANONYMOUS | NFT_SET_CONSTANT |
NFT_SET_INTERVAL | NFT_SET_TIMEOUT |
NFT_SET_MAP | NFT_SET_EVAL |
NFT_SET_OBJECT | NFT_SET_CONCAT | NFT_SET_EXPR))
return -EOPNOTSUPP;
/* Only one of these operations is supported */
if ((flags & (NFT_SET_MAP | NFT_SET_OBJECT)) ==
(NFT_SET_MAP | NFT_SET_OBJECT))
return -EOPNOTSUPP;
if ((flags & (NFT_SET_EVAL | NFT_SET_OBJECT)) ==
(NFT_SET_EVAL | NFT_SET_OBJECT))
return -EOPNOTSUPP;
/* FIX: anonymous sets are never used with timeouts from userspace,
* so reject the combination before the set exists. NFT_SET_EVAL
* stays allowed so legacy meters keep working. */
if ((flags & (NFT_SET_ANONYMOUS | NFT_SET_TIMEOUT | NFT_SET_EVAL)) ==
(NFT_SET_ANONYMOUS | NFT_SET_TIMEOUT))
return -EOPNOTSUPP;
}
Engineering & System Hardening Checklist
- ✓Run a kernel that contains commit 16603605b667 (Linux 6.8, or a stable or distribution kernel whose changelog lists
CVE-2024-26642). - ✓Where workloads do not need them, disable unprivileged user namespaces (
kernel.on Debian and Ubuntu,unprivileged_userns_clone=0user., or Ubuntu's AppArmor userns restriction) so local users cannot reach nf_tables.max_user_namespaces=0 - ✓On hosts that do not use nftables, stop the
nf_tablesmodule from loading. - ✓In kernel and API code, express accepted flag combinations as an explicit allow-list and reject anything no supported client produces, instead of rejecting only known-bad pairs.
- ✓Fuzz netlink interfaces with syzkaller descriptions that cover every flag bit, so unusual combinations reach the object lifetime code in testing first.