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: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
parent
7076aada10
commit
6783eaa2e1
@ -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)
|
|||||||
}
|
}
|
||||||
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;
|
UML_LONGJMP(current->thread.exec_buf, 1);
|
||||||
|
|
||||||
err = do_execve(file, argv, env, ¤t->thread.regs);
|
|
||||||
if (!err)
|
|
||||||
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, ¤t->thread.regs);
|
|
||||||
putname(filename);
|
|
||||||
out:
|
|
||||||
return error;
|
|
||||||
}
|
}
|
||||||
|
@ -1 +0,0 @@
|
|||||||
extern long um_execve(const char *file, const char __user *const __user *argv, const char __user *const __user *env);
|
|
@ -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,
|
|||||||
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)
|
|||||||
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,
|
|||||||
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);
|
|||||||
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 *);
|
|||||||
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 @@
|
|||||||
# 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
|
|||||||
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) {
|
|||||||
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)
|
|||||||
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:
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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:
|
|||||||
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,
|
|||||||
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)
|
|||||||
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
|
||||||
*/
|
*/
|
||||||
|
@ -1,40 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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 @@
|
|||||||
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 @@
|
|||||||
#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
|
||||||
|
Loading…
Reference in New Issue
Block a user