Process builders need to run setup in the child before its first return
to userspace without storing a kernel callback in architecture-specific
saved registers.

Allow an internal clone caller to supply task work. Queue it after the
last ordinary fork failure check, while the child is still TASK_NEW. A
NULL work pointer leaves existing clone callers unchanged.

Assisted-by: Codex:gpt-5.6-sol
Signed-off-by: Li Chen <[email protected]>
---
 include/linux/sched/task.h | 2 ++
 kernel/fork.c              | 6 ++++++
 2 files changed, 8 insertions(+)

diff --git a/include/linux/sched/task.h b/include/linux/sched/task.h
index 5b7facf12b33b..830de99aabaed 100644
--- a/include/linux/sched/task.h
+++ b/include/linux/sched/task.h
@@ -43,6 +43,8 @@ struct kernel_clone_args {
        int idle;
        int (*fn)(void *);
        void *fn_arg;
+       /* Run before the new task first returns to userspace. */
+       struct callback_head *task_work;
        struct cgroup *cgrp;
        struct css_set *cset;
        bool embryonic_exec;
diff --git a/kernel/fork.c b/kernel/fork.c
index e3ade83b2d4e2..c0584eaa74711 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -109,6 +109,7 @@
 #include <uapi/linux/pidfd.h>
 #include <linux/pidfs.h>
 #include <linux/tick.h>
+#include <linux/task_work.h>
 #include <linux/unwind_deferred.h>
 #include <linux/pgalloc.h>
 #include <linux/uaccess.h>
@@ -2504,6 +2505,11 @@ __latent_entropy struct task_struct *copy_process(
                retval = -EINTR;
                goto bad_fork_core_free;
        }
+       if (args->task_work) {
+               retval = task_work_add(p, args->task_work, TWA_RESUME);
+               if (WARN_ON_ONCE(retval))
+                       goto bad_fork_core_free;
+       }
 
        /* No more failure paths after this point. */
 
-- 
2.52.0


Reply via email to