Re: [PATCH] cgroup/cpuset: Skip security check for hotplug induced v1 task migration

From: Chen Ridong

Date: Fri Mar 27 2026 - 21:40:34 EST




On 2026/3/28 4:15, Waiman Long wrote:
> When a CPU hot removal causes a v1 cpuset to lose all its CPUs, the
> cpuset hotplug handler will schedule a work function to migrate tasks
> in that cpuset with no CPU to its parent to enable those tasks to
> continue running.
>
> If a strict security policy is in place, however, the task migration
> may fail when security_task_setscheduler() call in cpuset_can_attach()
> returns a -EACCESS error. That will mean that those tasks will have
> no CPU to run on. The system administrators will have to explicitly
> intervene to either add CPUs to that cpuset or move the tasks elsewhere
> if they are aware of it.
>
> This problem was found by a reported test failure in the LTP's
> cpuset_hotplug_test.sh. Fix this problem by treating this special case
> as an exception to skip the setsched security check as it is initated
> internally within the kernel itself instead of from user input. With that
> patch applied, the cpuset_hotplug_test.sh test can be run successfully
> without failure.
>
> Signed-off-by: Waiman Long <longman@xxxxxxxxxx>

Should we add a Fixes tag?

> ---
> kernel/cgroup/cpuset.c | 18 +++++++++++++++++-
> 1 file changed, 17 insertions(+), 1 deletion(-)
>
> diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c
> index d21868455341..88ce7ed91cd1 100644
> --- a/kernel/cgroup/cpuset.c
> +++ b/kernel/cgroup/cpuset.c
> @@ -2989,6 +2989,7 @@ static int cpuset_can_attach(struct cgroup_taskset *tset)
> struct cpuset *cs, *oldcs;
> struct task_struct *task;
> bool cpus_updated, mems_updated;
> + bool kthread_move_task_from_empty_cs;

This name is too long. How about `kthread_nocpus`?

> int ret;
>
> /* used later by cpuset_attach() */
> @@ -3006,6 +3007,14 @@ static int cpuset_can_attach(struct cgroup_taskset *tset)
> cpus_updated = !cpumask_equal(cs->effective_cpus, oldcs->effective_cpus);
> mems_updated = !nodes_equal(cs->effective_mems, oldcs->effective_mems);
>
> + /*
> + * Set to true if a kthread is moving tasks away from a v1 cpuset with
> + * no CPUs
> + */
> + kthread_move_task_from_empty_cs = !cpuset_v2() &&
> + cpumask_empty(oldcs->effective_cpus) &&
> + (current->flags & PF_KTHREAD);
> +
> cgroup_taskset_for_each(task, css, tset) {
> ret = task_can_attach(task);
> if (ret)
> @@ -3015,8 +3024,15 @@ static int cpuset_can_attach(struct cgroup_taskset *tset)
> * Skip rights over task check in v2 when nothing changes,
> * migration permission derives from hierarchy ownership in
> * cgroup_procs_write_permission()).
> + *
> + * In the special case of forced cpuset1 task migration to
> + * parent via workqueue because of empty cpuset.cpus caused by
> + * hotplug, skip the task check to prevent restrictive security
> + * policy from denying the task migration. Otherwise those
> + * tasks will have no CPU to run on.
> */
> - if (!cpuset_v2() || (cpus_updated || mems_updated)) {
> + if (!kthread_move_task_from_empty_cs &&
> + (!cpuset_v2() || cpus_updated || mems_updated)) {
> ret = security_task_setscheduler(task);
> if (ret)
> goto out_unlock;

--
Best regards,
Ridong