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 05/24] pidfd: add spawn builder path configuration
Date: Thu, 16 Jul 2026 22:31:31 +0800 [thread overview]
Message-ID: <650cf9dd6ed58ee90617f72f7743262787c822c7.1784204592.git.me@linux.beauty> (raw)
In-Reply-To: <cover.1784204592.git.me@linux.beauty>
Add an fsconfig-style pidfd_config() implementation and the initial path
string key. The builder inode retains configuration, which userspace may
replace before the child is created.
Bind configuration authority to the creator mm, credential object, and
child PID namespace. Passing the fd alone therefore does not delegate
launch authority to a different process context.
Accept absolute and relative executable paths. A later run operation
resolves relative paths from the child working directory without PATH
search. Keep the syscall unreachable until the complete spawn state machine
is wired later in the series.
Assisted-by: Codex:gpt-5.6-sol
Signed-off-by: Li Chen <me@linux.beauty>
---
fs/pidfd_spawn.c | 155 +++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 155 insertions(+)
diff --git a/fs/pidfd_spawn.c b/fs/pidfd_spawn.c
index ff2b0cb6365a5..46207c8e8139f 100644
--- a/fs/pidfd_spawn.c
+++ b/fs/pidfd_spawn.c
@@ -3,24 +3,47 @@
* pidfd-backed process spawn builders
*/
+#include <linux/cred.h>
#include <linux/file.h>
#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/mutex.h>
+#include <linux/namei.h>
#include <linux/pid.h>
+#include <linux/pid_namespace.h>
#include <linux/pidfd_spawn.h>
#include <linux/pidfs.h>
#include <linux/refcount.h>
+#include <linux/sched/signal.h>
#include <linux/slab.h>
+#include <linux/syscalls.h>
+#include <linux/uaccess.h>
#include <uapi/linux/pidfd.h>
+#define PIDFD_SPAWN_MAX_CONFIG_KEY_SIZE 256
+
struct pidfd_spawn_state {
+ /* Serializes configuration and payload teardown. */
+ struct mutex lock;
refcount_t count;
struct pid *pid;
+ struct mm_struct *creator_mm;
+ const struct cred *creator_cred;
+ struct pid_namespace *creator_pid_ns;
+ char *staged_path;
};
static void pidfd_spawn_state_put(struct pidfd_spawn_state *state);
static void pidfd_spawn_free_state(struct pidfd_spawn_state *state)
{
+ kfree(state->staged_path);
+ if (state->creator_mm)
+ mmdrop(state->creator_mm);
+ if (state->creator_cred)
+ put_cred(state->creator_cred);
+ if (state->creator_pid_ns)
+ put_pid_ns(state->creator_pid_ns);
put_pid(state->pid);
kfree(state);
}
@@ -31,6 +54,15 @@ static void pidfd_spawn_state_put(struct pidfd_spawn_state *state)
pidfd_spawn_free_state(state);
}
+static void pidfd_spawn_state_put_cleanup(struct pidfd_spawn_state *state)
+{
+ if (!IS_ERR_OR_NULL(state))
+ pidfd_spawn_state_put(state);
+}
+
+DEFINE_FREE(pidfd_spawn_state, struct pidfd_spawn_state *,
+ pidfd_spawn_state_put_cleanup(_T))
+
static void pidfd_spawn_state_release(void *data)
{
pidfd_spawn_state_put(data);
@@ -50,17 +82,140 @@ static const struct pidfs_future_file_ops pidfd_spawn_future_ops = {
.release = pidfd_spawn_state_release,
};
+static struct pidfd_spawn_state *
+pidfd_spawn_state_get_file(struct file *file)
+{
+ struct pidfd_spawn_state *state;
+
+ state = pidfs_future_file_data(file, &pidfd_spawn_future_ops);
+ if (!state || !refcount_inc_not_zero(&state->count))
+ return ERR_PTR(state ? -ESRCH : -EINVAL);
+ return state;
+}
+
+static bool pidfd_spawn_same_creator(struct pidfd_spawn_state *state)
+{
+ return current->mm == state->creator_mm &&
+ current_cred() == state->creator_cred &&
+ current->nsproxy->pid_ns_for_children == state->creator_pid_ns;
+}
+
+static struct filename *pidfd_spawn_get_path(const char __user *value)
+{
+ CLASS(filename, name)(value);
+
+ if (IS_ERR(name))
+ return ERR_CAST(name);
+
+ return no_free_ptr(name);
+}
+
+static char *pidfd_spawn_copy_path(const char __user *value)
+{
+ struct filename *name __free(putname) = NULL;
+ char *path;
+
+ name = pidfd_spawn_get_path(value);
+ if (IS_ERR(name))
+ return ERR_CAST(name);
+ path = kstrdup(name->name, GFP_KERNEL_ACCOUNT);
+ if (!path)
+ return ERR_PTR(-ENOMEM);
+
+ return path;
+}
+
+static int pidfd_spawn_state_set_path(struct pidfd_spawn_state *state,
+ const char __user *value)
+{
+ char *path __free(kfree) = NULL;
+ char *old __free(kfree) = NULL;
+
+ path = pidfd_spawn_copy_path(value);
+ if (IS_ERR(path))
+ return PTR_ERR(path);
+
+ scoped_cond_guard(mutex_intr, return -EINTR, &state->lock) {
+ if (!pidfd_spawn_same_creator(state))
+ return -EPERM;
+
+ old = state->staged_path;
+ state->staged_path = no_free_ptr(path);
+ }
+ return 0;
+}
+
+static int pidfd_spawn_state_set_string(struct pidfd_spawn_state *state,
+ const char *key,
+ const void __user *value)
+{
+ if (!strcmp(key, PIDFD_CONFIG_KEY_PATH))
+ return pidfd_spawn_state_set_path(state, value);
+
+ return -EOPNOTSUPP;
+}
+
+SYSCALL_DEFINE5(pidfd_config, int, fd, unsigned int, cmd,
+ const char __user *, ukey, const void __user *, uvalue,
+ int, aux)
+{
+ char *key __free(kfree) = NULL;
+ struct pidfd_spawn_state *state __free(pidfd_spawn_state) = NULL;
+ int ret;
+
+ switch (cmd) {
+ case PIDFD_CONFIG_SET_STRING:
+ if (!ukey || !uvalue || aux)
+ return -EINVAL;
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ CLASS(fd, f)(fd);
+ if (fd_empty(f))
+ return -EBADF;
+
+ state = pidfd_spawn_state_get_file(fd_file(f));
+ if (IS_ERR(state))
+ return PTR_ERR(state);
+
+ key = strndup_user(ukey, PIDFD_SPAWN_MAX_CONFIG_KEY_SIZE);
+ if (IS_ERR(key))
+ return PTR_ERR(key);
+
+ switch (cmd) {
+ case PIDFD_CONFIG_SET_STRING:
+ ret = pidfd_spawn_state_set_string(state, key, uvalue);
+ break;
+ default:
+ ret = -EOPNOTSUPP;
+ break;
+ }
+
+ return ret;
+}
+
int pidfd_empty_open(unsigned int flags)
{
struct pidfd_spawn_state *state;
struct file *pidfile;
int pidfd;
+ if (!current->mm)
+ return -EINVAL;
+
state = kzalloc_obj(*state, GFP_KERNEL_ACCOUNT);
if (!state)
return -ENOMEM;
+ mutex_init(&state->lock);
refcount_set(&state->count, 1);
+ mmgrab(current->mm);
+ state->creator_mm = current->mm;
+ state->creator_cred = get_current_cred();
+ state->creator_pid_ns =
+ get_pid_ns(current->nsproxy->pid_ns_for_children);
pidfile = pidfs_alloc_future_file("[pidfd_spawn]", state,
&pidfd_spawn_future_ops,
--
2.52.0
next prev parent reply other threads:[~2026-07-16 14:35 UTC|newest]
Thread overview: 30+ 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 ` Li Chen [this message]
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 ` [RFC PATCH 09/24] fork: let process builders supply preallocated pids Li Chen
2026-07-16 14:31 ` [RFC PATCH 10/24] pidfs: publish future pidfd files 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-08-19 10:19 ` Li Chen
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
2026-08-04 20:25 ` [RFC PATCH 00/24] pidfd: add a minimal process spawn builder Justin Suess
2026-08-19 1:14 ` Li Chen
2026-08-25 21:27 ` Mateusz Guzik
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=650cf9dd6ed58ee90617f72f7743262787c822c7.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