{"id":29676,"date":"2026-09-26T20:31:46","date_gmt":"2026-09-26T12:31:46","guid":{"rendered":"https:\/\/www.54iter.cn\/?vuln=cve-2026-98163"},"modified":"2026-09-26T20:31:46","modified_gmt":"2026-09-26T12:31:46","slug":"cve-2026-98163","status":"publish","type":"vuln","link":"https:\/\/www.54iter.cn\/?vuln=cve-2026-98163","title":{"rendered":"CVE-2026-98163 &#8211; In the Linux kernel, the following vulnerability has been resolved:\n\ncgroup: Avoid iterati"},"content":{"rendered":"<p>In the Linux kernel, the following vulnerability has been resolved:<\/p>\n<p>cgroup: Avoid iteration of dying tasks with zero refcount<\/p>\n<p>The commit 260fbcb92bbea (&#8220;cgroup: Move dying_tasks cleanup from<br \/>\ncgroup_task_release() to cgroup_task_free()&#8221;) extended the lifetime of<br \/>\ntasks on the dying_tasks list.<br \/>\nThe iterators have provision to go through dying_tasks because of<br \/>\ndying threadgroup leaders or explicit CSS_TASK_ITER_WITH_DEAD, however,<br \/>\nit was expected that such tasks can obtain a new reference (that is<br \/>\npossible before cgroup_task_release()\/put_task_struct_rcu_user()).<br \/>\nThe tasks after cgroup_task_release() and before cgroup_task_free()<br \/>\nare subject to race when they may or may not have -&gt;usage count &gt; 0.<\/p>\n<p>The race window is between css_task_iter_next() invocations<br \/>\nwhen css_set_lock is released and we may arrive at a new -&gt;task_pos.<br \/>\nThe iterator should not attempt to resurrect tasks whose -&gt;usage count<br \/>\ndropped to zero. (When that happens, __put_task_struct_rcu_cb() is<br \/>\nalready imminent and the returned task_struct would could be used<br \/>\nafter free.)<\/p>\n<p>As for the fix, we cannot simply check the signal-&gt;live count of a task<br \/>\non the dying list because that won&#8217;t distinguish regular zombies waiting<br \/>\nto be reaped from RCU remnant tasks that are going to be free&#8217;d.<br \/>\nTherefore add an extra check to rule out -&gt;usage==0 tasks from any<br \/>\niteration.<\/p>\n<p>The repeat: loop in css_task_iter_advance() doesn&#8217;t consider -&gt;usage<br \/>\ncount, so add a new loop to css_task_iter_next() to skip de-used tasks<br \/>\non the dying_list.<\/p>\n<p>Rough illustration of the possible race<\/p>\n<p>  R (reader of cgroup.procs)         T (thread)                       L (group leader)<br \/>\n  &#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;  &#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211; &#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;<br \/>\n                                                                      L exits, signal-&gt;live &gt; 0<br \/>\n                                                                      cgroup_task_dead(L)<br \/>\n                                                                        css_set_skip_task_iters() \/\/ skips only cset-&gt;tasks<br \/>\n                                                                        list_add_tail(&amp;L-&gt;cg_list, &amp;cset-&gt;dying_tasks)<br \/>\n  css_task_iter_next()<br \/>\n    take css_set_lock<br \/>\n    css_task_iter_advance()<br \/>\n      leader &amp;&amp; signal-&gt;live != 0<br \/>\n      =&gt; it-&gt;task_pos = &amp;L-&gt;cg_list<br \/>\n    release css_set_lock<br \/>\n                                     T exits<br \/>\n                                     &#8211;signal-&gt;live == 0<br \/>\n\t\t\t\t     cgroup_task_dead(T) \/\/ css_set_lock<br \/>\n                                     release_task(T)<br \/>\n                                       cgroup_task_release(T)<br \/>\n                                       release_task(L) \/\/ zap_leader<br \/>\n                                         cgroup_task_release(L)<br \/>\n                                         put_task_struct_rcu_user(L)<br \/>\n                                         &#8230;RCU&#8230;<br \/>\n                                         put_task_struct(L)<br \/>\n                                           L-&gt;usage = 0<br \/>\n                                           \/* L still on dying_tasks *\/<br \/>\n                                           &#8230;RCU&#8230;<br \/>\n                                           __put_task_struct(L)<br \/>\n  css_task_iter_next() \/\/ another iteration<br \/>\n    take css_set_lock<br \/>\n    it-&gt;task_pos = &amp;L-&gt;cg_list<br \/>\n    get_task_struct(L)<br \/>\n      =&gt; addition on 0<br \/>\n    drop css_set_lock<br \/>\n                                           cgroup_task_free(L)<br \/>\n                                             css_set_skip_task_iters() \/\/ dying skip comes too late<br \/>\n                                           free_task(L)<br \/>\n  cgroup_procs_show()<br \/>\n    task_pid_vnr(L)<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In the Linux kernel, the following vulnerability has been resolved:<\/p>\n<p>cgroup: Avoid iteration of dying tasks with zero refcount<\/p>\n<p>The commit 260fbcb92bbea (&#8220;cgroup: Move dying_tasks cleanup from<br \/>\ncgroup_<\/p>\n","protected":false},"template":"","meta":[],"categories":[],"tags":[],"class_list":["post-29676","vuln","type-vuln","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/www.54iter.cn\/index.php?rest_route=\/wp\/v2\/vuln\/29676","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=29676"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.54iter.cn\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=29676"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.54iter.cn\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=29676"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}