Instituto Nacional de ciberseguridad. Sección Incibe
Instituto Nacional de Ciberseguridad. Sección INCIBE-CERT

CVE-2026-74700

Gravedad:
Pendiente de análisis
Tipo:
No Disponible / Otro tipo
Fecha de publicación:
22/08/2026
Última modificación:
22/08/2026

Descripción

*** Pendiente de traducción *** In the Linux kernel, the following vulnerability has been resolved:<br /> <br /> net/sched: cls_api: Always acquire rtnl_lock when destroying locked classifiers<br /> <br /> Another challenge with unlocked filters.<br /> There is a short window in tc_new_tfilter where a tcf_proto can be found<br /> and briefly referenced by a totally unrelated, unlocked classifier&amp;#39;s request<br /> and cause a race.<br /> <br /> Feng created a poc which created this race with two threads, one creating a<br /> u32 filter and other a flower filter in the same chain/prio:<br /> <br /> 1. Both threads enter tc_new_tfilter, both find the chain empty, both<br /> drop filter_chain_lock<br /> 2. u32 finishes tcf_proto_create("u32") first, calls<br /> tcf_chain_tp_insert_unique() -&gt; inserts u32_tp into the chain<br /> 3. flower finishes tcf_proto_create("flower") later, calls<br /> tcf_chain_tp_insert_unique() -&gt; tcf_chain_tp_find() now sees u32_tp<br /> already there, takes a reference on it, destroys flower&amp;#39;s own tp_new<br /> and returns u32_tp to the caller.<br /> <br /> Flower then hits the kind mismatch check (because it requested for kind<br /> "flower" but tp-&gt;ops-&gt;kind is "u32") and goes through the errout path<br /> which calls tcf_proto_put() on u32_tp. If the u32 thread has already<br /> gone through its own errout (its change() call failed on the PoC&amp;#39;s empty<br /> options) and dropped its create and insert refs, flower&amp;#39;s put is the<br /> last one and drops u32_tp&amp;#39;s refcnt to zero.<br /> <br /> At this point tp-&gt;ops-&gt;destroy() runs in a context that never took<br /> rtnl_lock. When that happens, it might cause a UAF like the following<br /> (illustrated by the PoC):<br /> <br /> [ +0.000710] BUG: KASAN: slab-use-after-free in u32_init (net/sched/cls_u32.c:393)<br /> [ +0.000281] Read of size 8 at addr ffff888120022f00 by task poc_feng_xue/524<br /> <br /> Call Trace:<br /> u32_init (net/sched/cls_u32.c:393)<br /> tc_new_tfilter (net/sched/cls_api.c:2378)<br /> <br /> Allocated by task 526:<br /> u32_init (net/sched/cls_u32.c:378)<br /> tc_new_tfilter (net/sched/cls_api.c:2378)<br /> <br /> Freed by task 522:<br /> kfree<br /> u32_destroy (net/sched/cls_u32.c:662)<br /> tcf_proto_destroy (net/sched/cls_api.c:446)<br /> tcf_proto_put (net/sched/cls_api.c:459)<br /> tc_new_tfilter (net/sched/cls_api.c:2459)<br /> <br /> Fix this by having tcf_proto_destroy() take rtnl_lock around<br /> tp-&gt;ops-&gt;destroy() for locked classifiers whenever rtnl is not held.<br /> <br /> To explain why I used a temp variable "not_lockless" I&amp;#39;d like to point to a<br /> semi-related note on rtnl_held vs TCF_PROTO_OPS_DOIT_UNLOCKED (adding here<br /> for future cleanup if deemed necessary):<br /> The rtnl_held parameter and the TCF_PROTO_OPS_DOIT_UNLOCKED flag are<br /> redundant sources of truth for whether rtnl_lock is held. Among the nine<br /> classifier destroy(..rtnl_held..) callbacks, only flower consults the<br /> rtnl_held parameter which it propagates to tc_setup_cb_destroy()<br /> and tc_setup_cb_call(). The other eight (u32, flow, bpf, cgroup, route, basic,<br /> fw, mall) ignore it entirely;-&gt; those that call tc_setup_cb_destroy()<br /> (u32, bpf, mall) hardcode true always instead of forwarding the parameter.<br /> <br /> A future cleanup should remove the rtnl_held parameter from the destroy callback<br /> signature entirely and have callers rely solely on their knowledge whether<br /> they are running in an unlocked context.

Impacto