{"id":16124,"date":"2026-09-04T19:05:09","date_gmt":"2026-09-04T11:05:09","guid":{"rendered":"https:\/\/www.54iter.cn\/?vuln=cve-2026-46319"},"modified":"2026-09-04T19:05:09","modified_gmt":"2026-09-04T11:05:09","slug":"cve-2026-46319","status":"publish","type":"vuln","link":"https:\/\/www.54iter.cn\/?vuln=cve-2026-46319","title":{"rendered":"CVE-2026-46319 [HIGH] &#8211; In the Linux kernel, the following vulnerability has been resolved:\n\nnet\/sched: act_ct: On"},"content":{"rendered":"<p>In the Linux kernel, the following vulnerability has been resolved:<\/p>\n<p>net\/sched: act_ct: Only release RCU read lock after ct_ft<\/p>\n<p>When looking up a flow table in act_ct in tcf_ct_flow_table_get(),<br \/>\nrhashtable_lookup_fast() internally opens and closes an RCU read critical<br \/>\nsection before returning ct_ft.<br \/>\nThe tcf_ct_flow_table_cleanup_work() can complete before refcount_inc_not_zero()<br \/>\nis invoked on the returned ct_ft resulting in a UAF on the already freed ct_ft<br \/>\nobject. This vulnerability can lead to privilege escalation.<\/p>\n<p>Analysis from zdi-disclosures@trendmicro.com:<br \/>\nWhen initializing act_ct, tcf_ct_init() is called, which internally triggers<br \/>\ntcf_ct_flow_table_get().<\/p>\n<p>static int tcf_ct_flow_table_get(struct net *net, struct tcf_ct_params *params)<\/p>\n<p>{<br \/>\n                struct zones_ht_key key = { .net = net, .zone = params-&gt;zone };<br \/>\n                struct tcf_ct_flow_table *ct_ft;<br \/>\n                int err = -ENOMEM;<\/p>\n<p>                mutex_lock(&amp;zones_mutex);<br \/>\n                ct_ft = rhashtable_lookup_fast(&amp;zones_ht, &amp;key, zones_params); \/\/ [1]<br \/>\n                if (ct_ft &amp;&amp; refcount_inc_not_zero(&amp;ct_ft-&gt;ref)) \/\/ [2]<br \/>\n                                goto out_unlock;<br \/>\n                &#8230;<br \/>\n}<\/p>\n<p>static __always_inline void *rhashtable_lookup_fast(<br \/>\n                struct rhashtable *ht, const void *key,<br \/>\n                const struct rhashtable_params params)<br \/>\n{<br \/>\n                void *obj;<\/p>\n<p>                rcu_read_lock();<br \/>\n                obj = rhashtable_lookup(ht, key, params);<br \/>\n                rcu_read_unlock();<\/p>\n<p>                return obj;<br \/>\n}<\/p>\n<p>At [1], rhashtable_lookup_fast() looks up and returns the corresponding ct_ft<br \/>\nfrom zones_ht . The lookup is performed within an RCU read critical section<br \/>\nthrough rcu_read_lock() \/ rcu_read_unlock(), which prevents the object from<br \/>\nbeing freed. However, at the point of function return, rcu_read_unlock() has<br \/>\nalready been called, and there is nothing preventing ct_ft from being freed<br \/>\nbefore reaching refcount_inc_not_zero(&amp;ct_ft-&gt;ref) at [2]. This interval becomes<br \/>\nthe race window, during which ct_ft can be freed.<\/p>\n<p>Free Process:<\/p>\n<p>tcf_ct_flow_table_put() is executed through the path tcf_ct_cleanup() call_rcu()<br \/>\ntcf_ct_params_free_rcu() tcf_ct_params_free() tcf_ct_flow_table_put().<\/p>\n<p>static void tcf_ct_flow_table_put(struct tcf_ct_flow_table *ct_ft)<br \/>\n{<br \/>\n                if (refcount_dec_and_test(&amp;ct_ft-&gt;ref)) {<br \/>\n                                rhashtable_remove_fast(&amp;zones_ht, &amp;ct_ft-&gt;node, zones_params);<br \/>\n                                INIT_RCU_WORK(&amp;ct_ft-&gt;rwork, tcf_ct_flow_table_cleanup_work); \/\/ [3]<br \/>\n                                queue_rcu_work(act_ct_wq, &amp;ct_ft-&gt;rwork);<br \/>\n                }<br \/>\n}<\/p>\n<p>At [3], tcf_ct_flow_table_cleanup_work() is scheduled as RCU work<\/p>\n<p>static void tcf_ct_flow_table_cleanup_work(struct work_struct *work)<\/p>\n<p>{<br \/>\n                struct tcf_ct_flow_table *ct_ft;<br \/>\n                struct flow_block *block;<\/p>\n<p>                ct_ft = container_of(to_rcu_work(work), struct tcf_ct_flow_table,<br \/>\n                                                                rwork);<br \/>\n                nf_flow_table_free(&amp;ct_ft-&gt;nf_ft);<br \/>\n                block = &amp;ct_ft-&gt;nf_ft.flow_block;<br \/>\n                down_write(&amp;ct_ft-&gt;nf_ft.flow_block_lock);<br \/>\n                WARN_ON(!list_empty(&amp;block-&gt;cb_list));<br \/>\n                up_write(&amp;ct_ft-&gt;nf_ft.flow_block_lock);<br \/>\n                kfree(ct_ft); \/\/ [4]<\/p>\n<p>                module_put(THIS_MODULE);<br \/>\n}<\/p>\n<p>tcf_ct_flow_table_cleanup_work() frees ct_ft at [4]. When this function executes<br \/>\nbetween [1] and [2], UAF occurs.<\/p>\n<p>This race condition has a very short race window, making it generally<br \/>\ndifficult to trigger. Therefore, to trigger the vulnerability an msleep(100) was<br \/>\ninserted after[1]<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In the Linux kernel, the following vulnerability has been resolved:<\/p>\n<p>net\/sched: act_ct: Only release RCU read lock after ct_ft<\/p>\n<p>When looking up a flow table in act_ct in tcf_ct_flow_table_get(),<br \/>\nrhash<\/p>\n","protected":false},"template":"","meta":[],"categories":[],"tags":[],"class_list":["post-16124","vuln","type-vuln","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/www.54iter.cn\/index.php?rest_route=\/wp\/v2\/vuln\/16124","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.54iter.cn\/index.php?rest_route=\/wp\/v2\/vuln"}],"about":[{"href":"https:\/\/www.54iter.cn\/index.php?rest_route=\/wp\/v2\/types\/vuln"}],"wp:attachment":[{"href":"https:\/\/www.54iter.cn\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=16124"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.54iter.cn\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=16124"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.54iter.cn\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=16124"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}