Commit 6783eaa2 authored by Al Viro's avatar Al Viro

x86, um/x86: switch to generic sys_execve and kernel_execve

32bit wrapper is lost on that; 64bit one is *not*, since
we need to arrange for full pt_regs on stack when we call
sys_execve() and we need to load callee-saved ones from
there afterwards.
Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent 7076aada
...@@ -16,7 +16,6 @@ ...@@ -16,7 +16,6 @@
#include "mem_user.h" #include "mem_user.h"
#include "skas.h" #include "skas.h"
#include "os.h" #include "os.h"
#include "internal.h"
void flush_thread(void) void flush_thread(void)
{ {
...@@ -49,27 +48,7 @@ void start_thread(struct pt_regs *regs, unsigned long eip, unsigned long esp) ...@@ -49,27 +48,7 @@ void start_thread(struct pt_regs *regs, unsigned long eip, unsigned long esp)
} }
EXPORT_SYMBOL(start_thread); EXPORT_SYMBOL(start_thread);
long um_execve(const char *file, const char __user *const __user *argv, const char __user *const __user *env) void __noreturn ret_from_kernel_execve(struct pt_regs *unused)
{ {
long err;
err = do_execve(file, argv, env, &current->thread.regs);
if (!err)
UML_LONGJMP(current->thread.exec_buf, 1); UML_LONGJMP(current->thread.exec_buf, 1);
return err;
}
long sys_execve(const char __user *file, const char __user *const __user *argv,
const char __user *const __user *env)
{
long error;
char *filename;
filename = getname(file);
error = PTR_ERR(filename);
if (IS_ERR(filename)) goto out;
error = do_execve(filename, argv, env, &current->thread.regs);
putname(filename);
out:
return error;
} }
extern long um_execve(const char *file, const char __user *const __user *argv, const char __user *const __user *env);
...@@ -13,7 +13,6 @@ ...@@ -13,7 +13,6 @@
#include "asm/mman.h" #include "asm/mman.h"
#include "asm/uaccess.h" #include "asm/uaccess.h"
#include "asm/unistd.h" #include "asm/unistd.h"
#include "internal.h"
long sys_fork(void) long sys_fork(void)
{ {
...@@ -50,19 +49,3 @@ long old_mmap(unsigned long addr, unsigned long len, ...@@ -50,19 +49,3 @@ long old_mmap(unsigned long addr, unsigned long len,
out: out:
return err; return err;
} }
int kernel_execve(const char *filename,
const char *const argv[],
const char *const envp[])
{
mm_segment_t fs;
int ret;
fs = get_fs();
set_fs(KERNEL_DS);
ret = um_execve(filename, (const char __user *const __user *)argv,
(const char __user *const __user *) envp);
set_fs(fs);
return ret;
}
...@@ -459,7 +459,7 @@ GLOBAL(\label) ...@@ -459,7 +459,7 @@ GLOBAL(\label)
PTREGSCALL stub32_rt_sigreturn, sys32_rt_sigreturn, %rdi PTREGSCALL stub32_rt_sigreturn, sys32_rt_sigreturn, %rdi
PTREGSCALL stub32_sigreturn, sys32_sigreturn, %rdi PTREGSCALL stub32_sigreturn, sys32_sigreturn, %rdi
PTREGSCALL stub32_sigaltstack, sys32_sigaltstack, %rdx PTREGSCALL stub32_sigaltstack, sys32_sigaltstack, %rdx
PTREGSCALL stub32_execve, sys32_execve, %rcx PTREGSCALL stub32_execve, compat_sys_execve, %rcx
PTREGSCALL stub32_fork, sys_fork, %rdi PTREGSCALL stub32_fork, sys_fork, %rdi
PTREGSCALL stub32_clone, sys32_clone, %rdx PTREGSCALL stub32_clone, sys32_clone, %rdx
PTREGSCALL stub32_vfork, sys_vfork, %rdi PTREGSCALL stub32_vfork, sys_vfork, %rdi
......
...@@ -385,21 +385,6 @@ asmlinkage long sys32_sendfile(int out_fd, int in_fd, ...@@ -385,21 +385,6 @@ asmlinkage long sys32_sendfile(int out_fd, int in_fd,
return ret; return ret;
} }
asmlinkage long sys32_execve(const char __user *name, compat_uptr_t __user *argv,
compat_uptr_t __user *envp, struct pt_regs *regs)
{
long error;
char *filename;
filename = getname(name);
error = PTR_ERR(filename);
if (IS_ERR(filename))
return error;
error = compat_do_execve(filename, argv, envp, regs);
putname(filename);
return error;
}
asmlinkage long sys32_clone(unsigned int clone_flags, unsigned int newsp, asmlinkage long sys32_clone(unsigned int clone_flags, unsigned int newsp,
struct pt_regs *regs) struct pt_regs *regs)
{ {
......
...@@ -54,8 +54,6 @@ asmlinkage long sys32_pwrite(unsigned int, const char __user *, u32, u32, u32); ...@@ -54,8 +54,6 @@ asmlinkage long sys32_pwrite(unsigned int, const char __user *, u32, u32, u32);
asmlinkage long sys32_personality(unsigned long); asmlinkage long sys32_personality(unsigned long);
asmlinkage long sys32_sendfile(int, int, compat_off_t __user *, s32); asmlinkage long sys32_sendfile(int, int, compat_off_t __user *, s32);
asmlinkage long sys32_execve(const char __user *, compat_uptr_t __user *,
compat_uptr_t __user *, struct pt_regs *);
asmlinkage long sys32_clone(unsigned int, unsigned int, struct pt_regs *); asmlinkage long sys32_clone(unsigned int, unsigned int, struct pt_regs *);
long sys32_lseek(unsigned int, int, unsigned int); long sys32_lseek(unsigned int, int, unsigned int);
......
...@@ -25,7 +25,7 @@ int sys_fork(struct pt_regs *); ...@@ -25,7 +25,7 @@ int sys_fork(struct pt_regs *);
int sys_vfork(struct pt_regs *); int sys_vfork(struct pt_regs *);
long sys_execve(const char __user *, long sys_execve(const char __user *,
const char __user *const __user *, const char __user *const __user *,
const char __user *const __user *, struct pt_regs *); const char __user *const __user *);
long sys_clone(unsigned long, unsigned long, void __user *, long sys_clone(unsigned long, unsigned long, void __user *,
void __user *, struct pt_regs *); void __user *, struct pt_regs *);
......
...@@ -50,6 +50,8 @@ ...@@ -50,6 +50,8 @@
# define __ARCH_WANT_SYS_TIME # define __ARCH_WANT_SYS_TIME
# define __ARCH_WANT_SYS_UTIME # define __ARCH_WANT_SYS_UTIME
# define __ARCH_WANT_SYS_WAITPID # define __ARCH_WANT_SYS_WAITPID
# define __ARCH_WANT_SYS_EXECVE
# define __ARCH_WANT_KERNEL_EXECVE
/* /*
* "Conditional" syscalls * "Conditional" syscalls
......
...@@ -23,7 +23,7 @@ obj-y += time.o ioport.o ldt.o dumpstack.o nmi.o ...@@ -23,7 +23,7 @@ obj-y += time.o ioport.o ldt.o dumpstack.o nmi.o
obj-y += setup.o x86_init.o i8259.o irqinit.o jump_label.o obj-y += setup.o x86_init.o i8259.o irqinit.o jump_label.o
obj-$(CONFIG_IRQ_WORK) += irq_work.o obj-$(CONFIG_IRQ_WORK) += irq_work.o
obj-y += probe_roms.o obj-y += probe_roms.o
obj-$(CONFIG_X86_32) += sys_i386_32.o i386_ksyms_32.o obj-$(CONFIG_X86_32) += i386_ksyms_32.o
obj-$(CONFIG_X86_64) += sys_x86_64.o x8664_ksyms_64.o obj-$(CONFIG_X86_64) += sys_x86_64.o x8664_ksyms_64.o
obj-y += syscall_$(BITS).o obj-y += syscall_$(BITS).o
obj-$(CONFIG_X86_64) += vsyscall_64.o obj-$(CONFIG_X86_64) += vsyscall_64.o
......
...@@ -69,4 +69,7 @@ void common(void) { ...@@ -69,4 +69,7 @@ void common(void) {
OFFSET(BP_kernel_alignment, boot_params, hdr.kernel_alignment); OFFSET(BP_kernel_alignment, boot_params, hdr.kernel_alignment);
OFFSET(BP_pref_address, boot_params, hdr.pref_address); OFFSET(BP_pref_address, boot_params, hdr.pref_address);
OFFSET(BP_code32_start, boot_params, hdr.code32_start); OFFSET(BP_code32_start, boot_params, hdr.code32_start);
BLANK();
DEFINE(PTREGS_SIZE, sizeof(struct pt_regs));
} }
...@@ -298,6 +298,13 @@ ENTRY(ret_from_fork) ...@@ -298,6 +298,13 @@ ENTRY(ret_from_fork)
CFI_ENDPROC CFI_ENDPROC
END(ret_from_fork) END(ret_from_fork)
ENTRY(ret_from_kernel_execve)
movl %eax, %esp
movl $0,PT_EAX(%esp)
GET_THREAD_INFO(%ebp)
jmp syscall_exit
END(ret_from_kernel_execve)
/* /*
* Interrupt exit functions should be protected against kprobes * Interrupt exit functions should be protected against kprobes
*/ */
...@@ -322,8 +329,7 @@ ret_from_intr: ...@@ -322,8 +329,7 @@ ret_from_intr:
andl $(X86_EFLAGS_VM | SEGMENT_RPL_MASK), %eax andl $(X86_EFLAGS_VM | SEGMENT_RPL_MASK), %eax
#else #else
/* /*
* We can be coming here from a syscall done in the kernel space, * We can be coming here from child spawned by kernel_thread().
* e.g. a failed kernel_execve().
*/ */
movl PT_CS(%esp), %eax movl PT_CS(%esp), %eax
andl $SEGMENT_RPL_MASK, %eax andl $SEGMENT_RPL_MASK, %eax
...@@ -727,7 +733,6 @@ ENDPROC(ptregs_##name) ...@@ -727,7 +733,6 @@ ENDPROC(ptregs_##name)
PTREGSCALL1(iopl) PTREGSCALL1(iopl)
PTREGSCALL0(fork) PTREGSCALL0(fork)
PTREGSCALL0(vfork) PTREGSCALL0(vfork)
PTREGSCALL3(execve)
PTREGSCALL2(sigaltstack) PTREGSCALL2(sigaltstack)
PTREGSCALL0(sigreturn) PTREGSCALL0(sigreturn)
PTREGSCALL0(rt_sigreturn) PTREGSCALL0(rt_sigreturn)
......
...@@ -767,7 +767,6 @@ ENTRY(stub_execve) ...@@ -767,7 +767,6 @@ ENTRY(stub_execve)
PARTIAL_FRAME 0 PARTIAL_FRAME 0
SAVE_REST SAVE_REST
FIXUP_TOP_OF_STACK %r11 FIXUP_TOP_OF_STACK %r11
movq %rsp, %rcx
call sys_execve call sys_execve
RESTORE_TOP_OF_STACK %r11 RESTORE_TOP_OF_STACK %r11
movq %rax,RAX(%rsp) movq %rax,RAX(%rsp)
...@@ -817,8 +816,7 @@ ENTRY(stub_x32_execve) ...@@ -817,8 +816,7 @@ ENTRY(stub_x32_execve)
PARTIAL_FRAME 0 PARTIAL_FRAME 0
SAVE_REST SAVE_REST
FIXUP_TOP_OF_STACK %r11 FIXUP_TOP_OF_STACK %r11
movq %rsp, %rcx call compat_sys_execve
call sys32_execve
RESTORE_TOP_OF_STACK %r11 RESTORE_TOP_OF_STACK %r11
movq %rax,RAX(%rsp) movq %rax,RAX(%rsp)
RESTORE_REST RESTORE_REST
...@@ -1216,36 +1214,19 @@ bad_gs: ...@@ -1216,36 +1214,19 @@ bad_gs:
jmp 2b jmp 2b
.previous .previous
/* ENTRY(ret_from_kernel_execve)
* execve(). This function needs to use IRET, not SYSRET, to set up all state properly. movq %rdi, %rsp
* movl $0, RAX(%rsp)
* C extern interface: // RESTORE_REST
* extern long execve(const char *name, char **argv, char **envp) movq 0*8(%rsp), %r15
* movq 1*8(%rsp), %r14
* asm input arguments: movq 2*8(%rsp), %r13
* rdi: name, rsi: argv, rdx: envp movq 3*8(%rsp), %r12
* movq 4*8(%rsp), %rbp
* We want to fallback into: movq 5*8(%rsp), %rbx
* extern long sys_execve(const char *name, char **argv,char **envp, struct pt_regs *regs) addq $(6*8), %rsp
* jmp int_ret_from_sys_call
* do_sys_execve asm fallback arguments: END(ret_from_kernel_execve)
* rdi: name, rsi: argv, rdx: envp, rcx: fake frame on the stack
*/
ENTRY(kernel_execve)
CFI_STARTPROC
FAKE_STACK_FRAME $0
SAVE_ALL
movq %rsp,%rcx
call sys_execve
movq %rax, RAX(%rsp)
RESTORE_REST
testq %rax,%rax
je int_ret_from_sys_call
RESTORE_ARGS
UNFAKE_STACK_FRAME
ret
CFI_ENDPROC
END(kernel_execve)
/* Call softirq on interrupt stack. Interrupts are off. */ /* Call softirq on interrupt stack. Interrupts are off. */
ENTRY(call_softirq) ENTRY(call_softirq)
......
...@@ -298,25 +298,6 @@ sys_clone(unsigned long clone_flags, unsigned long newsp, ...@@ -298,25 +298,6 @@ sys_clone(unsigned long clone_flags, unsigned long newsp,
return do_fork(clone_flags, newsp, regs, 0, parent_tid, child_tid); return do_fork(clone_flags, newsp, regs, 0, parent_tid, child_tid);
} }
/*
* sys_execve() executes a new program.
*/
long sys_execve(const char __user *name,
const char __user *const __user *argv,
const char __user *const __user *envp, struct pt_regs *regs)
{
long error;
char *filename;
filename = getname(name);
error = PTR_ERR(filename);
if (IS_ERR(filename))
return error;
error = do_execve(filename, argv, envp, regs);
putname(filename);
return error;
}
/* /*
* Idle related variables and functions * Idle related variables and functions
*/ */
......
...@@ -207,6 +207,7 @@ start_thread(struct pt_regs *regs, unsigned long new_ip, unsigned long new_sp) ...@@ -207,6 +207,7 @@ start_thread(struct pt_regs *regs, unsigned long new_ip, unsigned long new_sp)
regs->cs = __USER_CS; regs->cs = __USER_CS;
regs->ip = new_ip; regs->ip = new_ip;
regs->sp = new_sp; regs->sp = new_sp;
regs->flags = X86_EFLAGS_IF;
/* /*
* Free the old FP and other extended state * Free the old FP and other extended state
*/ */
......
/*
* This file contains various random system calls that
* have a non-standard calling sequence on the Linux/i386
* platform.
*/
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/fs.h>
#include <linux/smp.h>
#include <linux/sem.h>
#include <linux/msg.h>
#include <linux/shm.h>
#include <linux/stat.h>
#include <linux/syscalls.h>
#include <linux/mman.h>
#include <linux/file.h>
#include <linux/utsname.h>
#include <linux/ipc.h>
#include <linux/uaccess.h>
#include <linux/unistd.h>
#include <asm/syscalls.h>
/*
* Do a system call from kernel instead of calling sys_execve so we
* end up with proper pt_regs.
*/
int kernel_execve(const char *filename,
const char *const argv[],
const char *const envp[])
{
long __res;
asm volatile ("int $0x80"
: "=a" (__res)
: "0" (__NR_execve), "b" (filename), "c" (argv), "d" (envp) : "memory");
return __res;
}
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
8 i386 creat sys_creat 8 i386 creat sys_creat
9 i386 link sys_link 9 i386 link sys_link
10 i386 unlink sys_unlink 10 i386 unlink sys_unlink
11 i386 execve ptregs_execve stub32_execve 11 i386 execve sys_execve stub32_execve
12 i386 chdir sys_chdir 12 i386 chdir sys_chdir
13 i386 time sys_time compat_sys_time 13 i386 time sys_time compat_sys_time
14 i386 mknod sys_mknod 14 i386 mknod sys_mknod
......
...@@ -25,7 +25,6 @@ ...@@ -25,7 +25,6 @@
#define old_mmap sys_old_mmap #define old_mmap sys_old_mmap
#define ptregs_fork sys_fork #define ptregs_fork sys_fork
#define ptregs_execve sys_execve
#define ptregs_iopl sys_iopl #define ptregs_iopl sys_iopl
#define ptregs_vm86old sys_vm86old #define ptregs_vm86old sys_vm86old
#define ptregs_clone i386_clone #define ptregs_clone i386_clone
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment