Thread (26 messages) 26 messages, 2 authors, 21h ago
HOTtoday

[RFC PATCH 09/24] fork: let process builders supply preallocated pids

From: Li Chen <hidden>
Date: 2026-07-16 14:37:58
Also in: linux-arch, linux-doc, linux-fsdevel, linux-kselftest, linux-mm, linux-security-module, lkml
Subsystem: exec & binfmt api, elf, memory management - core, scheduler, the rest · Maintainers: Kees Cook, Andrew Morton, David Hildenbrand, Ingo Molnar, Peter Zijlstra, Juri Lelli, Vincent Guittot, Linus Torvalds

Process builders can reserve a pidfs identity before copy_process()
makes a task visible. Add an alloc_pid() variant for a reserved pidfs
inode, and let copy_process() consume a caller-provided struct pid on
success.

Keep caller ownership on failure. The legacy NULL-pid path continues to
allocate and free its own pid. Validate the target PID namespace before
using a preallocated identity.

Assisted-by: Codex:gpt-5.6-sol
Signed-off-by: Li Chen <redacted>
---
 include/linux/pid.h |  3 +++
 kernel/fork.c       | 16 ++++++++++++++--
 kernel/pid.c        | 22 ++++++++++++++++++++--
 3 files changed, 37 insertions(+), 4 deletions(-)
diff --git a/include/linux/pid.h b/include/linux/pid.h
index a29ffe2a5fa8e..fa8acae336f7c 100644
--- a/include/linux/pid.h
+++ b/include/linux/pid.h
@@ -142,6 +142,9 @@ extern struct pid *find_ge_pid(int nr, struct pid_namespace *);
 
 extern struct pid *alloc_pid(struct pid_namespace *ns, pid_t *set_tid,
 			     size_t set_tid_size);
+struct pid *alloc_pid_with_pidfs_ino(struct pid_namespace *ns,
+				     pid_t *set_tid, size_t set_tid_size,
+				     u64 pidfs_ino);
 extern void free_pid(struct pid *pid);
 void free_pids(struct pid **pids);
 extern void disable_pid_allocation(struct pid_namespace *ns);
diff --git a/kernel/fork.c b/kernel/fork.c
index 970810a01bbf6..d16405c037c2f 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -2006,6 +2006,9 @@ static bool need_futex_hash_allocate_default(u64 clone_flags)
  * It copies the registers, and all the appropriate
  * parts of the process environment (as per the clone
  * flags). The actual kick-off is left to the caller.
+ *
+ * Except for init_struct_pid, a caller-supplied pid reference remains owned
+ * by the caller on failure and is transferred to the new task on success.
  */
 __latent_entropy struct task_struct *copy_process(
 					struct pid *pid,
@@ -2017,6 +2020,7 @@ __latent_entropy struct task_struct *copy_process(
 	struct task_struct *p;
 	struct multiprocess_signals delayed;
 	struct file *pidfile = NULL;
+	bool allocated_pid = false;
 	const u64 clone_flags = args->flags;
 	struct nsproxy *nsp = current->nsproxy;
 
@@ -2317,13 +2321,21 @@ __latent_entropy struct task_struct *copy_process(
 
 	stackleak_task_init(p);
 
-	if (pid != &init_struct_pid) {
+	if (!pid) {
 		pid = alloc_pid(p->nsproxy->pid_ns_for_children, args->set_tid,
 				args->set_tid_size);
 		if (IS_ERR(pid)) {
 			retval = PTR_ERR(pid);
 			goto bad_fork_cleanup_thread;
 		}
+		allocated_pid = true;
+	} else if (pid != &init_struct_pid) {
+		if (args->set_tid_size ||
+		    ns_of_pid(pid) != p->nsproxy->pid_ns_for_children ||
+		    WARN_ON_ONCE(pid_has_task(pid, PIDTYPE_PID))) {
+			retval = -EINVAL;
+			goto bad_fork_cleanup_thread;
+		}
 	}
 
 	/*
@@ -2587,7 +2599,7 @@ __latent_entropy struct task_struct *copy_process(
 		put_unused_fd(pidfd);
 	}
 bad_fork_free_pid:
-	if (pid != &init_struct_pid)
+	if (allocated_pid)
 		free_pid(pid);
 bad_fork_cleanup_thread:
 	exit_thread(p);
diff --git a/kernel/pid.c b/kernel/pid.c
index f55189a3d07d4..010f80177cac8 100644
--- a/kernel/pid.c
+++ b/kernel/pid.c
@@ -156,8 +156,8 @@ void free_pids(struct pid **pids)
 			free_pid(pids[tmp]);
 }
 
-struct pid *alloc_pid(struct pid_namespace *ns, pid_t *arg_set_tid,
-		      size_t arg_set_tid_size)
+static struct pid *__alloc_pid(struct pid_namespace *ns, pid_t *arg_set_tid,
+			       size_t arg_set_tid_size, u64 pidfs_ino)
 {
 	int set_tid[MAX_PID_NS_LEVEL + 1] = {};
 	int pid_max[MAX_PID_NS_LEVEL + 1] = {};
@@ -198,6 +198,7 @@ struct pid *alloc_pid(struct pid_namespace *ns, pid_t *arg_set_tid,
 	init_waitqueue_head(&pid->wait_pidfd);
 	INIT_HLIST_HEAD(&pid->inodes);
 	pidfs_prepare_pid(pid);
+	pid->ino = pidfs_ino;
 
 	/*
 	 * 2. perm check checkpoint_restore_ns_capable()
@@ -358,6 +359,23 @@ struct pid *alloc_pid(struct pid_namespace *ns, pid_t *arg_set_tid,
 	return ERR_PTR(retval);
 }
 
+struct pid *alloc_pid(struct pid_namespace *ns, pid_t *arg_set_tid,
+		      size_t arg_set_tid_size)
+{
+	return __alloc_pid(ns, arg_set_tid, arg_set_tid_size, 0);
+}
+
+struct pid *alloc_pid_with_pidfs_ino(struct pid_namespace *ns,
+				     pid_t *arg_set_tid,
+				     size_t arg_set_tid_size,
+				     u64 pidfs_ino)
+{
+	if (!pidfs_ino)
+		return ERR_PTR(-EINVAL);
+
+	return __alloc_pid(ns, arg_set_tid, arg_set_tid_size, pidfs_ino);
+}
+
 void disable_pid_allocation(struct pid_namespace *ns)
 {
 	spin_lock(&pidmap_lock);
-- 
2.52.0
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help