[PATCH v4 32/59] switch {alloc,free}_bprm() to CLASS()

Al Viro
2026-01-08T07:36:55Z

All linux_binprm instances come from alloc_bprm() and are unconditionally
destroyed by free_bprm() in the end of the same scope. IOW, CLASS()
machinery is a decent fit for those.

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/exec.c | 68 +++++++++++++++++++++++--------------------------------
1 file changed, 28 insertions(+), 40 deletions(-)

diff --git a/fs/exec.c b/fs/exec.c
index 1473e8c06a8c..68986dca9b9d 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -1465,6 +1465,9 @@ static struct linux_binprm *alloc_bprm(int fd, struct filename *filename, int fl
return ERR_PTR(retval);
}

+DEFINE_CLASS(bprm, struct linux_binprm *, if (!IS_ERR(_T)) free_bprm(_T),
+ alloc_bprm(fd, name, flags), int fd, struct filename *name, int flags)
+
int bprm_change_interp(const char *interp, struct linux_binprm *bprm)
{
/* If a binfmt changed the interp, free it first. */
@@ -1774,12 +1777,12 @@ static int bprm_execve(struct linux_binprm *bprm)
return retval;
}

-static int do_execveat_common(int fd, struct filename *filename,
+static int do_execveat_common(int fd, struct filename *__filename,
struct user_arg_ptr argv,
struct user_arg_ptr envp,
int flags)
{
- struct linux_binprm *bprm;
+ CLASS(filename_consume, filename)(__filename);
int retval;

/*
@@ -1788,48 +1791,44 @@ static int do_execveat_common(int fd, struct filename *filename,
* 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))) {
- retval = -EAGAIN;
- goto out_ret;
- }
+ if (unlikely(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;

- bprm = alloc_bprm(fd, filename, flags);
- if (IS_ERR(bprm)) {
- retval = PTR_ERR(bprm);
- goto out_ret;
- }
+ CLASS(bprm, bprm)(fd, filename, flags);
+ if (IS_ERR(bprm))
+ return PTR_ERR(bprm);

retval = count(argv, MAX_ARG_STRINGS);
if (retval < 0)
- goto out_free;
+ return retval;
bprm->argc = retval;

retval = count(envp, MAX_ARG_STRINGS);
if (retval < 0)
- goto out_free;
+ return retval;
bprm->envc = retval;

retval = bprm_stack_limits(bprm);
if (retval < 0)
- goto out_free;
+ return retval;

retval = copy_string_kernel(bprm->filename, bprm);
if (retval < 0)
- goto out_free;
+ return retval;
bprm->exec = bprm->p;

retval = copy_strings(bprm->envc, envp, bprm);
if (retval < 0)
- goto out_free;
+ return retval;

retval = copy_strings(bprm->argc, argv, bprm);
if (retval < 0)
- goto out_free;
+ return retval;

/*
* When argv is empty, add an empty string ("") as argv[0] to
@@ -1840,27 +1839,19 @@ static int do_execveat_common(int fd, struct filename *filename,
if (bprm->argc == 0) {
retval = copy_string_kernel("", bprm);
if (retval < 0)
- goto out_free;
+ return retval;
bprm->argc = 1;

pr_warn_once("process '%s' launched '%s' with NULL argv: empty string added\n",
current->comm, bprm->filename);
}

- retval = bprm_execve(bprm);
-out_free:
- free_bprm(bprm);
-
-out_ret:
- putname(filename);
- return retval;
+ return bprm_execve(bprm);
}

int kernel_execve(const char *kernel_filename,
const char *const *argv, const char *const *envp)
{
- struct linux_binprm *bprm;
- int fd = AT_FDCWD;
int retval;

/* It is non-sense for kernel threads to call execve */
@@ -1868,43 +1859,40 @@ int kernel_execve(const char *kernel_filename,
return -EINVAL;

CLASS(filename_kernel, filename)(kernel_filename);
- bprm = alloc_bprm(fd, filename, 0);
+ CLASS(bprm, bprm)(AT_FDCWD, filename, 0);
if (IS_ERR(bprm))
return PTR_ERR(bprm);

retval = count_strings_kernel(argv);
if (WARN_ON_ONCE(retval == 0))
- retval = -EINVAL;
+ return -EINVAL;
if (retval < 0)
- goto out_free;
+ return retval;
bprm->argc = retval;

retval = count_strings_kernel(envp);
if (retval < 0)
- goto out_free;
+ return retval;
bprm->envc = retval;

retval = bprm_stack_limits(bprm);
if (retval < 0)
- goto out_free;
+ return retval;

retval = copy_string_kernel(bprm->filename, bprm);
if (retval < 0)
- goto out_free;
+ return retval;
bprm->exec = bprm->p;

retval = copy_strings_kernel(bprm->envc, envp, bprm);
if (retval < 0)
- goto out_free;
+ return retval;

retval = copy_strings_kernel(bprm->argc, argv, bprm);
if (retval < 0)
- goto out_free;
+ return retval;

- retval = bprm_execve(bprm);
-out_free:
- free_bprm(bprm);
- return retval;
+ return bprm_execve(bprm);
}

static int do_execve(struct filename *filename,
--
2.47.3