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 12/24] fork: let kernel callers create embryonic tasks
Date: Thu, 16 Jul 2026 22:31:38 +0800 [thread overview]
Message-ID: <538e494dd8fcc677da24ec985c6e90dde554e7f3.1784204592.git.me@linux.beauty> (raw)
In-Reply-To: <cover.1784204592.git.me@linux.beauty>
A kernel-created task can become visible before it has installed a new
executable image or a valid userspace register frame. Exposing such a task
through ptrace can disclose kernel setup state.
Add a task-local embryonic flag and an internal clone argument for callers
that need this lifecycle. Reject ptrace access until the creator clears the
flag. Clear it with release ordering and observe it with acquire ordering.
This orders visibility of the completed exec state with the transition.
Existing fork, vfork, clone, and kernel-thread callers leave the argument
unset and retain their current behavior.
Assisted-by: Codex:gpt-5.6-sol
Signed-off-by: Li Chen <me@linux.beauty>
---
include/linux/sched.h | 21 +++++++++++++++++++++
include/linux/sched/task.h | 1 +
kernel/fork.c | 1 +
kernel/ptrace.c | 4 ++++
4 files changed, 27 insertions(+)
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 908aff695ef86..031ae92884c3c 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -1863,6 +1863,7 @@ static __always_inline bool is_user_task(struct task_struct *task)
#define PFA_SPEC_IB_DISABLE 5 /* Indirect branch speculation restricted */
#define PFA_SPEC_IB_FORCE_DISABLE 6 /* Indirect branch speculation permanently restricted */
#define PFA_SPEC_SSB_NOEXEC 7 /* Speculative Store Bypass clear on execve() */
+#define PFA_EMBRYONIC_EXEC 8 /* No valid user register frame */
#define TASK_PFA_TEST(name, func) \
static inline bool task_##func(struct task_struct *p) \
@@ -1905,6 +1906,26 @@ TASK_PFA_CLEAR(SPEC_IB_DISABLE, spec_ib_disable)
TASK_PFA_TEST(SPEC_IB_FORCE_DISABLE, spec_ib_force_disable)
TASK_PFA_SET(SPEC_IB_FORCE_DISABLE, spec_ib_force_disable)
+/* Clearing this bit publishes the register and security state from exec. */
+static inline bool task_is_embryonic_exec(struct task_struct *p)
+{
+ return test_bit_acquire(PFA_EMBRYONIC_EXEC, &p->atomic_flags);
+}
+
+/* The task is private during copy_process(), so no publication barrier. */
+static inline void task_init_embryonic_exec(struct task_struct *p, bool set)
+{
+ if (set)
+ __set_bit(PFA_EMBRYONIC_EXEC, &p->atomic_flags);
+ else
+ __clear_bit(PFA_EMBRYONIC_EXEC, &p->atomic_flags);
+}
+
+static inline void task_clear_embryonic_exec(struct task_struct *p)
+{
+ clear_bit_unlock(PFA_EMBRYONIC_EXEC, &p->atomic_flags);
+}
+
static inline void
current_restore_flags(unsigned long orig_flags, unsigned long flags)
{
diff --git a/include/linux/sched/task.h b/include/linux/sched/task.h
index 92b4e3bc31e66..5b7facf12b33b 100644
--- a/include/linux/sched/task.h
+++ b/include/linux/sched/task.h
@@ -45,6 +45,7 @@ struct kernel_clone_args {
void *fn_arg;
struct cgroup *cgrp;
struct css_set *cset;
+ bool embryonic_exec;
unsigned int kill_seq;
};
diff --git a/kernel/fork.c b/kernel/fork.c
index d16405c037c2f..e3ade83b2d4e2 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -2138,6 +2138,7 @@ __latent_entropy struct task_struct *copy_process(
retval = copy_exec_state(clone_flags, p);
if (retval)
goto bad_fork_free;
+ task_init_embryonic_exec(p, args->embryonic_exec);
p->flags &= ~PF_KTHREAD;
if (args->kthread)
p->flags |= PF_KTHREAD;
diff --git a/kernel/ptrace.c b/kernel/ptrace.c
index d041645d9d17d..36eb9b154a397 100644
--- a/kernel/ptrace.c
+++ b/kernel/ptrace.c
@@ -56,6 +56,8 @@ bool ptracer_access_allowed(struct task_struct *tsk)
guard(rcu)();
if (ptrace_parent(tsk) != current)
return false;
+ if (task_is_embryonic_exec(tsk))
+ return false;
es = task_exec_state_rcu(tsk);
return READ_ONCE(es->dumpable) == TASK_DUMPABLE_OWNER ||
ptracer_capable(tsk, es->user_ns);
@@ -312,6 +314,8 @@ static int __ptrace_may_access(struct task_struct *task, unsigned int mode)
WARN(1, "denying ptrace access check without PTRACE_MODE_*CREDS\n");
return -EPERM;
}
+ if (task_is_embryonic_exec(task))
+ return -EPERM;
/* May we inspect the given task?
* This check is used both for attaching with ptrace
--
2.52.0
next prev parent reply other threads:[~2026-07-16 14:39 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 ` [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 ` [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 ` Li Chen [this message]
2026-07-16 15:57 ` [RFC PATCH 12/24] fork: let kernel callers create embryonic tasks 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=538e494dd8fcc677da24ec985c6e90dde554e7f3.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