[RFC PATCH 06/24] exec: expose execveat internals to process builders

From: Li Chen

Date: Thu Jul 16 2026 - 11:50:43 EST


Move struct user_arg_ptr and its native and compat constructors to an
fs-private header. Expose do_execveat_common() within fs so a process
builder can enter the normal exec path without synthesizing a userspace
execveat() syscall.

Assisted-by: Codex:gpt-5.6-sol
Signed-off-by: Li Chen <me@linux.beauty>
---
MAINTAINERS | 1 +
fs/exec.c | 28 ++++------------------------
fs/exec_internal.h | 40 ++++++++++++++++++++++++++++++++++++++++
3 files changed, 45 insertions(+), 24 deletions(-)
create mode 100644 fs/exec_internal.h

diff --git a/MAINTAINERS b/MAINTAINERS
index 8d7f94f09f414..85b1306cb2ff3 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -9757,6 +9757,7 @@ F: Documentation/userspace-api/ELF.rst
F: fs/*binfmt_*.c
F: fs/Kconfig.binfmt
F: fs/exec.c
+F: fs/exec_internal.h
F: fs/tests/binfmt_*_kunit.c
F: fs/tests/exec_kunit.c
F: include/linux/binfmts.h
diff --git a/fs/exec.c b/fs/exec.c
index d5993cedc829a..1a256ba26425e 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -76,6 +76,7 @@

#include <trace/events/task.h>
#include "internal.h"
+#include "exec_internal.h"

#include <trace/events/sched.h>

@@ -291,17 +292,6 @@ static int bprm_mm_init(struct linux_binprm *bprm)
return err;
}

-struct user_arg_ptr {
-#ifdef CONFIG_COMPAT
- bool is_compat;
-#endif
- union {
- const char __user *const __user *native;
-#ifdef CONFIG_COMPAT
- const compat_uptr_t __user *compat;
-#endif
- } ptr;
-};

static const char __user *get_user_arg_ptr(struct user_arg_ptr argv, int nr)
{
@@ -1805,10 +1795,9 @@ static int bprm_execve(struct linux_binprm *bprm)
return retval;
}

-static int do_execveat_common(int fd, struct filename *filename,
- struct user_arg_ptr argv,
- struct user_arg_ptr envp,
- int flags)
+int do_execveat_common(int fd, struct filename *filename,
+ struct user_arg_ptr argv,
+ struct user_arg_ptr envp, int flags)
{
int retval;

@@ -1935,10 +1924,6 @@ void set_binfmt(struct linux_binfmt *new)
}
EXPORT_SYMBOL(set_binfmt);

-static inline struct user_arg_ptr native_arg(const char __user *const __user *p)
-{
- return (struct user_arg_ptr){.ptr.native = p};
-}

SYSCALL_DEFINE3(execve,
const char __user *, filename,
@@ -1963,11 +1948,6 @@ SYSCALL_DEFINE5(execveat,

#ifdef CONFIG_COMPAT

-static inline struct user_arg_ptr compat_arg(const compat_uptr_t __user *p)
-{
- return (struct user_arg_ptr){.is_compat = true, .ptr.compat = p};
-}
-
COMPAT_SYSCALL_DEFINE3(execve, const char __user *, filename,
const compat_uptr_t __user *, argv,
const compat_uptr_t __user *, envp)
diff --git a/fs/exec_internal.h b/fs/exec_internal.h
new file mode 100644
index 0000000000000..bf6a873e98426
--- /dev/null
+++ b/fs/exec_internal.h
@@ -0,0 +1,40 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef _FS_EXEC_INTERNAL_H
+#define _FS_EXEC_INTERNAL_H
+
+#include <linux/compat.h>
+#include <linux/compiler_types.h>
+#include <linux/types.h>
+
+struct filename;
+
+struct user_arg_ptr {
+#ifdef CONFIG_COMPAT
+ bool is_compat;
+#endif
+ union {
+ const char __user *const __user *native;
+#ifdef CONFIG_COMPAT
+ const compat_uptr_t __user *compat;
+#endif
+ } ptr;
+};
+
+static inline struct user_arg_ptr
+native_arg(const char __user *const __user *p)
+{
+ return (struct user_arg_ptr){.ptr.native = p};
+}
+
+#ifdef CONFIG_COMPAT
+static inline struct user_arg_ptr compat_arg(const compat_uptr_t __user *p)
+{
+ return (struct user_arg_ptr){.is_compat = true, .ptr.compat = p};
+}
+#endif
+
+int do_execveat_common(int fd, struct filename *filename,
+ struct user_arg_ptr argv,
+ struct user_arg_ptr envp, int flags);
+
+#endif /* _FS_EXEC_INTERNAL_H */
--
2.52.0