flawopen.com/Teardowns/cve-2024-26642-linux-nftables-anonymous-set-timeout

● CVE-2024-26642 · CVSS 7.8 · High
FlawOpen Security Research

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.

💡 Plain English Explainer (ELI5)

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_NEWSET netlink message and handled by nf_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 meter statements. 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

Step 1

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.

Step 2

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.

Step 3

The kernel accepts it

nf_tables_newset() finds no forbidden flag pair and creates a rule-bound anonymous set whose elements carry expiry times.

Step 4

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

UNPATCHED FLAW
/* 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. */
	}
HARDENED SECURE PATCH
/* 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

Sources