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 <willdeacon@google.com>
This commit is contained in:
Will Deacon 2021-05-25 16:45:39 +01:00
commit 2f056f11e8

View file

@ -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 @@ out_set_mask:
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);
}