[RFC PATCH v1 01/13] exec: factor argument setup out of do_execveat_common()

From: Li Chen

Date: Thu May 28 2026 - 05:55:50 EST


Move the common userspace argv and envp counting and stack setup code
into do_execveat_common_bprm(). Keep do_execveat_common() responsible
for the existing RLIMIT_NPROC check, bprm allocation, and error path.
This is a mechanical refactor for later opened-file exec users. It
does not change execve or execveat behavior.

Signed-off-by: Li Chen <me@linux.beauty>
---
fs/exec.c | 53 +++++++++++++++++++++++++++++++----------------------
1 file changed, 31 insertions(+), 22 deletions(-)

diff --git a/fs/exec.c b/fs/exec.c
index 2889b7cf808d7..53f7b18d2b1ea 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -1775,31 +1775,12 @@ 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)
+static int do_execveat_common_bprm(struct linux_binprm *bprm,
+ struct user_arg_ptr argv,
+ struct user_arg_ptr envp)
{
int retval;

- /*
- * We move the actual failure in case of RLIMIT_NPROC excess from
- * set*uid() to execve() because too many poorly written programs
- * don't check setuid() return code. Here we additionally recheck
- * whether NPROC limit is still exceeded.
- */
- if ((current->flags & PF_NPROC_EXCEEDED) &&
- is_rlimit_overlimit(current_ucounts(), UCOUNT_RLIMIT_NPROC, rlimit(RLIMIT_NPROC)))
- return -EAGAIN;
-
- /* We're below the limit (still or again), so we don't want to make
- * further execve() calls fail. */
- current->flags &= ~PF_NPROC_EXCEEDED;
-
- CLASS(bprm, bprm)(fd, filename, flags);
- if (IS_ERR(bprm))
- return PTR_ERR(bprm);
-
retval = count(argv, MAX_ARG_STRINGS);
if (retval < 0)
return retval;
@@ -1846,6 +1827,34 @@ static int do_execveat_common(int fd, struct filename *filename,
return bprm_execve(bprm);
}

+static int do_execveat_common(int fd, struct filename *filename,
+ struct user_arg_ptr argv,
+ struct user_arg_ptr envp,
+ int flags)
+{
+ /*
+ * We move the actual failure in case of RLIMIT_NPROC excess from
+ * set*uid() to execve() because too many poorly written programs
+ * don't check setuid() return code. Here we additionally recheck
+ * whether NPROC limit is still exceeded.
+ */
+ if ((current->flags & PF_NPROC_EXCEEDED) &&
+ is_rlimit_overlimit(current_ucounts(), UCOUNT_RLIMIT_NPROC, rlimit(RLIMIT_NPROC)))
+ return -EAGAIN;
+
+ /*
+ * We're below the limit (still or again), so we don't want to make
+ * further execve() calls fail.
+ */
+ current->flags &= ~PF_NPROC_EXCEEDED;
+
+ CLASS(bprm, bprm)(fd, filename, flags);
+ if (IS_ERR(bprm))
+ return PTR_ERR(bprm);
+
+ return do_execveat_common_bprm(bprm, argv, envp);
+}
+
int kernel_execve(const char *kernel_filename,
const char *const *argv, const char *const *envp)
{
--
2.52.0