[PATCH v3 0/4] sched/debug: Introduce per-CPU debugfs files
Aaron Tomlin <[email protected]>
| Newsgroups | gmane.linux.kernel |
|---|---|
| Message-ID | <[email protected]> |
Hi Peter, Juri, Ingo, Vincent, This patch series addresses a few pre-existing memory safety and list traversal concurrency issues in scheduler debugfs handlers, and introduces per-CPU debugfs files under /sys/kernel/debug/sched/cpu/cpu<N>/debug. Patch 1 fixes a potential use-after-free in print_cpu() where rq->curr is dereferenced locklessly to output the running task's PID. If the task exits concurrently and its reference count drops to zero, put_task_struct() schedules __put_task_struct_rcu_cb() via call_rcu(). Without holding an RCU read lock, an RCU grace period can elapse concurrently and free the task structure via free_task(), leading to a use-after-free race condition. This patch protects the rq->curr access using READ_ONCE() inside an RCU read-side critical section, delaying callback execution and guaranteeing memory safety. Patch 2 fixes a use-after-free in print_dl_rq() where cpu_rq(cpu)->rd is dereferenced locklessly to display deadline bandwidth statistics. During CPU hot-unplug or cgroup cpuset repartitioning events, partition_sched_domains() calls rq_attach_root() to detach the CPU from its root_domain and schedules free_rootdomain() via call_rcu(). Without an RCU read lock, an RCU grace period can resolve concurrently while debugfs reads the file, allowing free_rootdomain() to execute kfree() and causing a UAF when reading dl_bw->bw. This patch fetches rq->rd using READ_ONCE() inside an RCU read-side critical section to guarantee memory safety. Patch 3 fixes an RCU traversal violation in print_cfs_stats() where rq->leaf_cfs_rq_list is traversed locklessly using for_each_leaf_cfs_rq_safe(), which expands to list_for_each_entry_safe(). Although leaf_cfs_rq_list is modified using list_add_rcu(), list_for_each_entry_safe() lacks READ_ONCE(), allowing compiler instruction reordering or re-fetching that can cause readers to observe newly inserted cfs_rq nodes before their internal fields are fully visible. This patch introduces for_each_leaf_cfs_rq_rcu() using list_for_each_entry_rcu(). Patch 4 introduces per-CPU debugfs entries under /sys/kernel/debug/sched/cpu/, allowing targeted inspection of an individual CPU's runqueue on demand. If the target CPU is currently offline, reading its file returns -ENODEV. Changes since v2: - Protected lockless rq->curr dereferencing in print_cpu() with rcu_read_lock() and READ_ONCE() - Protected lockless rq->rd dereferencing in print_dl_rq() against CPU hot-unplug and cgroup cpuset repartitioning races - Introduced for_each_leaf_cfs_rq_rcu() using list_for_each_entry_rcu() for lockless leaf_cfs_rq_list iteration - Linked to v2: https://lore.kernel.org/lkml/[email protected]/ Changes since v1: - Reframed commit message motivation around targeted interactive debugging on large SMP topologies (Peter Zijlstra and Zhan Xusheng) - Gated sched_debug_cpu_show() with a cpu_online(cpu) check returning -ENODEV when target CPU is offline (Zhan Xusheng) - Linked to v1: https://lore.kernel.org/lkml/[email protected]/ Aaron Tomlin (4): sched/debug: Protect lockless rq->curr access in print_cpu() sched/debug: Protect lockless rq->rd access in print_dl_rq() sched/fair: Use list_for_each_entry_rcu() in print_cfs_stats() sched/debug: Introduce per-CPU debugfs files kernel/sched/debug.c | 60 +++++++++++++++++++++++++++++++++++++++++--- kernel/sched/fair.c | 11 ++++++-- 2 files changed, 65 insertions(+), 6 deletions(-) -- 2.55.0