From 826eba4db0c643cc0e705c8365902c63fac2b7ee Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 3 Aug 2012 12:14:44 +0400 Subject: the only place that needs to include asm/exec.h is linux/binfmts.h Signed-off-by: Al Viro --- fs/binfmt_elf.c | 1 - fs/binfmt_elf_fdpic.c | 1 - fs/exec.c | 1 - 3 files changed, 3 deletions(-) (limited to 'fs') diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index 1b52956afe3..2ab91905b2e 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c @@ -35,7 +35,6 @@ #include #include #include -#include static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs); static int load_elf_library(struct file *); diff --git a/fs/binfmt_elf_fdpic.c b/fs/binfmt_elf_fdpic.c index 3d77cf81ba3..c298f2efc1b 100644 --- a/fs/binfmt_elf_fdpic.c +++ b/fs/binfmt_elf_fdpic.c @@ -39,7 +39,6 @@ #include #include #include -#include typedef char *elf_caddr_t; diff --git a/fs/exec.c b/fs/exec.c index 574cf4de4ec..d7f9e14f897 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -59,7 +59,6 @@ #include #include #include -#include #include #include "internal.h" -- cgit v1.2.3-70-g09d2 From 282124d18626379a20b41d25e0c580f290cd09d4 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 30 Sep 2012 13:20:09 -0400 Subject: generic kernel_execve() based mostly on arm and alpha versions. Architectures can define __ARCH_WANT_KERNEL_EXECVE and use it, provided that * they have working current_pt_regs(), even for kernel threads. * kernel_thread-spawned threads do have space for pt_regs in the normal location. Normally that's as simple as switching to generic kernel_thread() and making sure that kernel threads do *not* go through return from syscall path; call the payload from equivalent of ret_from_fork if we are in a kernel thread (or just have separate ret_from_kernel_thread and make copy_thread() use it instead of ret_from_fork in kernel thread case). * they have ret_from_kernel_execve(); it is called after successful do_execve() done by kernel_execve() and gets normal pt_regs location passed to it as argument. It's essentially a longjmp() analog - it should set sp, etc. to the situation expected at the return for syscall and go there. Eventually the need for that sucker will disappear, but that'll take some surgery on kernel_thread() payloads. Signed-off-by: Al Viro --- fs/exec.c | 22 ++++++++++++++++++++++ include/linux/binfmts.h | 5 +++++ 2 files changed, 27 insertions(+) (limited to 'fs') diff --git a/fs/exec.c b/fs/exec.c index d7f9e14f897..48c525115fe 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -2318,3 +2318,25 @@ int dump_seek(struct file *file, loff_t off) return ret; } EXPORT_SYMBOL(dump_seek); + +#ifdef __ARCH_WANT_KERNEL_EXECVE +int kernel_execve(const char *filename, + const char *const argv[], + const char *const envp[]) +{ + struct pt_regs *p = current_pt_regs(); + int ret; + + ret = do_execve(filename, + (const char __user *const __user *)argv, + (const char __user *const __user *)envp, p); + if (ret < 0) + return ret; + + /* + * We were successful. We won't be returning to our caller, but + * instead to user space by manipulating the kernel stack. + */ + ret_from_kernel_execve(p); +} +#endif diff --git a/include/linux/binfmts.h b/include/linux/binfmts.h index 8938beabad7..f9c9d08f4f7 100644 --- a/include/linux/binfmts.h +++ b/include/linux/binfmts.h @@ -19,6 +19,7 @@ struct pt_regs; #ifdef __KERNEL__ #include +#include #include #define CORENAME_MAX_SIZE 128 @@ -137,5 +138,9 @@ extern void do_coredump(long signr, int exit_code, struct pt_regs *regs); extern void set_binfmt(struct linux_binfmt *new); extern void free_bprm(struct linux_binprm *); +#ifdef __ARCH_WANT_KERNEL_EXECVE +extern void ret_from_kernel_execve(struct pt_regs *normal) __noreturn; +#endif + #endif /* __KERNEL__ */ #endif /* _LINUX_BINFMTS_H */ -- cgit v1.2.3-70-g09d2 From 38b983b3461e7d3c64a981e2338bb34605c46f30 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 30 Sep 2012 13:38:55 -0400 Subject: generic sys_execve() Selected by __ARCH_WANT_SYS_EXECVE in unistd.h. Requires * working current_pt_regs() * *NOT* doing a syscall-in-kernel kind of kernel_execve() implementation. Using generic kernel_execve() is fine. Signed-off-by: Al Viro --- fs/exec.c | 38 ++++++++++++++++++++++++++++++++++---- include/linux/compat.h | 8 ++++++-- 2 files changed, 40 insertions(+), 6 deletions(-) (limited to 'fs') diff --git a/fs/exec.c b/fs/exec.c index 48c525115fe..50a1270da95 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -401,7 +401,7 @@ struct user_arg_ptr { union { const char __user *const __user *native; #ifdef CONFIG_COMPAT - compat_uptr_t __user *compat; + const compat_uptr_t __user *compat; #endif } ptr; }; @@ -1600,9 +1600,9 @@ int do_execve(const char *filename, } #ifdef CONFIG_COMPAT -int compat_do_execve(char *filename, - compat_uptr_t __user *__argv, - compat_uptr_t __user *__envp, +int compat_do_execve(const char *filename, + const compat_uptr_t __user *__argv, + const compat_uptr_t __user *__envp, struct pt_regs *regs) { struct user_arg_ptr argv = { @@ -2319,6 +2319,36 @@ int dump_seek(struct file *file, loff_t off) } EXPORT_SYMBOL(dump_seek); +#ifdef __ARCH_WANT_SYS_EXECVE +SYSCALL_DEFINE3(execve, + const char __user *, filename, + const char __user *const __user *, argv, + const char __user *const __user *, envp) +{ + const char *path = getname(filename); + int error = PTR_ERR(path); + if (!IS_ERR(path)) { + error = do_execve(path, argv, envp, current_pt_regs()); + putname(path); + } + return error; +} +#ifdef CONFIG_COMPAT +asmlinkage long compat_sys_execve(const char __user * filename, + const compat_uptr_t __user * argv, + const compat_uptr_t __user * envp) +{ + const char *path = getname(filename); + int error = PTR_ERR(path); + if (!IS_ERR(path)) { + error = compat_do_execve(path, argv, envp, current_pt_regs()); + putname(path); + } + return error; +} +#endif +#endif + #ifdef __ARCH_WANT_KERNEL_EXECVE int kernel_execve(const char *filename, const char *const argv[], diff --git a/include/linux/compat.h b/include/linux/compat.h index 09b28b7369d..c4be3f55511 100644 --- a/include/linux/compat.h +++ b/include/linux/compat.h @@ -289,8 +289,12 @@ asmlinkage ssize_t compat_sys_pwritev(unsigned long fd, const struct compat_iovec __user *vec, unsigned long vlen, u32 pos_low, u32 pos_high); -int compat_do_execve(char *filename, compat_uptr_t __user *argv, - compat_uptr_t __user *envp, struct pt_regs *regs); +int compat_do_execve(const char *filename, const compat_uptr_t __user *argv, + const compat_uptr_t __user *envp, struct pt_regs *regs); +#ifdef __ARCH_WANT_SYS_EXECVE +asmlinkage long compat_sys_execve(const char __user *filename, const compat_uptr_t __user *argv, + const compat_uptr_t __user *envp); +#endif asmlinkage long compat_sys_select(int n, compat_ulong_t __user *inp, compat_ulong_t __user *outp, compat_ulong_t __user *exp, -- cgit v1.2.3-70-g09d2