From: Li Chen <me@linux.beauty>
To: Christian Brauner <brauner@kernel.org>
Cc: "Kees Cook" <kees@kernel.org>,
"Gabriel Krisman Bertazi" <krisman@kernel.org>,
"Josh Triplett" <josh@joshtriplett.org>,
"Mateusz Guzik" <mjguzik@gmail.com>,
"Andy Lutomirski" <luto@kernel.org>,
"John Ericson" <mail@johnericson.me>,
"Jonathan Corbet" <corbet@lwn.net>,
"Shuah Khan" <shuah@kernel.org>, "Arnd Bergmann" <arnd@arndb.de>,
"Oleg Nesterov" <oleg@redhat.com>,
"Andrew Morton" <akpm@linux-foundation.org>,
"Paul Moore" <paul@paul-moore.com>,
"Eric Paris" <eparis@redhat.com>,
"Mickaël Salaün" <mic@digikod.net>,
"Günther Noack" <gnoack@google.com>,
"Alexander Viro" <viro@zeniv.linux.org.uk>,
"Jan Kara" <jack@suse.cz>,
linux-api@vger.kernel.org, linux-fsdevel@vger.kernel.org,
linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org,
linux-doc@vger.kernel.org, audit@vger.kernel.org,
linux-security-module@vger.kernel.org,
linux-arch@vger.kernel.org, linux-mm@kvack.org,
"Li Chen" <me@linux.beauty>
Subject: [RFC PATCH 09/24] fork: let process builders supply preallocated pids
Date: Thu, 16 Jul 2026 22:31:35 +0800 [thread overview]
Message-ID: <129eedc78affaf85e4d552daae1460a43057fb39.1784204592.git.me@linux.beauty> (raw)
In-Reply-To: <cover.1784204592.git.me@linux.beauty>
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 <me@linux.beauty>
---
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
next prev parent reply other threads:[~2026-07-16 14:37 UTC|newest]
Thread overview: 26+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-16 14:31 [RFC PATCH 00/24] pidfd: add a minimal process spawn builder Li Chen
2026-07-16 14:31 ` [RFC PATCH 01/24] pidfd: add spawn builder uapi Li Chen
2026-07-16 14:31 ` [RFC PATCH 02/24] libfs: allow custom validation of stashed inode data Li Chen
2026-07-16 14:31 ` [RFC PATCH 03/24] pidfs: add taskless future pidfd inodes Li Chen
2026-07-16 14:31 ` [RFC PATCH 04/24] pidfd: create taskless spawn builders Li Chen
2026-07-16 14:31 ` [RFC PATCH 05/24] pidfd: add spawn builder path configuration Li Chen
2026-07-16 14:31 ` [RFC PATCH 06/24] exec: expose execveat internals to process builders Li Chen
2026-07-16 14:31 ` [RFC PATCH 07/24] fork: expose vfork completion helper Li Chen
2026-07-16 14:31 ` [RFC PATCH 08/24] pidfs: attach pids to future pidfd files Li Chen
2026-07-16 14:31 ` Li Chen [this message]
2026-07-16 14:31 ` [RFC PATCH 10/24] pidfs: publish " Li Chen
2026-07-16 14:31 ` [RFC PATCH 11/24] pidfd: add spawn builder state tracking Li Chen
2026-07-16 14:31 ` [RFC PATCH 12/24] fork: let kernel callers create embryonic tasks Li Chen
2026-07-16 15:57 ` Andy Lutomirski
2026-07-16 14:31 ` [RFC PATCH 13/24] fork: let new tasks start with task work Li Chen
2026-07-16 14:31 ` [RFC PATCH 14/24] pidfd: create and execute spawn builder tasks Li Chen
2026-07-16 14:31 ` [RFC PATCH 15/24] fork: keep embryonic tasks hidden until exec completes Li Chen
2026-07-16 14:31 ` [RFC PATCH 16/24] audit: add pidfd spawn child contexts Li Chen
2026-07-16 14:31 ` [RFC PATCH 17/24] pidfd: audit child spawn execution Li Chen
2026-07-16 14:31 ` [RFC PATCH 18/24] pidfd: make spawn builder execution signal-safe Li Chen
2026-07-16 14:31 ` [RFC PATCH 19/24] file: expose spawn file-action helpers Li Chen
2026-07-16 14:31 ` [RFC PATCH 20/24] pidfd: add initial spawn file actions Li Chen
2026-07-16 14:31 ` [RFC PATCH 21/24] pidfd: consume spawn builders on the first run attempt Li Chen
2026-07-16 14:31 ` [RFC PATCH 22/24] pidfd: expose spawn builder system calls Li Chen
2026-07-16 14:31 ` [RFC PATCH 23/24] selftests/pidfd: cover pidfd spawn builders Li Chen
2026-07-16 14:31 ` [RFC PATCH 24/24] Documentation: describe " Li Chen
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=129eedc78affaf85e4d552daae1460a43057fb39.1784204592.git.me@linux.beauty \
--to=me@linux.beauty \
--cc=akpm@linux-foundation.org \
--cc=arnd@arndb.de \
--cc=audit@vger.kernel.org \
--cc=brauner@kernel.org \
--cc=corbet@lwn.net \
--cc=eparis@redhat.com \
--cc=gnoack@google.com \
--cc=jack@suse.cz \
--cc=josh@joshtriplett.org \
--cc=kees@kernel.org \
--cc=krisman@kernel.org \
--cc=linux-api@vger.kernel.org \
--cc=linux-arch@vger.kernel.org \
--cc=linux-doc@vger.kernel.org \
--cc=linux-fsdevel@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-kselftest@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=linux-security-module@vger.kernel.org \
--cc=luto@kernel.org \
--cc=mail@johnericson.me \
--cc=mic@digikod.net \
--cc=mjguzik@gmail.com \
--cc=oleg@redhat.com \
--cc=paul@paul-moore.com \
--cc=shuah@kernel.org \
--cc=viro@zeniv.linux.org.uk \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox