shield: procs: do not accept illegal user affinity masks. By accident, an affinity mask of all-zeros (or indeed, any mask which did not have a single online cpu in it), caused sched_setaffinity to correctly return EINVAL. However, unknown to us, the bad user affinity mask was being accepted anyways. The end result was that the user mask of some thread was set to all-zero, while the actual affinity mask was left alone. This bug was introduced during the port of 5.4-RedHawk to 5.10. Fixed-by: Joe Korty while at concurrent-rt.com Index: b/kernel/sched/core.c =================================================================== --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -2247,27 +2247,26 @@ void do_set_cpus_allowed(struct task_str /* * do_set_cpus_allowed_check -- returns an error if a useful actual affinity - * cannot be generated from the given mask. + * cannot be generated from the given (user) mask. That is, the user affinity + * must contain at least one online but not downed CPU in order for it to + * be considered valid. */ #ifdef CONFIG_CPU_DOWNING -/* Return -EINVAL if the reduced mask contains downed cpus. We do this - * kind of check only at the user interface to process affinity; internal - * affinity changes do not follow this path and are thus not rejected - * by this test. - */ int do_set_cpus_allowed_check(const struct cpumask *new_user_mask) { - cpumask_t new_mask; /* bad when on stack, #cpus >1k kinda iffy */ + cpumask_t new_mask; /* bad when on stack as nr_cpus >1k kinda iffy */ - mkshield(&new_mask, new_user_mask, &shielded_procs); - return cpumask_intersects(&new_mask, &downed_cpus) ? -EINVAL : 0; + cpumask_andnot(&new_mask, new_user_mask, &downed_cpus); + return !cpumask_intersects(&new_mask, cpu_online_mask) ? -EINVAL : 0; } + #else /* !CONFIG_CPU_DOWNING */ + int do_set_cpus_allowed_check(const struct cpumask *new_user_mask) { - return 0; + return !cpumask_intersects(new_user_mask, cpu_online_mask) ? -EINVAL : 0; } #endif /* CONFIG_CPU_DOWNING */ @@ -7071,9 +7070,11 @@ long sched_setaffinity(pid_t pid, const } #endif again: - cpumask_copy(&p->cpus_mask_user, new_mask); - if (p->affinity_detached) + if (p->affinity_detached) { + if (do_set_cpus_allowed_check(new_mask) == 0) + cpumask_copy(&p->cpus_mask_user, new_mask); goto out_free_new_mask; + } if (!alloc_cpumask_var(&actual_mask, GFP_KERNEL)) { retval = __set_cpus_allowed_ptr(p, new_mask, SCA_CHECK); @@ -7084,6 +7085,7 @@ again: } if (!retval) { + cpumask_copy(&p->cpus_mask_user, new_mask); recalc_task_numa_balance(p); /* before mem shielding recalc */ recalc_task_mem_shielding(p); cpuset_cpus_allowed(p, cpus_allowed);