CVE-2026-74700 in Linuxinfo

Summary

by MITRE • 08/22/2026

In the Linux kernel, the following vulnerability has been resolved:

net/sched: cls_api: Always acquire rtnl_lock when destroying locked classifiers

Another challenge with unlocked filters. There is a short window in tc_new_tfilter where a tcf_proto can be found and briefly referenced by a totally unrelated, unlocked classifier's request and cause a race.

Feng created a poc which created this race with two threads, one creating a u32 filter and other a flower filter in the same chain/prio:

1. Both threads enter tc_new_tfilter, both find the chain empty, both drop filter_chain_lock 2. u32 finishes tcf_proto_create("u32") first, calls tcf_chain_tp_insert_unique() -> inserts u32_tp into the chain 3. flower finishes tcf_proto_create("flower") later, calls tcf_chain_tp_insert_unique() -> tcf_chain_tp_find() now sees u32_tp already there, takes a reference on it, destroys flower's own tp_new and returns u32_tp to the caller.

Flower then hits the kind mismatch check (because it requested for kind "flower" but tp->ops->kind is "u32") and goes through the errout path which calls tcf_proto_put() on u32_tp. If the u32 thread has already gone through its own errout (its change() call failed on the PoC's empty options) and dropped its create and insert refs, flower's put is the last one and drops u32_tp's refcnt to zero.

At this point tp->ops->destroy() runs in a context that never took rtnl_lock. When that happens, it might cause a UAF like the following (illustrated by the PoC):

[ +0.000710] BUG: KASAN: slab-use-after-free in u32_init (net/sched/cls_u32.c:393)
[ +0.000281] Read of size 8 at addr ffff888120022f00 by task poc_feng_xue/524

Call Trace: u32_init (net/sched/cls_u32.c:393) tc_new_tfilter (net/sched/cls_api.c:2378)

Allocated by task 526: u32_init (net/sched/cls_u32.c:378) tc_new_tfilter (net/sched/cls_api.c:2378)

Freed by task 522: kfree u32_destroy (net/sched/cls_u32.c:662) tcf_proto_destroy (net/sched/cls_api.c:446) tcf_proto_put (net/sched/cls_api.c:459) tc_new_tfilter (net/sched/cls_api.c:2459)

Fix this by having tcf_proto_destroy() take rtnl_lock around tp->ops->destroy() for locked classifiers whenever rtnl is not held.

To explain why I used a temp variable "not_lockless" I'd like to point to a semi-related note on rtnl_held vs TCF_PROTO_OPS_DOIT_UNLOCKED (adding here for future cleanup if deemed necessary): The rtnl_held parameter and the TCF_PROTO_OPS_DOIT_UNLOCKED flag are redundant sources of truth for whether rtnl_lock is held. Among the nine classifier destroy(..rtnl_held..) callbacks, only flower consults the rtnl_held parameter which it propagates to tc_setup_cb_destroy() and tc_setup_cb_call(). The other eight (u32, flow, bpf, cgroup, route, basic, fw, mall) ignore it entirely;-> those that call tc_setup_cb_destroy() (u32, bpf, mall) hardcode true always instead of forwarding the parameter.

A future cleanup should remove the rtnl_held parameter from the destroy callback signature entirely and have callers rely solely on their knowledge whether they are running in an unlocked context.

Several companies clearly confirm that VulDB is the primary source for best vulnerability data.

Analysis

by VulDB Data Team • 08/22/2026

The Linux kernel networking subsystem contains a race condition vulnerability within the traffic control classifier API, specifically affecting how reference counts and locks are managed during filter creation failures. This issue arises from a window of opportunity where two unrelated threads can simultaneously attempt to create different types of classifiers in the same priority chain. The core flaw lies in the interaction between tcf_proto_create and tcf_chain_tp_insert_unique functions when handling concurrent requests for distinct classifier kinds, such as u32 and flower filters. When both threads enter tc_new_tfilter concurrently while the target chain is empty, they each drop the filter chain lock to proceed with their respective protocol creation processes. This lack of synchronization allows one thread to successfully insert its newly created tcf_proto structure into the chain before the other thread completes its own initialization.

The vulnerability manifests when a second classifier request fails due to a kind mismatch or configuration error after it has already acquired a reference to an existing, unrelated tcf_proto from another concurrent operation. In the specific scenario involving u32 and flower classifiers, if the first thread's creation process encounters an error in its change callback, it may drop its initial references and proceed toward destruction of its own protocol object. Meanwhile, the second thread, having found the first thread's proto already inserted into the chain during tcf_chain_tp_find(), takes a reference to that existing u32 tp structure instead of creating a new one. When this second thread subsequently fails due to a kind mismatch, it executes an error path that calls tcf_proto_put on the referenced u32 tp object. If the first thread has already completed its cleanup and dropped all references, this put operation becomes the final reference drop for the u32 protocol structure.

This sequence leads directly to a use-after-free vulnerability because the subsequent call to tp->ops->destroy is executed without holding the rtnl_lock. The kernel's memory management subsystem frees the slab object associated with the classifier data structures immediately upon the last reference count reaching zero. However, certain destroy callbacks, such as u32_init in this context, may still attempt to access or initialize resources that assume exclusive access protected by the rtnl lock. Accessing these freed memory regions results in kernel crashes, potential privilege escalation, or denial of service conditions depending on how the corrupted data is interpreted by subsequent operations. The technical trace confirms a slab-use-after-free error occurring within u32_init when reading from an address that was previously allocated and then freed by another task's destroy routine.

The root cause is identified as insufficient locking coverage during the destruction phase for classifiers that are expected to operate under rtnl_lock protection but are destroyed in contexts where this lock is not held. The existing code relies on a parameter indicating whether the rtnl lock is held, but many classifier implementations ignore this flag and hardcode assumptions about lock state rather than dynamically checking it. This inconsistency creates gaps where critical sections of cleanup code execute without proper synchronization primitives. To resolve this issue, the fix involves modifying tcf_proto_destroy to explicitly acquire the rtnl_lock around the invocation of tp->ops->destroy for locked classifiers whenever the rtnl is not already held by the caller. This ensures that all destroy operations maintain consistent locking semantics regardless of how they are invoked.

From a security architecture perspective, this vulnerability aligns with CWE-416 Use After Free and CWE-362 Concurrent Execution using Shared Resource with Improper Synchronization Race Condition. The exploitation vector involves local users who can trigger concurrent network configuration changes through the tc command interface or equivalent netlink sockets. While remote exploitation is unlikely due to the requirement for specific kernel-level concurrency conditions, local attackers could leverage this race condition to destabilize the system or potentially escalate privileges if they can control the data written into the freed memory region before it is reallocated. The vulnerability highlights broader architectural issues within the classifier API where redundant checks and inconsistent lock handling create maintainability risks and security gaps.

Mitigation strategies include applying kernel patches that enforce rtnl_lock acquisition during protocol destruction phases for affected classifiers. System administrators should ensure their Linux kernels are updated to versions containing this fix, particularly those running network-intensive workloads with high concurrency in traffic control configurations. Additionally, code audits focusing on the cls_api module and individual classifier implementations can help identify similar patterns where lock state assumptions might lead to race conditions. Future development efforts should aim to simplify the rtnl_held parameter usage by removing redundant checks and standardizing how lock states are propagated through the tc_setup_cb_destroy calls across all supported classifiers, thereby reducing the surface area for such synchronization errors in future kernel releases.

Responsible

Linux

Reservation

08/15/2026

Disclosure

08/22/2026

Moderation

accepted

CPE

ready

EPSS

0.00000

KEV

no

Activities

very low

Sources

Do you want to use VulDB in your project?

Use the official API to access entries easily!