[PATCH] cgroup/cpuset: Skip security check for hotplug induced v1 task migration
From: Waiman Long
Date: Fri Mar 27 2026 - 16:29:12 EST
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>
---
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;
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;
--
2.53.0