summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/exec.c22
-rw-r--r--include/linux/binfmts.h5
2 files changed, 27 insertions, 0 deletions
diff --git a/fs/exec.c b/fs/exec.c
index d7f9e14f8977..48c525115fe4 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 8938beabad7a..f9c9d08f4f7c 100644
--- a/include/linux/binfmts.h
+++ b/include/linux/binfmts.h
@@ -19,6 +19,7 @@ struct pt_regs;
#ifdef __KERNEL__
#include <linux/sched.h>
+#include <linux/unistd.h>
#include <asm/exec.h>
#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 */