From 541003b576c3e3c328314398a6df76eb3cebf847 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 28 Oct 2025 00:11:45 -0400 Subject: rename do_filp_open() to do_file_open() "filp" thing never made sense; seeing that there are exactly 4 callers in the entire tree (and it's neither exported nor even declared in linux/*/*.h), there's no point keeping that ugliness. FWIW, the 'filp' thing did originate in OSD&I; for some reason Tanenbaum decided to call the object representing an opened file 'struct filp', the last letter standing for 'position'. In all Unices, Linux included, the corresponding object had always been 'struct file'... Signed-off-by: Al Viro --- fs/exec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'fs/exec.c') diff --git a/fs/exec.c b/fs/exec.c index 9d5ebc9d15b0..b7d8081d12ea 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -780,7 +780,7 @@ static struct file *do_open_execat(int fd, struct filename *name, int flags) if (flags & AT_EMPTY_PATH) open_exec_flags.lookup_flags |= LOOKUP_EMPTY; - file = do_filp_open(fd, name, &open_exec_flags); + file = do_file_open(fd, name, &open_exec_flags); if (IS_ERR(file)) return file; -- cgit v1.2.3 From 2c941f26c6abc032fd7800ac7dcbfaf3cb586e21 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 25 Sep 2025 17:14:20 -0400 Subject: simplify the callers of do_open_execat() Signed-off-by: Al Viro --- fs/exec.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) (limited to 'fs/exec.c') diff --git a/fs/exec.c b/fs/exec.c index b7d8081d12ea..5b4110c7522e 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -815,14 +815,8 @@ static struct file *do_open_execat(int fd, struct filename *name, int flags) */ struct file *open_exec(const char *name) { - struct filename *filename = getname_kernel(name); - struct file *f = ERR_CAST(filename); - - if (!IS_ERR(filename)) { - f = do_open_execat(AT_FDCWD, filename, 0); - putname(filename); - } - return f; + CLASS(filename_kernel, filename)(name); + return do_open_execat(AT_FDCWD, filename, 0); } EXPORT_SYMBOL(open_exec); -- cgit v1.2.3 From bb850584aaa2f31bc6c494f973047a325961b333 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 25 Sep 2025 17:18:42 -0400 Subject: simplify the callers of alloc_bprm() alloc_bprm() starts with do_open_execat() and it will do the right thing if given ERR_PTR() for name. Allows to drop such checks in its callers... Signed-off-by: Al Viro --- fs/exec.c | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) (limited to 'fs/exec.c') diff --git a/fs/exec.c b/fs/exec.c index 5b4110c7522e..1473e8c06a8c 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -1782,9 +1782,6 @@ static int do_execveat_common(int fd, struct filename *filename, struct linux_binprm *bprm; int retval; - if (IS_ERR(filename)) - return PTR_ERR(filename); - /* * We move the actual failure in case of RLIMIT_NPROC excess from * set*uid() to execve() because too many poorly written programs @@ -1862,7 +1859,6 @@ out_ret: int kernel_execve(const char *kernel_filename, const char *const *argv, const char *const *envp) { - struct filename *filename; struct linux_binprm *bprm; int fd = AT_FDCWD; int retval; @@ -1871,15 +1867,10 @@ int kernel_execve(const char *kernel_filename, if (WARN_ON_ONCE(current->flags & PF_KTHREAD)) return -EINVAL; - filename = getname_kernel(kernel_filename); - if (IS_ERR(filename)) - return PTR_ERR(filename); - + CLASS(filename_kernel, filename)(kernel_filename); bprm = alloc_bprm(fd, filename, 0); - if (IS_ERR(bprm)) { - retval = PTR_ERR(bprm); - goto out_ret; - } + if (IS_ERR(bprm)) + return PTR_ERR(bprm); retval = count_strings_kernel(argv); if (WARN_ON_ONCE(retval == 0)) @@ -1913,8 +1904,6 @@ int kernel_execve(const char *kernel_filename, retval = bprm_execve(bprm); out_free: free_bprm(bprm); -out_ret: - putname(filename); return retval; } -- cgit v1.2.3 From 88b33614f9ca09a0f6471b1790f5f718d01d84a6 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 7 Jan 2026 15:16:24 -0500 Subject: execve: fold {compat_,}do_execve{,at}() into their sole callers All of them are wrappers for do_execveat_common() and each has exactly one caller. The only difference is in the way they are constructing argv/envp arguments for do_execveat_common() and that's easy to do with less boilerplate. Signed-off-by: Al Viro --- fs/exec.c | 80 +++++++++++++++------------------------------------------------ 1 file changed, 19 insertions(+), 61 deletions(-) (limited to 'fs/exec.c') diff --git a/fs/exec.c b/fs/exec.c index 1473e8c06a8c..5d15c0440c3d 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -1907,59 +1907,6 @@ out_free: return retval; } -static int do_execve(struct filename *filename, - const char __user *const __user *__argv, - const char __user *const __user *__envp) -{ - struct user_arg_ptr argv = { .ptr.native = __argv }; - struct user_arg_ptr envp = { .ptr.native = __envp }; - return do_execveat_common(AT_FDCWD, filename, argv, envp, 0); -} - -static int do_execveat(int fd, struct filename *filename, - const char __user *const __user *__argv, - const char __user *const __user *__envp, - int flags) -{ - struct user_arg_ptr argv = { .ptr.native = __argv }; - struct user_arg_ptr envp = { .ptr.native = __envp }; - - return do_execveat_common(fd, filename, argv, envp, flags); -} - -#ifdef CONFIG_COMPAT -static int compat_do_execve(struct filename *filename, - const compat_uptr_t __user *__argv, - const compat_uptr_t __user *__envp) -{ - struct user_arg_ptr argv = { - .is_compat = true, - .ptr.compat = __argv, - }; - struct user_arg_ptr envp = { - .is_compat = true, - .ptr.compat = __envp, - }; - return do_execveat_common(AT_FDCWD, filename, argv, envp, 0); -} - -static int compat_do_execveat(int fd, struct filename *filename, - const compat_uptr_t __user *__argv, - const compat_uptr_t __user *__envp, - int flags) -{ - struct user_arg_ptr argv = { - .is_compat = true, - .ptr.compat = __argv, - }; - struct user_arg_ptr envp = { - .is_compat = true, - .ptr.compat = __envp, - }; - return do_execveat_common(fd, filename, argv, envp, flags); -} -#endif - void set_binfmt(struct linux_binfmt *new) { struct mm_struct *mm = current->mm; @@ -1984,12 +1931,18 @@ void set_dumpable(struct mm_struct *mm, int value) __mm_flags_set_mask_dumpable(mm, value); } +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, const char __user *const __user *, argv, const char __user *const __user *, envp) { - return do_execve(getname(filename), argv, envp); + return do_execveat_common(AT_FDCWD, getname(filename), + native_arg(argv), native_arg(envp), 0); } SYSCALL_DEFINE5(execveat, @@ -1998,17 +1951,23 @@ SYSCALL_DEFINE5(execveat, const char __user *const __user *, envp, int, flags) { - return do_execveat(fd, - getname_uflags(filename, flags), - argv, envp, flags); + return do_execveat_common(fd, getname_uflags(filename, flags), + native_arg(argv), native_arg(envp), flags); } #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) { - return compat_do_execve(getname(filename), argv, envp); + return do_execveat_common(AT_FDCWD, getname(filename), + compat_arg(argv), compat_arg(envp), 0); } COMPAT_SYSCALL_DEFINE5(execveat, int, fd, @@ -2017,9 +1976,8 @@ COMPAT_SYSCALL_DEFINE5(execveat, int, fd, const compat_uptr_t __user *, envp, int, flags) { - return compat_do_execveat(fd, - getname_uflags(filename, flags), - argv, envp, flags); + return do_execveat_common(fd, getname_uflags(filename, flags), + compat_arg(argv), compat_arg(envp), flags); } #endif -- cgit v1.2.3 From 194c760b6acd214e47f2504cede9a9dbadd8fcba Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 7 Jan 2026 15:20:45 -0500 Subject: do_execveat_common(): don't consume filename reference ... and convert its callers to CLASS(filename...) Signed-off-by: Al Viro --- fs/exec.c | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) (limited to 'fs/exec.c') diff --git a/fs/exec.c b/fs/exec.c index 5d15c0440c3d..9e799af13602 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -1789,20 +1789,16 @@ static int do_execveat_common(int fd, struct filename *filename, * 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; - } + 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; - } + if (IS_ERR(bprm)) + return PTR_ERR(bprm); retval = count(argv, MAX_ARG_STRINGS); if (retval < 0) @@ -1850,9 +1846,6 @@ static int do_execveat_common(int fd, struct filename *filename, retval = bprm_execve(bprm); out_free: free_bprm(bprm); - -out_ret: - putname(filename); return retval; } @@ -1941,7 +1934,8 @@ SYSCALL_DEFINE3(execve, const char __user *const __user *, argv, const char __user *const __user *, envp) { - return do_execveat_common(AT_FDCWD, getname(filename), + CLASS(filename, name)(filename); + return do_execveat_common(AT_FDCWD, name, native_arg(argv), native_arg(envp), 0); } @@ -1951,7 +1945,8 @@ SYSCALL_DEFINE5(execveat, const char __user *const __user *, envp, int, flags) { - return do_execveat_common(fd, getname_uflags(filename, flags), + CLASS(filename_uflags, name)(filename, flags); + return do_execveat_common(fd, name, native_arg(argv), native_arg(envp), flags); } @@ -1966,7 +1961,8 @@ COMPAT_SYSCALL_DEFINE3(execve, const char __user *, filename, const compat_uptr_t __user *, argv, const compat_uptr_t __user *, envp) { - return do_execveat_common(AT_FDCWD, getname(filename), + CLASS(filename, name)(filename); + return do_execveat_common(AT_FDCWD, name, compat_arg(argv), compat_arg(envp), 0); } @@ -1976,7 +1972,8 @@ COMPAT_SYSCALL_DEFINE5(execveat, int, fd, const compat_uptr_t __user *, envp, int, flags) { - return do_execveat_common(fd, getname_uflags(filename, flags), + CLASS(filename_uflags, name)(filename, flags); + return do_execveat_common(fd, name, compat_arg(argv), compat_arg(envp), flags); } #endif -- cgit v1.2.3 From 0697b4f400696c1311cbd14421698b340dd8f7d4 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 28 Oct 2025 02:29:04 -0400 Subject: switch {alloc,free}_bprm() to CLASS() 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 --- fs/exec.c | 48 +++++++++++++++++++++--------------------------- 1 file changed, 21 insertions(+), 27 deletions(-) (limited to 'fs/exec.c') diff --git a/fs/exec.c b/fs/exec.c index 9e799af13602..5dd8ff61f27a 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -1465,6 +1465,9 @@ out_free: 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. */ @@ -1779,7 +1782,6 @@ static int do_execveat_common(int fd, struct filename *filename, struct user_arg_ptr envp, int flags) { - struct linux_binprm *bprm; int retval; /* @@ -1796,36 +1798,36 @@ static int do_execveat_common(int fd, struct filename *filename, * further execve() calls fail. */ current->flags &= ~PF_NPROC_EXCEEDED; - bprm = alloc_bprm(fd, filename, flags); + 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 @@ -1836,24 +1838,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); - 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 */ @@ -1861,43 +1858,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); } void set_binfmt(struct linux_binfmt *new) -- cgit v1.2.3 From 819cb2c1dd8dc1168d5f1810182f1cf1925b4d2f Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 20 Sep 2024 00:48:51 -0400 Subject: do_open_execat(): don't care about LOOKUP_EMPTY do_file_open() doesn't. Signed-off-by: Al Viro --- fs/exec.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'fs/exec.c') diff --git a/fs/exec.c b/fs/exec.c index 5dd8ff61f27a..a4f29d2c2d3a 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -777,8 +777,6 @@ static struct file *do_open_execat(int fd, struct filename *name, int flags) return ERR_PTR(-EINVAL); if (flags & AT_SYMLINK_NOFOLLOW) open_exec_flags.lookup_flags &= ~LOOKUP_FOLLOW; - if (flags & AT_EMPTY_PATH) - open_exec_flags.lookup_flags |= LOOKUP_EMPTY; file = do_file_open(fd, name, &open_exec_flags); if (IS_ERR(file)) -- cgit v1.2.3