[PATCH] mm/migrate: find_mm_struct: fix race between security checks and suid exec
From: Oleg Nesterov
Date: Tue May 26 2026 - 10:51:11 EST
The target task can execute a setuid binary between ptrace_may_access()
and get_task_mm(). Protect this critical section with exec_update_lock.
I don't think cpuset_mems_allowed(task) should be called under
exec_update_lock, but this patch just tries to add the minimal fix.
Perhaps we can later add a common helper which can be used by
find_mm_struct() and kernel_migrate_pages().
Signed-off-by: Oleg Nesterov <oleg@xxxxxxxxxx>
---
mm/migrate.c | 13 +++++++++----
1 file changed, 9 insertions(+), 4 deletions(-)
diff --git a/mm/migrate.c b/mm/migrate.c
index 8a64291ab5b4..e4cf664fb161 100644
--- a/mm/migrate.c
+++ b/mm/migrate.c
@@ -2557,24 +2557,29 @@ static struct mm_struct *find_mm_struct(pid_t pid, nodemask_t *mem_nodes)
}
task = find_get_task_by_vpid(pid);
- if (!task) {
+ if (!task)
return ERR_PTR(-ESRCH);
- }
+ if (down_read_killable(&task->signal->exec_update_lock)) {
+ mm = ERR_PTR(-EINTR);
+ goto out;
+ }
/*
* Check if this process has the right to modify the specified
* process. Use the regular "ptrace_may_access()" checks.
*/
if (!ptrace_may_access(task, PTRACE_MODE_READ_REALCREDS)) {
mm = ERR_PTR(-EPERM);
- goto out;
+ goto unlock;
}
mm = ERR_PTR(security_task_movememory(task));
if (IS_ERR(mm))
- goto out;
+ goto unlock;
*mem_nodes = cpuset_mems_allowed(task);
mm = get_task_mm(task);
+unlock:
+ up_read(&task->signal->exec_update_lock);
out:
put_task_struct(task);
if (!mm)
--
2.52.0