• Zhang Qiao's avatar
    kernel/sched: Fix sched_fork() access an invalid sched_task_group · 4ef0c5c6
    Zhang Qiao authored
    There is a small race between copy_process() and sched_fork()
    where child->sched_task_group point to an already freed pointer.
    
    	parent doing fork()      | someone moving the parent
    				 | to another cgroup
      -------------------------------+-------------------------------
      copy_process()
          + dup_task_struct()<1>
    				  parent move to another cgroup,
    				  and free the old cgroup. <2>
          + sched_fork()
    	+ __set_task_cpu()<3>
    	+ task_fork_fair()
    	  + sched_slice()<4>
    
    In the worst case, this bug can lead to "use-after-free" and
    cause panic as shown above:
    
      (1) parent copy its sched_task_group to child at <1>;
    
      (2) someone move the parent to another cgroup and free the old
          cgroup at <2>;
    
      (3) the sched_task_group and cfs_rq that belong to the old cgroup
          will be accessed at <3> and <4>, which cause a panic:
    
      [] BUG: unable to handle kernel NULL pointer dereference at 0000000000000000
      [] PGD 8000001fa0a86067 P4D 8000001fa0a86067 PUD 2029955067 PMD 0
      [] Oops: 0000 [#1] SMP PTI
      [] CPU: 7 PID: 648398 Comm: ebizzy Kdump: loaded Tainted: G           OE    --------- -  - 4.18.0.x86_64+ #1
      [] RIP: 0010:sched_slice+0x84/0xc0
    
      [] Call Trace:
      []  task_fork_fair+0x81/0x120
      []  sched_fork+0x132/0x240
      []  copy_process.part.5+0x675/0x20e0
      []  ? __handle_mm_fault+0x63f/0x690
      []  _do_fork+0xcd/0x3b0
      []  do_syscall_64+0x5d/0x1d0
      []  entry_SYSCALL_64_after_hwframe+0x65/0xca
      [] RIP: 0033:0x7f04418cd7e1
    
    Between cgroup_can_fork() and cgroup_post_fork(), the cgroup
    membership and thus sched_task_group can't change. So update child's
    sched_task_group at sched_post_fork() and move task_fork() and
    __set_task_cpu() (where accees the sched_task_group) from sched_fork()
    to sched_post_fork().
    
    Fixes: 8323f26c ("sched: Fix race in task_group")
    Signed-off-by: default avatarZhang Qiao <zhangqiao22@huawei.com>
    Signed-off-by: default avatarPeter Zijlstra (Intel) <peterz@infradead.org>
    Acked-by: default avatarTejun Heo <tj@kernel.org>
    Link: https://lkml.kernel.org/r/20210915064030.2231-1-zhangqiao22@huawei.com
    4ef0c5c6
fork.c 77.7 KB