[RFC PATCH 17/24] pidfd: audit child spawn execution
From: Li Chen <hidden>
Date: 2026-07-16 14:42:11
Also in:
linux-arch, linux-doc, linux-fsdevel, linux-kselftest, linux-mm, linux-security-module, lkml
Subsystem:
filesystems (vfs and infrastructure), the rest · Maintainers:
Alexander Viro, Christian Brauner, Linus Torvalds
The child exec path runs outside the caller's audit context. A delayed filename can leave a name-only record in the caller transaction, but inode metadata and exec arguments are otherwise lost because the new task starts with an unused audit context. Start a dedicated AUDIT_PIDFD_SPAWN transaction before executable lookup so audit rules can observe child identity, EXECVE arguments, and inode-backed PATH records. Close it explicitly with the child setup result. Task work does not enter through a userspace syscall frame, so do not synthesize one. Assisted-by: Codex:gpt-5.6-sol Signed-off-by: Li Chen <redacted> --- fs/pidfd_spawn.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+)
diff --git a/fs/pidfd_spawn.c b/fs/pidfd_spawn.c
index 41d5cbb49a0f7..5586926988406 100644
--- a/fs/pidfd_spawn.c
+++ b/fs/pidfd_spawn.c@@ -3,6 +3,8 @@ * pidfd-backed process spawn builders */ +#include <asm/syscall.h> +#include <linux/audit.h> #include <linux/completion.h> #include <linux/cred.h> #include <linux/file.h>
@@ -81,6 +83,8 @@ struct pidfd_spawn_state { char *staged_path; struct user_arg_ptr argv; struct user_arg_ptr envp; + unsigned long audit_args[4]; + int audit_syscall; int result; enum pidfd_spawn_status status; };
@@ -206,6 +210,8 @@ static void pidfd_spawn_drop_run_data(struct pidfd_spawn_state *state, state->staged_path = NULL; state->argv = native_arg(NULL); state->envp = native_arg(NULL); + memset(state->audit_args, 0, sizeof(state->audit_args)); + state->audit_syscall = 0; state->result = result; pidfd_spawn_set_status(state, PIDFD_SPAWN_SETUP_DONE); mutex_unlock(&state->lock);
@@ -377,6 +383,22 @@ SYSCALL_DEFINE5(pidfd_config, int, fd, unsigned int, cmd, return ret; } +static void pidfd_spawn_save_audit_context(struct pidfd_spawn_state *state) +{ + struct pt_regs *regs = current_pt_regs(); + unsigned long args[6]; + + syscall_get_arguments(current, regs, args); + state->audit_syscall = syscall_get_nr(current, regs); + memcpy(state->audit_args, args, sizeof(state->audit_args)); +} + +static void pidfd_spawn_audit_entry(struct pidfd_spawn_state *state) +{ + audit_pidfd_spawn_entry(state->audit_syscall, state->audit_args[0], + state->audit_args[1], state->audit_args[2], + state->audit_args[3]); +} static void pidfd_spawn_finish_child(struct pidfd_spawn_state *state, struct filename *filename, int result) {
@@ -391,6 +413,7 @@ static void pidfd_spawn_child(struct callback_head *work) struct filename *filename; int ret; + pidfd_spawn_audit_entry(state); filename = complete_getname(&state->filename); if (IS_ERR(filename)) ret = PTR_ERR(filename);
@@ -403,9 +426,11 @@ static void pidfd_spawn_child(struct callback_head *work) pidfd_spawn_finish_child(state, filename, ret); if (ret) { + audit_pidfd_spawn_exit(0, ret); pidfd_spawn_state_put(state); do_group_exit(PIDFD_SPAWN_EXIT_FAILURE); } + audit_pidfd_spawn_exit(1, 0); pidfd_spawn_state_put(state); }
@@ -575,6 +600,7 @@ static int pidfd_spawn_start(struct file *file, state->argv = pidfd_spawn_user_arg(kargs->argv); state->envp = pidfd_spawn_user_arg(kargs->envp); pidfd_spawn_set_status(state, PIDFD_SPAWN_STARTING); + pidfd_spawn_save_audit_context(state); reinit_completion(&state->done); task = pidfd_spawn_create_task(file, state, &clone_args);
@@ -584,6 +610,9 @@ static int pidfd_spawn_start(struct file *file, INIT_DELAYED_FILENAME(&state->filename); state->argv = native_arg(NULL); state->envp = native_arg(NULL); + memset(state->audit_args, 0, + sizeof(state->audit_args)); + state->audit_syscall = 0; state->result = 0; pidfd_spawn_set_status(state, PIDFD_SPAWN_CONFIGURING);
--
2.52.0