Create full stack frame plus switch stack frame in copy_thread() when creating a kernel worker thread. The switch stack frame will then be consumed in resume(), leaving a full stack frame of zero content for ptrace to play with. Change ret_from_exception switch stack handling to restore the switch stack (and pop the return address restored by that)after return from kernel worker threads. Patch suggested by Linus (authored, actually - replace my signoff if that's not appropriate, please). Tested on both ARAnyM and Falcon hardware. CC: Eric W. Biederman <ebiederm@xxxxxxxxxxxx> CC: Linus Torvalds <torvalds@xxxxxxxxxxxxxxxxxxxx> CC: Andreas Schwab <schwab@xxxxxxxxxxxxxx> Signed-off-by: Michael Schmitz <schmitzmic@xxxxxxxxx> --- arch/m68k/kernel/entry.S | 11 +++++++++++ arch/m68k/kernel/process.c | 13 +++++++++---- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/arch/m68k/kernel/entry.S b/arch/m68k/kernel/entry.S index 275452a..0c25038 100644 --- a/arch/m68k/kernel/entry.S +++ b/arch/m68k/kernel/entry.S @@ -147,6 +147,15 @@ ENTRY(ret_from_fork) addql #4,%sp jra ret_from_exception + | A kernel thread will jump here directly from resume, + | with the stack containing the full register state + | (pt_regs and switch_stack). + | + | The argument will be in d7, and the kernel function + | to call will be in a3. + | + | If the kernel function returns, we want to return + | to user space - it has done a kernel_execve(). ENTRY(ret_from_kernel_thread) | a3 contains the kernel thread payload, d7 - its argument movel %d1,%sp@- @@ -154,6 +163,8 @@ ENTRY(ret_from_kernel_thread) movel %d7,(%sp) jsr %a3@ addql #4,%sp + RESTORE_SWITCH_STACK + addql #4,%sp jra ret_from_exception #if defined(CONFIG_COLDFIRE) || !defined(CONFIG_MMU) diff --git a/arch/m68k/kernel/process.c b/arch/m68k/kernel/process.c index 7dd0eea..f9598e0 100644 --- a/arch/m68k/kernel/process.c +++ b/arch/m68k/kernel/process.c @@ -192,12 +192,17 @@ int copy_thread(unsigned long clone_flags, unsigned long usp, unsigned long arg, if (unlikely(p->flags & (PF_KTHREAD | PF_IO_WORKER))) { /* kernel thread */ - memset(frame, 0, sizeof(struct fork_frame)); + struct switch_stack *kstp = &frame->sw - 1; + + /* kernel thread - a kernel-side switch-stack and the full user fork_frame */ + memset(kstp, 0, sizeof(struct switch_stack) + sizeof(struct fork_frame)); + frame->regs.sr = PS_S; - frame->sw.a3 = usp; /* function */ - frame->sw.d7 = arg; - frame->sw.retpc = (unsigned long)ret_from_kernel_thread; + kstp->a3 = usp; /* function */ + kstp->d7 = arg; + kstp->retpc = (unsigned long)ret_from_kernel_thread; p->thread.usp = 0; + p->thread.ksp = (unsigned long)kstp; return 0; } memcpy(frame, container_of(current_pt_regs(), struct fork_frame, regs), -- 2.7.4