From 2f056f11e88924bc25c14be9d8bdff3e5f486231 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Tue, 25 May 2021 16:45:39 +0100 Subject: [PATCH] ANDROID: sched: fix race with CPU hot-unplug when overriding affinity Migrating a task to a CPU which is concurrently being taken offline can cause the migration to fail silently, with the task left running on the old CPU. This is usually not the end of the world, but when forcefully migrating a 32-bit task during execve() from a 64-bit task, it is imperative that we do not attempt to return to userspace on a 64-bit-only CPU. Take the CPU hotplug lock for read while forcefully migrating a 32-bit task on execve() so that the migration cannot fail. Bug: 187917024 Change-Id: I6eaf2a564fe3ad73c03f0a6029aade09c707330f Signed-off-by: Will Deacon --- kernel/sched/core.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 836a0e5664a0..d3a864d3f201 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -2091,7 +2091,15 @@ void force_compatible_cpus_allowed_ptr(struct task_struct *p) cpumask_var_t new_mask; const struct cpumask *override_mask = task_cpu_possible_mask(p); - if (!alloc_cpumask_var(&new_mask, GFP_KERNEL)) + alloc_cpumask_var(&new_mask, GFP_KERNEL); + + /* + * __migrate_task() can fail silently in the face of concurrent + * offlining of the chosen destination CPU, so take the hotplug + * lock to ensure that the migration succeeds. + */ + cpus_read_lock(); + if (!cpumask_available(new_mask)) goto out_set_mask; if (!restrict_cpus_allowed_ptr(p, new_mask, override_mask)) @@ -2111,8 +2119,9 @@ void force_compatible_cpus_allowed_ptr(struct task_struct *p) cpumask_pr_args(override_mask)); } - set_cpus_allowed_ptr(p, override_mask); + WARN_ON(set_cpus_allowed_ptr(p, override_mask)); out_free_mask: + cpus_read_unlock(); free_cpumask_var(new_mask); }