Patch "[PATCH 089/135] sched/numa: Fix use-after-free bug in the" has been added to the 4.4-stable tree
Subsystems (2)
This is a note to let you know that I've just added the patch titled
[PATCH 089/135] sched/numa: Fix use-after-free bug in the
to the 4.4-stable tree which can be found at:
http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary
The filename of the patch is:
0089-sched-numa-Fix-use-after-free-bug-in-the-task_numa_c.patch
and it can be found in the queue-4.4 subdirectory.
If you, or anyone else, feels it should not be added to the stable tree, please let <[email protected]> know about it.
Quoted 1 line
From
e4f58be65b185dcfc9ba8961bad0bd7d50e0bd3eMon Sep 17 00:00:00 2001
From: Gavin Guo <[email protected]>
Date: Wed, 20 Jan 2016 12:36:58 +0800
Subject: [PATCH 089/135] sched/numa: Fix use-after-free bug in the
task_numa_compare
[ Upstream commit 1dff76b92f69051e579bdc131e01500da9fa2a91 ]
The following message can be observed on the Ubuntu v3.13.0-65 with KASan backported:
==================================================================
BUG: KASan: use after free in task_numa_find_cpu+0x64c/0x890 at addr ffff880dd393ecd8 Read of size 8 by task qemu-system-x86/3998900 ============================================================================= BUG kmalloc-128 (Tainted: G B ): kasan: bad access detected -----------------------------------------------------------------------------
INFO: Allocated in task_numa_fault+0xc1b/0xed0 age=41980 cpu=18 pid=3998890
__slab_alloc+0x4f8/0x560 __kmalloc+0x1eb/0x280 task_numa_fault+0xc1b/0xed0 do_numa_page+0x192/0x200 handle_mm_fault+0x808/0x1160 __do_page_fault+0x218/0x750 do_page_fault+0x1a/0x70 page_fault+0x28/0x30 SyS_poll+0x66/0x1a0 system_call_fastpath+0x1a/0x1f INFO: Freed in task_numa_free+0x1d2/0x200 age=62 cpu=18 pid=0 __slab_free+0x2ab/0x3f0 kfree+0x161/0x170 task_numa_free+0x1d2/0x200 finish_task_switch+0x1d2/0x210 __schedule+0x5d4/0xc60 schedule_preempt_disabled+0x40/0xc0 cpu_startup_entry+0x2da/0x340 start_secondary+0x28f/0x360 Call Trace: [<ffffffff81a6ce35>] dump_stack+0x45/0x56 [<ffffffff81244aed>] print_trailer+0xfd/0x170 [<ffffffff8124ac36>] object_err+0x36/0x40 [<ffffffff8124cbf9>] kasan_report_error+0x1e9/0x3a0 [<ffffffff8124d260>] kasan_report+0x40/0x50 [<ffffffff810dda7c>] ? task_numa_find_cpu+0x64c/0x890 [<ffffffff8124bee9>] __asan_load8+0x69/0xa0 [<ffffffff814f5c38>] ? find_next_bit+0xd8/0x120 [<ffffffff810dda7c>] task_numa_find_cpu+0x64c/0x890 [<ffffffff810de16c>] task_numa_migrate+0x4ac/0x7b0 [<ffffffff810de523>] numa_migrate_preferred+0xb3/0xc0 [<ffffffff810e0b88>] task_numa_fault+0xb88/0xed0 [<ffffffff8120ef02>] do_numa_page+0x192/0x200 [<ffffffff81211038>] handle_mm_fault+0x808/0x1160 [<ffffffff810d7dbd>] ? sched_clock_cpu+0x10d/0x160 [<ffffffff81068c52>] ? native_load_tls+0x82/0xa0 [<ffffffff81a7bd68>] __do_page_fault+0x218/0x750 [<ffffffff810c2186>] ? hrtimer_try_to_cancel+0x76/0x160 [<ffffffff81a6f5e7>] ? schedule_hrtimeout_range_clock.part.24+0xf7/0x1c0 [<ffffffff81a7c2ba>] do_page_fault+0x1a/0x70 [<ffffffff81a772e8>] page_fault+0x28/0x30 [<ffffffff8128cbd4>] ? do_sys_poll+0x1c4/0x6d0 [<ffffffff810e64f6>] ? enqueue_task_fair+0x4b6/0xaa0 [<ffffffff810233c9>] ? sched_clock+0x9/0x10 [<ffffffff810cf70a>] ? resched_task+0x7a/0xc0 [<ffffffff810d0663>] ? check_preempt_curr+0xb3/0x130 [<ffffffff8128b5c0>] ? poll_select_copy_remaining+0x170/0x170 [<ffffffff810d3bc0>] ? wake_up_state+0x10/0x20 [<ffffffff8112a28f>] ? drop_futex_key_refs.isra.14+0x1f/0x90 [<ffffffff8112d40e>] ? futex_requeue+0x3de/0xba0 [<ffffffff8112e49e>] ? do_futex+0xbe/0x8f0 [<ffffffff81022c89>] ? read_tsc+0x9/0x20 [<ffffffff8111bd9d>] ? ktime_get_ts+0x12d/0x170 [<ffffffff8108f699>] ? timespec_add_safe+0x59/0xe0 [<ffffffff8128d1f6>] SyS_poll+0x66/0x1a0 [<ffffffff81a830dd>] system_call_fastpath+0x1a/0x1f
As commit 1effd9f19324 ("sched/numa: Fix unsafe get_task_struct() in task_numa_assign()") points out, the rcu_read_lock() cannot protect the task_struct from being freed in the finish_task_switch(). And the bug happens in the process of calculation of imp which requires the access of p->numa_faults being freed in the following path:
do_exit()
current->flags |= PF_EXITING;
release_task()
~~delayed_put_task_struct()~~
schedule()
...
...
rq->curr = next;
context_switch()
finish_task_switch()
put_task_struct()
__put_task_struct()
task_numa_free()The fix here to get_task_struct() early before end of dst_rq->lock to protect the calculation process and also put_task_struct() in the corresponding point if finally the dst_rq->curr somehow cannot be assigned.
Additional credit to Liang Chen who helped fix the error logic and add the put_task_struct() to the place it missed.
--- kernel/sched/fair.c | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-)
kernel/sched/fair.c +23 -7
@@ -1191,8 +1191,6 @@ static void task_numa_assign(struct task {if (env->best_task)put_task_struct (env->best_task); -if (p) -get_task_struct (p); env->best_task = p; env->best_imp = imp;
@@ -1260,20 +1258,30 @@ static void task_numa_compare(struct taslong imp = env->p->numa_group ? groupimp : taskimp;long moveimp = imp;int dist = env->dist; +bool assigned = false;rcu_read_lock ();raw_spin_lock_irq (&dst_rq->lock); cur = dst_rq->curr;/* -* No need to move the exiting task, and this ensures that ->curr -* wasn't reaped and thus get_task_struct() in task_numa_assign() -* is safe under RCU read lock. -* Note that rcu_read_lock() itself can't protect from the final -* put_task_struct() after the last schedule(). +* No need to move the exiting task or idle task. */ if ((cur->flags &PF_EXITING ) ||is_idle_task (cur)) cur =NULL ; +else { +/* +* The task_struct must be protected here to protect the +* p->numa_faults access in the task_weight since the +* numa_faults could already be freed in the following path: +* finish_task_switch() +* --> put_task_struct() +* --> __put_task_struct() +* --> task_numa_free() +*/ +get_task_struct (cur); + } +raw_spin_unlock_irq (&dst_rq->lock);/*
@@ -1357,6 +1365,7 @@ balance:*/ if (!load_too_imbalanced (src_load, dst_load, env)) { imp = moveimp -1 ; +put_task_struct (cur); cur =NULL ; goto assign; }
@@ -1382,9 +1391,16 @@ balance: env->dst_cpu =select_idle_sibling (env->p, env->dst_cpu); assign: + assigned = true;task_numa_assign (env, cur, imp); unlock:rcu_read_unlock (); +/* +* The dst_rq->curr isn't assigned. The protection for task_struct is +* finished. +*/ +if (cur && !assigned) +put_task_struct (cur); } static void task_numa_find_cpu(struct task_numa_env *env,
Patches currently in stable-queue which might be from [email protected] are
queue-4.4/0089-sched-numa-Fix-use-after-free-bug-in-the-task_numa_c.patch