[PATCH v3 2/3] m68k: correctly handle IO worker stack frame set-up

Michael Schmitz
2021-06-20T08:14:43Z

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@xmission.com>
CC: Linus Torvalds <torvalds@linux-foundation.org>
CC: Andreas Schwab <schwab@linux-m68k.org>
Signed-off-by: Michael Schmitz <schmitzmic@gmail.com>
---
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