| From a6e47e161a4c48e0b083225029ef3192351f344b Mon Sep 17 00:00:00 2001 |
| From: KeMeng Shi <shikemeng@huawei.com> |
| Date: Mon, 16 Sep 2019 06:53:28 +0000 |
| Subject: [PATCH] sched/core: Fix migration to invalid CPU in |
| __set_cpus_allowed_ptr() |
| |
| commit 714e501e16cd473538b609b3e351b2cc9f7f09ed upstream. |
| |
| An oops can be triggered in the scheduler when running qemu on arm64: |
| |
| Unable to handle kernel paging request at virtual address ffff000008effe40 |
| Internal error: Oops: 96000007 [#1] SMP |
| Process migration/0 (pid: 12, stack limit = 0x00000000084e3736) |
| pstate: 20000085 (nzCv daIf -PAN -UAO) |
| pc : __ll_sc___cmpxchg_case_acq_4+0x4/0x20 |
| lr : move_queued_task.isra.21+0x124/0x298 |
| ... |
| Call trace: |
| __ll_sc___cmpxchg_case_acq_4+0x4/0x20 |
| __migrate_task+0xc8/0xe0 |
| migration_cpu_stop+0x170/0x180 |
| cpu_stopper_thread+0xec/0x178 |
| smpboot_thread_fn+0x1ac/0x1e8 |
| kthread+0x134/0x138 |
| ret_from_fork+0x10/0x18 |
| |
| __set_cpus_allowed_ptr() will choose an active dest_cpu in affinity mask to |
| migrage the process if process is not currently running on any one of the |
| CPUs specified in affinity mask. __set_cpus_allowed_ptr() will choose an |
| invalid dest_cpu (dest_cpu >= nr_cpu_ids, 1024 in my virtual machine) if |
| CPUS in an affinity mask are deactived by cpu_down after cpumask_intersects |
| check. cpumask_test_cpu() of dest_cpu afterwards is overflown and may pass if |
| corresponding bit is coincidentally set. As a consequence, kernel will |
| access an invalid rq address associate with the invalid CPU in |
| migration_cpu_stop->__migrate_task->move_queued_task and the Oops occurs. |
| |
| The reproduce the crash: |
| |
| 1) A process repeatedly binds itself to cpu0 and cpu1 in turn by calling |
| sched_setaffinity. |
| |
| 2) A shell script repeatedly does "echo 0 > /sys/devices/system/cpu/cpu1/online" |
| and "echo 1 > /sys/devices/system/cpu/cpu1/online" in turn. |
| |
| 3) Oops appears if the invalid CPU is set in memory after tested cpumask. |
| |
| Signed-off-by: KeMeng Shi <shikemeng@huawei.com> |
| Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> |
| Reviewed-by: Valentin Schneider <valentin.schneider@arm.com> |
| Cc: Linus Torvalds <torvalds@linux-foundation.org> |
| Cc: Peter Zijlstra <peterz@infradead.org> |
| Cc: Thomas Gleixner <tglx@linutronix.de> |
| Link: https://lkml.kernel.org/r/1568616808-16808-1-git-send-email-shikemeng@huawei.com |
| Signed-off-by: Ingo Molnar <mingo@kernel.org> |
| Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> |
| |
| diff --git a/kernel/sched/core.c b/kernel/sched/core.c |
| index b78986ce1f6b..be7c380c07e6 100644 |
| --- a/kernel/sched/core.c |
| +++ b/kernel/sched/core.c |
| @@ -1129,7 +1129,8 @@ static int __set_cpus_allowed_ptr(struct task_struct *p, |
| if (cpumask_equal(&p->cpus_allowed, new_mask)) |
| goto out; |
| |
| - if (!cpumask_intersects(new_mask, cpu_valid_mask)) { |
| + dest_cpu = cpumask_any_and(cpu_valid_mask, new_mask); |
| + if (dest_cpu >= nr_cpu_ids) { |
| ret = -EINVAL; |
| goto out; |
| } |
| @@ -1150,7 +1151,6 @@ static int __set_cpus_allowed_ptr(struct task_struct *p, |
| if (cpumask_test_cpu(task_cpu(p), new_mask)) |
| goto out; |
| |
| - dest_cpu = cpumask_any_and(cpu_valid_mask, new_mask); |
| if (task_running(rq, p) || p->state == TASK_WAKING) { |
| struct migration_arg arg = { p, dest_cpu }; |
| /* Need help from migration thread: drop lock and wait. */ |
| -- |
| 2.7.4 |
| |