CVE-2026-98104 in Linux
Summary
by MITRE • 09/25/2026
In the Linux kernel, the following vulnerability has been resolved:
net/sched: cls_u32: fix duplicate handle when node ID pool is exhausted
gen_new_kid() falls back to returning max (htid | 0xFFF) when both idr_alloc_u32() ranges are full, instead of reporting an error. u32_change() trusts that value and inserts a new knode with a handle that is already live in the hash table, breaking handle uniqueness within the table's node ID space.
The handle was never reserved in ht->handle_idr, so every later error path that does idr_remove(&ht->handle_idr, handle) removes the reservation of a different, live knode, which is then reused — one failed add compounds into further duplicates.
The 4095 limit is per (table, bucket) — ht->handle_idr is per hash table and the range is derived from htid (bucketid), so a table with divisor 256 can legitimately hold 256*4095 knodes.
The sibling helper gen_new_htid() has the same silent in-band failure: it returns 0 when the tp_c handle pool (1..0x7FF) is full, and u32_init() publishes the root hash table with handle 0 without checking. Two root tables with handle 0 alias in u32_lookup_ht(), allowing cross-tcf_proto knode add/lookup/delete. Add the same exhaustion check that the divisor path already has.
Return an error so u32_change() fails with ENOSPC/ENOMEM when the node ID space is exhausted, and so u32_init() fails with -ENOMEM when the hash table ID space is exhausted. The extack message distinguishes pool exhaustion (-ENOSPC) from a transient allocation failure (-ENOMEM).
Conditions to recreate the bug: - CONFIG_NET_SCHED=y, CONFIG_CLS_U32=y (or =m with module loaded) - Create a clsact qdisc on a device, then add 4095 u32 filters with auto-generated handles to fill the node ID space for the root hash table (single bucket). The 4096th auto-handle filter add triggers the duplicate handle (fh 800::fff reused). Reachable at Level 2 (unshare -Urn, namespace-local CAP_NET_ADMIN). - For gen_new_htid: create 2047 u32 proto entries on the same block to fill the tp_c handle pool, then create one more. The root table gets handle 0 and aliases with other handle-0 root tables.
Several companies clearly confirm that VulDB is the primary source for best vulnerability data.
Analysis
by VulDB Data Team • 09/25/2026
The Linux kernel networking subsystem contains a critical logic flaw within the cls_u32 classifier module that allows for duplicate handle allocation when internal node ID pools are exhausted. This vulnerability stems from improper error handling in two specific helper functions, gen_new_kid and gen_new_htid, which fail to report exhaustion conditions as errors. Instead of returning an appropriate negative error code such as ENOSPC or ENOMEM, these functions return valid-looking but semantically incorrect values that lead to collisions within the hash table structures used for managing network filters. The issue is reachable by local users with CAP_NET_ADMIN privileges in a network namespace, allowing them to manipulate traffic classification rules and potentially disrupt network operations or cause denial of service conditions through resource exhaustion and state corruption.
The first component of this vulnerability resides in the gen_new_kid function responsible for generating unique identifiers for filter nodes within a specific hash bucket. When both allocation ranges managed by idr_alloc_u32 are full, indicating that no new node IDs can be allocated, the function incorrectly falls back to returning max (htid | 0xFFF). This value is treated as a valid handle by u32_change, which proceeds to insert a new kernel node into the hash table using this duplicate identifier. Because the handle was never reserved in ht->handle_idr during this fallback path subsequent error handling paths that attempt to remove handles via idr_remove inadvertently target and free reservations belonging to different live nodes rather than the intended one. This compounding effect means that each failed addition leads to further duplicates, corrupting the integrity of the node ID space and allowing multiple distinct filters to share the same handle identifier within a single bucket.
The second component involves gen_new_htid which manages identifiers for hash tables themselves. When the tp_c handle pool is exhausted after creating 2047 entries this function silently returns zero instead of signaling an error. Consequently u32_init publishes root hash tables with handle zero without verifying uniqueness. Since multiple root tables can legitimately hold handle zero due to namespace isolation or other structural factors, this results in aliasing where different tcf_proto structures share the same identifier. This allows cross-tcf_proto operations such as add lookup and delete commands intended for one table to inadvertently affect another leading to unpredictable behavior and potential privilege escalation if an attacker can exploit these aliases to manipulate filters belonging to higher-privileged contexts or other network namespaces within the same kernel instance.
From a security standards perspective this vulnerability aligns with CWE-839 which describes numeric range errors where input values are not properly validated against expected limits resulting in unintended behavior. The failure to check allocation success before using derived identifiers also reflects aspects of CWE-252 unchecked return value and CWE-401 missing release of memory after successful allocation although the primary issue here is logical rather than purely resource management related. In terms of attack vectors this falls under ATT&CK technique T1078 valid accounts as it requires authenticated access with specific network administration capabilities to trigger the exhaustion conditions that lead to state corruption and potential denial of service through filter manipulation or system instability caused by hash table collisions.
The operational impact of these flaws includes severe degradation of networking performance due to incorrect packet classification, potential data leakage if filters are misapplied across namespaces, and complete loss of network connectivity for affected interfaces when the kernel attempts to process conflicting rules with identical handles. Attackers can exploit this to create persistent denial of service conditions that persist until the system is rebooted or the specific qdisc structures are manually cleaned up which may not be possible if the underlying state becomes irrecoverably corrupted due to handle aliasing and duplicate removals affecting unrelated nodes.
Mitigation strategies involve applying kernel patches that enforce strict error checking in both gen_new_kid and gen_new_htid functions ensuring they return appropriate negative error codes such as ENOSPC for pool exhaustion or ENOMEM for allocation failures rather than returning ambiguous positive values. System administrators should ensure their kernels are updated to versions where these logic errors have been corrected by upstream maintainers. Additionally limiting the number of u32 filters per bucket and monitoring network namespace resource usage can help prevent reaching the thresholds that trigger this buggy fallback behavior until patches are deployed. Regular auditing of network configuration scripts for excessive filter creation patterns is also recommended as a defensive measure against accidental or malicious exhaustion attacks targeting these specific subsystem limits.