Merge branch 'execve' into upstream
* execve: arm64: Use generic sys_execve() implementation arm64: Use generic kernel_execve() implementation arm64: Use generic kernel_thread() implementation
This commit is contained in:
commit
908816dfe6
|
@ -7,6 +7,8 @@ config ARM64
|
|||
select GENERIC_IOMAP
|
||||
select GENERIC_IRQ_PROBE
|
||||
select GENERIC_IRQ_SHOW
|
||||
select GENERIC_KERNEL_EXECVE
|
||||
select GENERIC_KERNEL_THREAD
|
||||
select GENERIC_SMP_IDLE_THREAD
|
||||
select GENERIC_TIME_VSYSCALL
|
||||
select HARDIRQS_SW_RESEND
|
||||
|
|
|
@ -128,11 +128,6 @@ unsigned long get_wchan(struct task_struct *p);
|
|||
extern struct task_struct *cpu_switch_to(struct task_struct *prev,
|
||||
struct task_struct *next);
|
||||
|
||||
/*
|
||||
* Create a new kernel thread
|
||||
*/
|
||||
extern int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags);
|
||||
|
||||
#define task_pt_regs(p) \
|
||||
((struct pt_regs *)(THREAD_START_SP + task_stack_page(p)) - 1)
|
||||
|
||||
|
|
|
@ -23,9 +23,6 @@
|
|||
/*
|
||||
* System call wrappers implemented in kernel/entry.S.
|
||||
*/
|
||||
asmlinkage long sys_execve_wrapper(const char __user *filename,
|
||||
const char __user *const __user *argv,
|
||||
const char __user *const __user *envp);
|
||||
asmlinkage long sys_clone_wrapper(unsigned long clone_flags,
|
||||
unsigned long newsp,
|
||||
void __user *parent_tid,
|
||||
|
|
|
@ -25,4 +25,5 @@
|
|||
#define __ARCH_WANT_COMPAT_SYS_RT_SIGSUSPEND
|
||||
#define __ARCH_WANT_COMPAT_SYS_SENDFILE
|
||||
#endif
|
||||
#define __ARCH_WANT_SYS_EXECVE
|
||||
#include <uapi/asm/unistd.h>
|
||||
|
|
|
@ -32,7 +32,7 @@ __SYSCALL(7, sys_ni_syscall) /* 7 was sys_waitpid */
|
|||
__SYSCALL(8, sys_creat)
|
||||
__SYSCALL(9, sys_link)
|
||||
__SYSCALL(10, sys_unlink)
|
||||
__SYSCALL(11, compat_sys_execve_wrapper)
|
||||
__SYSCALL(11, compat_sys_execve)
|
||||
__SYSCALL(12, sys_chdir)
|
||||
__SYSCALL(13, sys_ni_syscall) /* 13 was sys_time */
|
||||
__SYSCALL(14, sys_mknod)
|
||||
|
|
|
@ -594,7 +594,7 @@ work_resched:
|
|||
/*
|
||||
* "slow" syscall return path.
|
||||
*/
|
||||
ENTRY(ret_to_user)
|
||||
ret_to_user:
|
||||
disable_irq // disable interrupts
|
||||
ldr x1, [tsk, #TI_FLAGS]
|
||||
and x2, x1, #_TIF_WORK_MASK
|
||||
|
@ -611,7 +611,10 @@ ENDPROC(ret_to_user)
|
|||
*/
|
||||
ENTRY(ret_from_fork)
|
||||
bl schedule_tail
|
||||
get_thread_info tsk
|
||||
cbz x19, 1f // not a kernel thread
|
||||
mov x0, x20
|
||||
blr x19
|
||||
1: get_thread_info tsk
|
||||
b ret_to_user
|
||||
ENDPROC(ret_from_fork)
|
||||
|
||||
|
@ -673,11 +676,6 @@ __sys_trace_return:
|
|||
/*
|
||||
* Special system call wrappers.
|
||||
*/
|
||||
ENTRY(sys_execve_wrapper)
|
||||
mov x3, sp
|
||||
b sys_execve
|
||||
ENDPROC(sys_execve_wrapper)
|
||||
|
||||
ENTRY(sys_clone_wrapper)
|
||||
mov x5, sp
|
||||
b sys_clone
|
||||
|
|
|
@ -240,27 +240,35 @@ int copy_thread(unsigned long clone_flags, unsigned long stack_start,
|
|||
struct pt_regs *childregs = task_pt_regs(p);
|
||||
unsigned long tls = p->thread.tp_value;
|
||||
|
||||
*childregs = *regs;
|
||||
childregs->regs[0] = 0;
|
||||
|
||||
if (is_compat_thread(task_thread_info(p)))
|
||||
childregs->compat_sp = stack_start;
|
||||
else {
|
||||
/*
|
||||
* Read the current TLS pointer from tpidr_el0 as it may be
|
||||
* out-of-sync with the saved value.
|
||||
*/
|
||||
asm("mrs %0, tpidr_el0" : "=r" (tls));
|
||||
childregs->sp = stack_start;
|
||||
}
|
||||
|
||||
memset(&p->thread.cpu_context, 0, sizeof(struct cpu_context));
|
||||
p->thread.cpu_context.sp = (unsigned long)childregs;
|
||||
p->thread.cpu_context.pc = (unsigned long)ret_from_fork;
|
||||
|
||||
/* If a TLS pointer was passed to clone, use that for the new thread. */
|
||||
if (clone_flags & CLONE_SETTLS)
|
||||
tls = regs->regs[3];
|
||||
if (likely(regs)) {
|
||||
*childregs = *regs;
|
||||
childregs->regs[0] = 0;
|
||||
if (is_compat_thread(task_thread_info(p))) {
|
||||
childregs->compat_sp = stack_start;
|
||||
} else {
|
||||
/*
|
||||
* Read the current TLS pointer from tpidr_el0 as it may be
|
||||
* out-of-sync with the saved value.
|
||||
*/
|
||||
asm("mrs %0, tpidr_el0" : "=r" (tls));
|
||||
childregs->sp = stack_start;
|
||||
}
|
||||
/*
|
||||
* If a TLS pointer was passed to clone (4th argument), use it
|
||||
* for the new thread.
|
||||
*/
|
||||
if (clone_flags & CLONE_SETTLS)
|
||||
tls = regs->regs[3];
|
||||
} else {
|
||||
memset(childregs, 0, sizeof(struct pt_regs));
|
||||
childregs->pstate = PSR_MODE_EL1h;
|
||||
p->thread.cpu_context.x19 = stack_start;
|
||||
p->thread.cpu_context.x20 = stk_sz;
|
||||
}
|
||||
p->thread.cpu_context.pc = (unsigned long)ret_from_fork;
|
||||
p->thread.cpu_context.sp = (unsigned long)childregs;
|
||||
p->thread.tp_value = tls;
|
||||
|
||||
ptrace_hw_copy_thread(p);
|
||||
|
@ -309,43 +317,6 @@ struct task_struct *__switch_to(struct task_struct *prev,
|
|||
return last;
|
||||
}
|
||||
|
||||
/*
|
||||
* Shuffle the argument into the correct register before calling the
|
||||
* thread function. x1 is the thread argument, x2 is the pointer to
|
||||
* the thread function, and x3 points to the exit function.
|
||||
*/
|
||||
extern void kernel_thread_helper(void);
|
||||
asm( ".section .text\n"
|
||||
" .align\n"
|
||||
" .type kernel_thread_helper, #function\n"
|
||||
"kernel_thread_helper:\n"
|
||||
" mov x0, x1\n"
|
||||
" mov x30, x3\n"
|
||||
" br x2\n"
|
||||
" .size kernel_thread_helper, . - kernel_thread_helper\n"
|
||||
" .previous");
|
||||
|
||||
#define kernel_thread_exit do_exit
|
||||
|
||||
/*
|
||||
* Create a kernel thread.
|
||||
*/
|
||||
pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
|
||||
{
|
||||
struct pt_regs regs;
|
||||
|
||||
memset(®s, 0, sizeof(regs));
|
||||
|
||||
regs.regs[1] = (unsigned long)arg;
|
||||
regs.regs[2] = (unsigned long)fn;
|
||||
regs.regs[3] = (unsigned long)kernel_thread_exit;
|
||||
regs.pc = (unsigned long)kernel_thread_helper;
|
||||
regs.pstate = PSR_MODE_EL1h;
|
||||
|
||||
return do_fork(flags|CLONE_VM|CLONE_UNTRACED, 0, ®s, 0, NULL, NULL);
|
||||
}
|
||||
EXPORT_SYMBOL(kernel_thread);
|
||||
|
||||
unsigned long get_wchan(struct task_struct *p)
|
||||
{
|
||||
struct stackframe frame;
|
||||
|
|
|
@ -41,70 +41,6 @@ asmlinkage long sys_clone(unsigned long clone_flags, unsigned long newsp,
|
|||
return do_fork(clone_flags, newsp, regs, 0, parent_tidptr, child_tidptr);
|
||||
}
|
||||
|
||||
/*
|
||||
* sys_execve() executes a new program.
|
||||
*/
|
||||
asmlinkage long sys_execve(const char __user *filenamei,
|
||||
const char __user *const __user *argv,
|
||||
const char __user *const __user *envp,
|
||||
struct pt_regs *regs)
|
||||
{
|
||||
long error;
|
||||
struct filename *filename;
|
||||
|
||||
filename = getname(filenamei);
|
||||
error = PTR_ERR(filename);
|
||||
if (IS_ERR(filename))
|
||||
goto out;
|
||||
error = do_execve(filename->name, argv, envp, regs);
|
||||
putname(filename);
|
||||
out:
|
||||
return error;
|
||||
}
|
||||
|
||||
int kernel_execve(const char *filename,
|
||||
const char *const argv[],
|
||||
const char *const envp[])
|
||||
{
|
||||
struct pt_regs regs;
|
||||
int ret;
|
||||
|
||||
memset(®s, 0, sizeof(struct pt_regs));
|
||||
ret = do_execve(filename,
|
||||
(const char __user *const __user *)argv,
|
||||
(const char __user *const __user *)envp, ®s);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
/*
|
||||
* Save argc to the register structure for userspace.
|
||||
*/
|
||||
regs.regs[0] = ret;
|
||||
|
||||
/*
|
||||
* We were successful. We won't be returning to our caller, but
|
||||
* instead to user space by manipulating the kernel stack.
|
||||
*/
|
||||
asm( "add x0, %0, %1\n\t"
|
||||
"mov x1, %2\n\t"
|
||||
"mov x2, %3\n\t"
|
||||
"bl memmove\n\t" /* copy regs to top of stack */
|
||||
"mov x27, #0\n\t" /* not a syscall */
|
||||
"mov x28, %0\n\t" /* thread structure */
|
||||
"mov sp, x0\n\t" /* reposition stack pointer */
|
||||
"b ret_to_user"
|
||||
:
|
||||
: "r" (current_thread_info()),
|
||||
"Ir" (THREAD_START_SP - sizeof(regs)),
|
||||
"r" (®s),
|
||||
"Ir" (sizeof(regs))
|
||||
: "x0", "x1", "x2", "x27", "x28", "x30", "memory");
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(kernel_execve);
|
||||
|
||||
asmlinkage long sys_mmap(unsigned long addr, unsigned long len,
|
||||
unsigned long prot, unsigned long flags,
|
||||
unsigned long fd, off_t off)
|
||||
|
@ -118,7 +54,6 @@ asmlinkage long sys_mmap(unsigned long addr, unsigned long len,
|
|||
/*
|
||||
* Wrappers to pass the pt_regs argument.
|
||||
*/
|
||||
#define sys_execve sys_execve_wrapper
|
||||
#define sys_clone sys_clone_wrapper
|
||||
#define sys_rt_sigreturn sys_rt_sigreturn_wrapper
|
||||
#define sys_sigaltstack sys_sigaltstack_wrapper
|
||||
|
|
|
@ -36,11 +36,6 @@ compat_sys_vfork_wrapper:
|
|||
b compat_sys_vfork
|
||||
ENDPROC(compat_sys_vfork_wrapper)
|
||||
|
||||
compat_sys_execve_wrapper:
|
||||
mov x3, sp
|
||||
b compat_sys_execve
|
||||
ENDPROC(compat_sys_execve_wrapper)
|
||||
|
||||
compat_sys_clone_wrapper:
|
||||
mov x5, sp
|
||||
b compat_sys_clone
|
||||
|
|
|
@ -49,24 +49,6 @@ asmlinkage int compat_sys_vfork(struct pt_regs *regs)
|
|||
regs, 0, NULL, NULL);
|
||||
}
|
||||
|
||||
asmlinkage int compat_sys_execve(const char __user *filenamei,
|
||||
compat_uptr_t argv, compat_uptr_t envp,
|
||||
struct pt_regs *regs)
|
||||
{
|
||||
int error;
|
||||
struct filename *filename;
|
||||
|
||||
filename = getname(filenamei);
|
||||
error = PTR_ERR(filename);
|
||||
if (IS_ERR(filename))
|
||||
goto out;
|
||||
error = compat_do_execve(filename->name, compat_ptr(argv),
|
||||
compat_ptr(envp), regs);
|
||||
putname(filename);
|
||||
out:
|
||||
return error;
|
||||
}
|
||||
|
||||
asmlinkage int compat_sys_sched_rr_get_interval(compat_pid_t pid,
|
||||
struct compat_timespec __user *interval)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue