Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/signal
Pull generic execve() changes from Al Viro: "This introduces the generic kernel_thread() and kernel_execve() functions, and switches x86, arm, alpha, um and s390 over to them." * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/signal: (26 commits) s390: convert to generic kernel_execve() s390: switch to generic kernel_thread() s390: fold kernel_thread_helper() into ret_from_fork() s390: fold execve_tail() into start_thread(), convert to generic sys_execve() um: switch to generic kernel_thread() x86, um/x86: switch to generic sys_execve and kernel_execve x86: split ret_from_fork alpha: introduce ret_from_kernel_execve(), switch to generic kernel_execve() alpha: switch to generic kernel_thread() alpha: switch to generic sys_execve() arm: get rid of execve wrapper, switch to generic execve() implementation arm: optimized current_pt_regs() arm: introduce ret_from_kernel_execve(), switch to generic kernel_execve() arm: split ret_from_fork, simplify kernel_thread() [based on patch by rmk] generic sys_execve() generic kernel_execve() new helper: current_pt_regs() preparation for generic kernel_thread() um: kill thread->forking um: let signal_delivered() do SIGTRAP on singlestepping into handler ...
This commit is contained in:
@@ -432,32 +432,6 @@ sys32_rt_sigqueueinfo(int pid, int sig, compat_siginfo_t __user *uinfo)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* sys32_execve() executes a new program after the asm stub has set
|
||||
* things up for us. This should basically do what I want it to.
|
||||
*/
|
||||
asmlinkage long sys32_execve(const char __user *name, compat_uptr_t __user *argv,
|
||||
compat_uptr_t __user *envp)
|
||||
{
|
||||
struct pt_regs *regs = task_pt_regs(current);
|
||||
char *filename;
|
||||
long rc;
|
||||
|
||||
filename = getname(name);
|
||||
rc = PTR_ERR(filename);
|
||||
if (IS_ERR(filename))
|
||||
return rc;
|
||||
rc = compat_do_execve(filename, argv, envp, regs);
|
||||
if (rc)
|
||||
goto out;
|
||||
current->thread.fp_regs.fpc=0;
|
||||
asm volatile("sfpc %0,0" : : "d" (0));
|
||||
rc = regs->gprs[2];
|
||||
out:
|
||||
putname(filename);
|
||||
return rc;
|
||||
}
|
||||
|
||||
asmlinkage long sys32_pread64(unsigned int fd, char __user *ubuf,
|
||||
size_t count, u32 poshi, u32 poslo)
|
||||
{
|
||||
|
@@ -125,8 +125,6 @@ long sys32_rt_sigprocmask(int how, compat_sigset_t __user *set,
|
||||
compat_sigset_t __user *oset, size_t sigsetsize);
|
||||
long sys32_rt_sigpending(compat_sigset_t __user *set, size_t sigsetsize);
|
||||
long sys32_rt_sigqueueinfo(int pid, int sig, compat_siginfo_t __user *uinfo);
|
||||
long sys32_execve(const char __user *name, compat_uptr_t __user *argv,
|
||||
compat_uptr_t __user *envp);
|
||||
long sys32_init_module(void __user *umod, unsigned long len,
|
||||
const char __user *uargs);
|
||||
long sys32_delete_module(const char __user *name_user, unsigned int flags);
|
||||
|
@@ -1576,7 +1576,7 @@ ENTRY(sys32_execve_wrapper)
|
||||
llgtr %r2,%r2 # char *
|
||||
llgtr %r3,%r3 # compat_uptr_t *
|
||||
llgtr %r4,%r4 # compat_uptr_t *
|
||||
jg sys32_execve # branch to system call
|
||||
jg compat_sys_execve # branch to system call
|
||||
|
||||
ENTRY(sys_fanotify_init_wrapper)
|
||||
llgfr %r2,%r2 # unsigned int
|
||||
|
@@ -331,45 +331,38 @@ ENTRY(ret_from_fork)
|
||||
l %r12,__LC_THREAD_INFO
|
||||
l %r13,__LC_SVC_NEW_PSW+4
|
||||
tm __PT_PSW+1(%r11),0x01 # forking a kernel thread ?
|
||||
jo 0f
|
||||
st %r15,__PT_R15(%r11) # store stack pointer for new kthread
|
||||
0: l %r1,BASED(.Lschedule_tail)
|
||||
je 1f
|
||||
l %r1,BASED(.Lschedule_tail)
|
||||
basr %r14,%r1 # call schedule_tail
|
||||
TRACE_IRQS_ON
|
||||
ssm __LC_SVC_NEW_PSW # reenable interrupts
|
||||
j sysc_tracenogo
|
||||
|
||||
1: # it's a kernel thread
|
||||
st %r15,__PT_R15(%r11) # store stack pointer for new kthread
|
||||
l %r1,BASED(.Lschedule_tail)
|
||||
basr %r14,%r1 # call schedule_tail
|
||||
TRACE_IRQS_ON
|
||||
ssm __LC_SVC_NEW_PSW # reenable interrupts
|
||||
lm %r9,%r11,__PT_R9(%r11) # load gprs
|
||||
ENTRY(kernel_thread_starter)
|
||||
la %r2,0(%r10)
|
||||
basr %r14,%r9
|
||||
la %r2,0
|
||||
br %r11 # do_exit
|
||||
|
||||
#
|
||||
# kernel_execve function needs to deal with pt_regs that is not
|
||||
# at the usual place
|
||||
#
|
||||
ENTRY(kernel_execve)
|
||||
stm %r12,%r15,48(%r15)
|
||||
lr %r14,%r15
|
||||
l %r13,__LC_SVC_NEW_PSW+4
|
||||
ahi %r15,-(STACK_FRAME_OVERHEAD + __PT_SIZE)
|
||||
st %r14,__SF_BACKCHAIN(%r15)
|
||||
la %r12,STACK_FRAME_OVERHEAD(%r15)
|
||||
xc 0(__PT_SIZE,%r12),0(%r12)
|
||||
l %r1,BASED(.Ldo_execve)
|
||||
lr %r5,%r12
|
||||
basr %r14,%r1 # call do_execve
|
||||
ltr %r2,%r2
|
||||
je 0f
|
||||
ahi %r15,(STACK_FRAME_OVERHEAD + __PT_SIZE)
|
||||
lm %r12,%r15,48(%r15)
|
||||
br %r14
|
||||
# execve succeeded.
|
||||
0: ssm __LC_PGM_NEW_PSW # disable I/O and ext. interrupts
|
||||
l %r15,__LC_KERNEL_STACK # load ksp
|
||||
ahi %r15,-(STACK_FRAME_OVERHEAD + __PT_SIZE)
|
||||
la %r11,STACK_FRAME_OVERHEAD(%r15)
|
||||
mvc 0(__PT_SIZE,%r11),0(%r12) # copy pt_regs
|
||||
l %r12,__LC_THREAD_INFO
|
||||
ENTRY(ret_from_kernel_execve)
|
||||
ssm __LC_PGM_NEW_PSW # disable I/O and ext. interrupts
|
||||
lr %r15,%r2
|
||||
lr %r11,%r2
|
||||
ahi %r15,-STACK_FRAME_OVERHEAD
|
||||
xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15)
|
||||
l %r12,__LC_THREAD_INFO
|
||||
ssm __LC_SVC_NEW_PSW # reenable interrupts
|
||||
l %r1,BASED(.Lexecve_tail)
|
||||
basr %r14,%r1 # call execve_tail
|
||||
j sysc_return
|
||||
|
||||
/*
|
||||
@@ -931,8 +924,6 @@ cleanup_idle_wait:
|
||||
.Ldo_signal: .long do_signal
|
||||
.Ldo_notify_resume: .long do_notify_resume
|
||||
.Ldo_per_trap: .long do_per_trap
|
||||
.Ldo_execve: .long do_execve
|
||||
.Lexecve_tail: .long execve_tail
|
||||
.Ljump_table: .long pgm_check_table
|
||||
.Lschedule: .long schedule
|
||||
#ifdef CONFIG_PREEMPT
|
||||
|
@@ -58,9 +58,6 @@ long sys_fork(void);
|
||||
long sys_clone(unsigned long newsp, unsigned long clone_flags,
|
||||
int __user *parent_tidptr, int __user *child_tidptr);
|
||||
long sys_vfork(void);
|
||||
void execve_tail(void);
|
||||
long sys_execve(const char __user *name, const char __user *const __user *argv,
|
||||
const char __user *const __user *envp);
|
||||
long sys_sigsuspend(int history0, int history1, old_sigset_t mask);
|
||||
long sys_sigaction(int sig, const struct old_sigaction __user *act,
|
||||
struct old_sigaction __user *oact);
|
||||
|
@@ -353,41 +353,31 @@ ENTRY(ret_from_fork)
|
||||
la %r11,STACK_FRAME_OVERHEAD(%r15)
|
||||
lg %r12,__LC_THREAD_INFO
|
||||
tm __PT_PSW+1(%r11),0x01 # forking a kernel thread ?
|
||||
jo 0f
|
||||
stg %r15,__PT_R15(%r11) # store stack pointer for new kthread
|
||||
0: brasl %r14,schedule_tail
|
||||
je 1f
|
||||
brasl %r14,schedule_tail
|
||||
TRACE_IRQS_ON
|
||||
ssm __LC_SVC_NEW_PSW # reenable interrupts
|
||||
j sysc_tracenogo
|
||||
|
||||
#
|
||||
# kernel_execve function needs to deal with pt_regs that is not
|
||||
# at the usual place
|
||||
#
|
||||
ENTRY(kernel_execve)
|
||||
stmg %r12,%r15,96(%r15)
|
||||
lgr %r14,%r15
|
||||
aghi %r15,-(STACK_FRAME_OVERHEAD + __PT_SIZE)
|
||||
stg %r14,__SF_BACKCHAIN(%r15)
|
||||
la %r12,STACK_FRAME_OVERHEAD(%r15)
|
||||
xc 0(__PT_SIZE,%r12),0(%r12)
|
||||
lgr %r5,%r12
|
||||
brasl %r14,do_execve
|
||||
ltgfr %r2,%r2
|
||||
je 0f
|
||||
aghi %r15,(STACK_FRAME_OVERHEAD + __PT_SIZE)
|
||||
lmg %r12,%r15,96(%r15)
|
||||
br %r14
|
||||
# execve succeeded.
|
||||
0: ssm __LC_PGM_NEW_PSW # disable I/O and ext. interrupts
|
||||
lg %r15,__LC_KERNEL_STACK # load ksp
|
||||
aghi %r15,-(STACK_FRAME_OVERHEAD + __PT_SIZE)
|
||||
la %r11,STACK_FRAME_OVERHEAD(%r15)
|
||||
mvc 0(__PT_SIZE,%r11),0(%r12) # copy pt_regs
|
||||
lg %r12,__LC_THREAD_INFO
|
||||
xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15)
|
||||
1: # it's a kernel thread
|
||||
stg %r15,__PT_R15(%r11) # store stack pointer for new kthread
|
||||
brasl %r14,schedule_tail
|
||||
TRACE_IRQS_ON
|
||||
ssm __LC_SVC_NEW_PSW # reenable interrupts
|
||||
lmg %r9,%r11,__PT_R9(%r11) # load gprs
|
||||
ENTRY(kernel_thread_starter)
|
||||
la %r2,0(%r10)
|
||||
basr %r14,%r9
|
||||
la %r2,0
|
||||
br %r11 # do_exit
|
||||
|
||||
ENTRY(ret_from_kernel_execve)
|
||||
ssm __LC_PGM_NEW_PSW # disable I/O and ext. interrupts
|
||||
lgr %r15,%r2
|
||||
lgr %r11,%r2
|
||||
aghi %r15,-STACK_FRAME_OVERHEAD
|
||||
xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15)
|
||||
lg %r12,__LC_THREAD_INFO
|
||||
ssm __LC_SVC_NEW_PSW # reenable interrupts
|
||||
brasl %r14,execve_tail
|
||||
j sysc_return
|
||||
|
||||
/*
|
||||
|
@@ -100,35 +100,6 @@ void cpu_idle(void)
|
||||
|
||||
extern void __kprobes kernel_thread_starter(void);
|
||||
|
||||
asm(
|
||||
".section .kprobes.text, \"ax\"\n"
|
||||
".global kernel_thread_starter\n"
|
||||
"kernel_thread_starter:\n"
|
||||
" la 2,0(10)\n"
|
||||
" basr 14,9\n"
|
||||
" la 2,0\n"
|
||||
" br 11\n"
|
||||
".previous\n");
|
||||
|
||||
int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
|
||||
{
|
||||
struct pt_regs regs;
|
||||
|
||||
memset(®s, 0, sizeof(regs));
|
||||
regs.psw.mask = psw_kernel_bits |
|
||||
PSW_MASK_DAT | PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK;
|
||||
regs.psw.addr = (unsigned long) kernel_thread_starter | PSW_ADDR_AMODE;
|
||||
regs.gprs[9] = (unsigned long) fn;
|
||||
regs.gprs[10] = (unsigned long) arg;
|
||||
regs.gprs[11] = (unsigned long) do_exit;
|
||||
regs.orig_gpr2 = -1;
|
||||
|
||||
/* Ok, create the new process.. */
|
||||
return do_fork(flags | CLONE_VM | CLONE_UNTRACED,
|
||||
0, ®s, 0, NULL, NULL);
|
||||
}
|
||||
EXPORT_SYMBOL(kernel_thread);
|
||||
|
||||
/*
|
||||
* Free current thread data structures etc..
|
||||
*/
|
||||
@@ -146,7 +117,7 @@ void release_thread(struct task_struct *dead_task)
|
||||
}
|
||||
|
||||
int copy_thread(unsigned long clone_flags, unsigned long new_stackp,
|
||||
unsigned long unused,
|
||||
unsigned long arg,
|
||||
struct task_struct *p, struct pt_regs *regs)
|
||||
{
|
||||
struct thread_info *ti;
|
||||
@@ -158,20 +129,44 @@ int copy_thread(unsigned long clone_flags, unsigned long new_stackp,
|
||||
|
||||
frame = container_of(task_pt_regs(p), struct fake_frame, childregs);
|
||||
p->thread.ksp = (unsigned long) frame;
|
||||
/* Store access registers to kernel stack of new process. */
|
||||
frame->childregs = *regs;
|
||||
frame->childregs.gprs[2] = 0; /* child returns 0 on fork. */
|
||||
frame->childregs.gprs[15] = new_stackp;
|
||||
frame->sf.back_chain = 0;
|
||||
/* Save access registers to new thread structure. */
|
||||
save_access_regs(&p->thread.acrs[0]);
|
||||
/* start new process with ar4 pointing to the correct address space */
|
||||
p->thread.mm_segment = get_fs();
|
||||
/* Don't copy debug registers */
|
||||
memset(&p->thread.per_user, 0, sizeof(p->thread.per_user));
|
||||
memset(&p->thread.per_event, 0, sizeof(p->thread.per_event));
|
||||
clear_tsk_thread_flag(p, TIF_SINGLE_STEP);
|
||||
clear_tsk_thread_flag(p, TIF_PER_TRAP);
|
||||
/* Initialize per thread user and system timer values */
|
||||
ti = task_thread_info(p);
|
||||
ti->user_timer = 0;
|
||||
ti->system_timer = 0;
|
||||
|
||||
frame->sf.back_chain = 0;
|
||||
/* new return point is ret_from_fork */
|
||||
frame->sf.gprs[8] = (unsigned long) ret_from_fork;
|
||||
|
||||
/* fake return stack for resume(), don't go back to schedule */
|
||||
frame->sf.gprs[9] = (unsigned long) frame;
|
||||
|
||||
/* Save access registers to new thread structure. */
|
||||
save_access_regs(&p->thread.acrs[0]);
|
||||
/* Store access registers to kernel stack of new process. */
|
||||
if (unlikely(!regs)) {
|
||||
/* kernel thread */
|
||||
memset(&frame->childregs, 0, sizeof(struct pt_regs));
|
||||
frame->childregs.psw.mask = psw_kernel_bits | PSW_MASK_DAT |
|
||||
PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK;
|
||||
frame->childregs.psw.addr = PSW_ADDR_AMODE |
|
||||
(unsigned long) kernel_thread_starter;
|
||||
frame->childregs.gprs[9] = new_stackp; /* function */
|
||||
frame->childregs.gprs[10] = arg;
|
||||
frame->childregs.gprs[11] = (unsigned long) do_exit;
|
||||
frame->childregs.orig_gpr2 = -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
frame->childregs = *regs;
|
||||
frame->childregs.gprs[2] = 0; /* child returns 0 on fork. */
|
||||
frame->childregs.gprs[15] = new_stackp;
|
||||
|
||||
/* Don't copy runtime instrumentation info */
|
||||
p->thread.ri_cb = NULL;
|
||||
@@ -202,17 +197,6 @@ int copy_thread(unsigned long clone_flags, unsigned long new_stackp,
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_64BIT */
|
||||
/* start new process with ar4 pointing to the correct address space */
|
||||
p->thread.mm_segment = get_fs();
|
||||
/* Don't copy debug registers */
|
||||
memset(&p->thread.per_user, 0, sizeof(p->thread.per_user));
|
||||
memset(&p->thread.per_event, 0, sizeof(p->thread.per_event));
|
||||
clear_tsk_thread_flag(p, TIF_SINGLE_STEP);
|
||||
clear_tsk_thread_flag(p, TIF_PER_TRAP);
|
||||
/* Initialize per thread user and system timer values */
|
||||
ti = task_thread_info(p);
|
||||
ti->user_timer = 0;
|
||||
ti->system_timer = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -257,31 +241,6 @@ asmlinkage void execve_tail(void)
|
||||
asm volatile("sfpc %0,%0" : : "d" (0));
|
||||
}
|
||||
|
||||
/*
|
||||
* sys_execve() executes a new program.
|
||||
*/
|
||||
SYSCALL_DEFINE3(execve, const char __user *, name,
|
||||
const char __user *const __user *, argv,
|
||||
const char __user *const __user *, envp)
|
||||
{
|
||||
struct pt_regs *regs = task_pt_regs(current);
|
||||
char *filename;
|
||||
long rc;
|
||||
|
||||
filename = getname(name);
|
||||
rc = PTR_ERR(filename);
|
||||
if (IS_ERR(filename))
|
||||
return rc;
|
||||
rc = do_execve(filename, argv, envp, regs);
|
||||
if (rc)
|
||||
goto out;
|
||||
execve_tail();
|
||||
rc = regs->gprs[2];
|
||||
out:
|
||||
putname(filename);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* fill in the FPU structure for a core dump.
|
||||
*/
|
||||
|
Reference in New Issue
Block a user