Skip to content

Commit

Permalink
generic kernel_execve()
Browse files Browse the repository at this point in the history
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 <viro@zeniv.linux.org.uk>
  • Loading branch information
Al Viro committed Sep 30, 2012
1 parent a3460a5 commit 282124d
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 0 deletions.
22 changes: 22 additions & 0 deletions fs/exec.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
5 changes: 5 additions & 0 deletions include/linux/binfmts.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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 */

0 comments on commit 282124d

Please sign in to comment.