Skip to content

Commit

Permalink
sched_ext: fix race in scx_move_task() with exiting tasks
Browse files Browse the repository at this point in the history
There is a race with exiting tasks in scx_move_tasks() where we may fail
to check for autogroup tasks, leading to the following oops:

 WARNING: CPU: 2 PID: 100 at kernel/sched/ext.c:2571 scx_move_task+0x9f/0xb0
 ...
 Sched_ext: flatcg (enabled+all), task: runnable_at=-5ms
 RIP: 0010:scx_move_task+0x9f/0xb0
 Call Trace:
  <TASK>
  ? scx_move_task+0x9f/0xb0
  ? __warn+0x85/0x170
  ? scx_move_task+0x9f/0xb0
  ? report_bug+0x171/0x1a0
  ? handle_bug+0x3b/0x70
  ? exc_invalid_op+0x17/0x70
  ? asm_exc_invalid_op+0x1a/0x20
  ? scx_move_task+0x9f/0xb0
  sched_move_task+0x104/0x300
  do_exit+0x37d/0xb70
  ? lock_release+0xbe/0x270
  do_group_exit+0x37/0xa0
  __x64_sys_exit_group+0x18/0x20
  do_syscall_64+0x44/0xf0
  entry_SYSCALL_64_after_hwframe+0x6f/0x77

And a related NULL pointer dereference afterwards:

 BUG: kernel NULL pointer dereference, address: 0000000000000148

Prevent this by skipping scx_move_tasks() actions for exiting tasks.

Moreover, make scx_move_tasks() more reliable by triggering only the
WARN_ON_ONCE() and returning, instead of triggering also the bug
afterwards.

Signed-off-by: Andrea Righi <andrea.righi@canonical.com>
  • Loading branch information
Andrea Righi committed Dec 28, 2023
1 parent dad3fb6 commit 6b747e0
Showing 1 changed file with 9 additions and 2 deletions.
11 changes: 9 additions & 2 deletions kernel/sched/ext.c
Original file line number Diff line number Diff line change
Expand Up @@ -2560,15 +2560,22 @@ void scx_move_task(struct task_struct *p)
/*
* We're called from sched_move_task() which handles both cgroup and
* autogroup moves. Ignore the latter.
*
* Also ignore exiting tasks, because in the exit path tasks transition
* from the autogroup to the root group, so task_group_is_autogroup()
* alone isn't able to catch exiting autogroup tasks. This is safe for
* cgroup_move(), because cgroup migrations never happen for PF_EXITING
* tasks.
*/
if (task_group_is_autogroup(task_group(p)))
if (p->flags & PF_EXITING || task_group_is_autogroup(task_group(p)))
return;

if (!scx_enabled())
return;

if (SCX_HAS_OP(cgroup_move)) {
WARN_ON_ONCE(!p->scx.cgrp_moving_from);
if (WARN_ON_ONCE(!p->scx.cgrp_moving_from))
return;
SCX_CALL_OP_TASK(SCX_KF_UNLOCKED, cgroup_move, p,
p->scx.cgrp_moving_from, tg_cgrp(task_group(p)));
}
Expand Down

0 comments on commit 6b747e0

Please sign in to comment.