linux-arch.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Michael Schmitz <schmitzmic@gmail.com>
To: geert@linux-m68k.org, linux-arch@vger.kernel.org,
	linux-m68k@lists.linux-m68k.org
Cc: ebiederm@xmission.com, torvalds@linux-foundation.org,
	schwab@linux-m68k.org, Michael Schmitz <schmitzmic@gmail.com>
Subject: [PATCH v4 3/3] m68k: track syscalls being traced with shallow user context stack
Date: Wed, 23 Jun 2021 12:21:36 +1200	[thread overview]
Message-ID: <1624407696-20180-4-git-send-email-schmitzmic@gmail.com> (raw)
In-Reply-To: <1624407696-20180-1-git-send-email-schmitzmic@gmail.com>

Add 'status' field to thread_info struct to hold syscall trace
status info.

Set flag bit in thread_info->status at syscall trace entry, clear
flag bit on trace exit.

Set another flag bit on entering syscall where the full stack
frame has been saved. These flags can be checked whenever a
syscall calls ptrace_stop().

Check flag bits in get_reg()/put_reg() and prevent access to
registers that are saved on the switch stack, in case the
syscall did not actually save these registers on the switch
stack.

Tested on ARAnyM only - boots and survives running strace on a
binary, nothing fancy.

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>

--

Changes from v3:

- complete flag bit handling for all syscalls that use a m68k
  wrapper
- add flag checking code to get_reg()/put_reg() in m68k ptrace.c
---
 arch/m68k/include/asm/entry.h       | 10 +++++++
 arch/m68k/include/asm/thread_info.h |  1 +
 arch/m68k/kernel/asm-offsets.c      |  1 +
 arch/m68k/kernel/entry.S            | 54 +++++++++++++++++++++++++++++++++++++
 arch/m68k/kernel/ptrace.c           | 44 +++++++++++++++++++++++++-----
 5 files changed, 104 insertions(+), 6 deletions(-)

diff --git a/arch/m68k/include/asm/entry.h b/arch/m68k/include/asm/entry.h
index 9b52b06..37ba65b 100644
--- a/arch/m68k/include/asm/entry.h
+++ b/arch/m68k/include/asm/entry.h
@@ -41,6 +41,16 @@
 #define ALLOWINT	(~0x700)
 #endif /* machine compilation types */
 
+#define TIS_TRACING		0
+#define TIS_ALLREGS_SAVED	1
+#define _TIS_TRACING		(1<<TIS_TRACING)
+#define _TIS_ALLREGS_SAVED	(1<<TIS_ALLREGS_SAVED)
+
+#define TIS_TRACE_ON		_TIS_TRACING
+#define TIS_TRACE_OFF		(~(_TIS_TRACING))
+#define TIS_SWITCH_STACK	_TIS_ALLREGS_SAVED
+#define TIS_NO_SWITCH_STACK	(~(_TIS_ALLREGS_SAVED))
+
 #ifdef __ASSEMBLY__
 /*
  * This defines the normal kernel pt-regs layout.
diff --git a/arch/m68k/include/asm/thread_info.h b/arch/m68k/include/asm/thread_info.h
index 15a7570..a88b48b 100644
--- a/arch/m68k/include/asm/thread_info.h
+++ b/arch/m68k/include/asm/thread_info.h
@@ -29,6 +29,7 @@ struct thread_info {
 	unsigned long		flags;
 	mm_segment_t		addr_limit;	/* thread address space */
 	int			preempt_count;	/* 0 => preemptable, <0 => BUG */
+	unsigned int		status;		/* thread-synchronous flags */
 	__u32			cpu;		/* should always be 0 on m68k */
 	unsigned long		tp_value;	/* thread pointer */
 };
diff --git a/arch/m68k/kernel/asm-offsets.c b/arch/m68k/kernel/asm-offsets.c
index ccea355..ac1ec8f 100644
--- a/arch/m68k/kernel/asm-offsets.c
+++ b/arch/m68k/kernel/asm-offsets.c
@@ -41,6 +41,7 @@ int main(void)
 	/* offsets into the thread_info struct */
 	DEFINE(TINFO_PREEMPT, offsetof(struct thread_info, preempt_count));
 	DEFINE(TINFO_FLAGS, offsetof(struct thread_info, flags));
+	DEFINE(TINFO_STATUS, offsetof(struct thread_info, status));
 
 	/* offsets into the pt_regs */
 	DEFINE(PT_OFF_D0, offsetof(struct pt_regs, d0));
diff --git a/arch/m68k/kernel/entry.S b/arch/m68k/kernel/entry.S
index 0c25038..4cc24d5 100644
--- a/arch/m68k/kernel/entry.S
+++ b/arch/m68k/kernel/entry.S
@@ -51,75 +51,115 @@
 
 .text
 ENTRY(__sys_fork)
+	movel	%curptr@(TASK_STACK),%a1
+	orb	#TIS_SWITCH_STACK, %a1@(TINFO_STATUS+3)
 	SAVE_SWITCH_STACK
 	jbsr	sys_fork
 	lea     %sp@(24),%sp
+	movel	%curptr@(TASK_STACK),%a1
+	andb	#TIS_NO_SWITCH_STACK, %a1@(TINFO_STATUS+3)
 	rts
 
 ENTRY(__sys_clone)
+	movel	%curptr@(TASK_STACK),%a1
+	orb	#TIS_SWITCH_STACK, %a1@(TINFO_STATUS+3)
 	SAVE_SWITCH_STACK
 	pea	%sp@(SWITCH_STACK_SIZE)
 	jbsr	m68k_clone
 	lea     %sp@(28),%sp
+	movel	%curptr@(TASK_STACK),%a1
+	andb	#TIS_NO_SWITCH_STACK, %a1@(TINFO_STATUS+3)
 	rts
 
 ENTRY(__sys_vfork)
+	movel	%curptr@(TASK_STACK),%a1
+	orb	#TIS_SWITCH_STACK, %a1@(TINFO_STATUS+3)
 	SAVE_SWITCH_STACK
 	jbsr	sys_vfork
 	lea     %sp@(24),%sp
+	movel	%curptr@(TASK_STACK),%a1
+	andb	#TIS_NO_SWITCH_STACK, %a1@(TINFO_STATUS+3)
 	rts
 
 ENTRY(__sys_clone3)
+	movel	%curptr@(TASK_STACK),%a1
+	orb	#TIS_SWITCH_STACK, %a1@(TINFO_STATUS+3)
 	SAVE_SWITCH_STACK
 	pea	%sp@(SWITCH_STACK_SIZE)
 	jbsr	m68k_clone3
 	lea	%sp@(28),%sp
+	movel	%curptr@(TASK_STACK),%a1
+	andb	#TIS_NO_SWITCH_STACK, %a1@(TINFO_STATUS+3)
 	rts
 
 ENTRY(__sys_exit)
+	movel	%curptr@(TASK_STACK),%a1
+	orb	#TIS_SWITCH_STACK, %a1@(TINFO_STATUS+3)
 	SAVE_SWITCH_STACK
 	pea	%sp@(SWITCH_STACK_SIZE)
 	jbsr	m68k_exit
 	lea	%sp@(28),%sp
+	movel	%curptr@(TASK_STACK),%a1
+	andb	#TIS_NO_SWITCH_STACK, %a1@(TINFO_STATUS+3)
 	rts
 
 ENTRY(__sys_exit_group)
+	movel	%curptr@(TASK_STACK),%a1
+	orb	#TIS_SWITCH_STACK, %a1@(TINFO_STATUS+3)
 	SAVE_SWITCH_STACK
 	pea	%sp@(SWITCH_STACK_SIZE)
 	jbsr	m68k_exit_group
 	lea	%sp@(28),%sp
+	movel	%curptr@(TASK_STACK),%a1
+	andb	#TIS_NO_SWITCH_STACK, %a1@(TINFO_STATUS+3)
 	rts
 
 ENTRY(__sys_execve)
+	movel	%curptr@(TASK_STACK),%a1
+	orb	#TIS_SWITCH_STACK, %a1@(TINFO_STATUS+3)
 	SAVE_SWITCH_STACK
 	pea	%sp@(SWITCH_STACK_SIZE)
 	jbsr	m68k_execve
 	lea	%sp@(28),%sp
+	movel	%curptr@(TASK_STACK),%a1
+	andb	#TIS_NO_SWITCH_STACK, %a1@(TINFO_STATUS+3)
 	rts
 
 ENTRY(__sys_execveat)
+	movel	%curptr@(TASK_STACK),%a1
+	orb	#TIS_SWITCH_STACK, %a1@(TINFO_STATUS+3)
 	SAVE_SWITCH_STACK
 	pea	%sp@(SWITCH_STACK_SIZE)
 	jbsr	m68k_execveat
 	lea	%sp@(28),%sp
+	movel	%curptr@(TASK_STACK),%a1
+	andb	#TIS_NO_SWITCH_STACK, %a1@(TINFO_STATUS+3)
 	rts
 
 ENTRY(sys_sigreturn)
+	movel	%curptr@(TASK_STACK),%a1
+	orb	#TIS_SWITCH_STACK, %a1@(TINFO_STATUS+3)
 	SAVE_SWITCH_STACK
 	movel	%sp,%sp@-		  | switch_stack pointer
 	pea	%sp@(SWITCH_STACK_SIZE+4) | pt_regs pointer
 	jbsr	do_sigreturn
 	addql	#8,%sp
 	RESTORE_SWITCH_STACK
+	movel	%curptr@(TASK_STACK),%a1
+	andb	#TIS_NO_SWITCH_STACK, %a1@(TINFO_STATUS+3)
 	rts
 
 ENTRY(sys_rt_sigreturn)
+	movel	%curptr@(TASK_STACK),%a1
+	orb	#TIS_SWITCH_STACK, %a1@(TINFO_STATUS+3)
 	SAVE_SWITCH_STACK
 	movel	%sp,%sp@-		  | switch_stack pointer
 	pea	%sp@(SWITCH_STACK_SIZE+4) | pt_regs pointer
 	jbsr	do_rt_sigreturn
 	addql	#8,%sp
 	RESTORE_SWITCH_STACK
+	movel	%curptr@(TASK_STACK),%a1
+	andb	#TIS_NO_SWITCH_STACK, %a1@(TINFO_STATUS+3)
 	rts
 
 ENTRY(buserr)
@@ -200,25 +240,33 @@ ENTRY(ret_from_user_rt_signal)
 #else
 
 do_trace_entry:
+	orb	#TIS_TRACE_ON, %a1@(TINFO_STATUS+3)
 	movel	#-ENOSYS,%sp@(PT_OFF_D0)| needed for strace
 	subql	#4,%sp
+	orb	#TIS_SWITCH_STACK, %a1@(TINFO_STATUS+3)
 	SAVE_SWITCH_STACK
 	jbsr	syscall_trace
 	RESTORE_SWITCH_STACK
+	andb	#TIS_NO_SWITCH_STACK, %a1@(TINFO_STATUS+3)
 	addql	#4,%sp
 	movel	%sp@(PT_OFF_ORIG_D0),%d0
 	cmpl	#NR_syscalls,%d0
 	jcs	syscall
 badsys:
+	andb	#TIS_TRACE_OFF, %a1@(TINFO_STATUS+3)
 	movel	#-ENOSYS,%sp@(PT_OFF_D0)
 	jra	ret_from_syscall
 
 do_trace_exit:
 	subql	#4,%sp
+	orb	#TIS_SWITCH_STACK, %a1@(TINFO_STATUS+3)
 	SAVE_SWITCH_STACK
 	jbsr	syscall_trace
 	RESTORE_SWITCH_STACK
+	andb	#TIS_NO_SWITCH_STACK, %a1@(TINFO_STATUS+3)
 	addql	#4,%sp
+	movel	%curptr@(TASK_STACK),%a1
+	andb	#TIS_TRACE_OFF, %a1@(TINFO_STATUS+3)
 	jra	.Lret_from_exception
 
 ENTRY(ret_from_signal)
@@ -227,6 +275,8 @@ ENTRY(ret_from_signal)
 	jge	1f
 	jbsr	syscall_trace
 1:	RESTORE_SWITCH_STACK
+	movel	%curptr@(TASK_STACK),%a1
+	andb	#TIS_TRACE_OFF, %a1@(TINFO_STATUS+3)
 	addql	#4,%sp
 /* on 68040 complete pending writebacks if any */
 #ifdef CONFIG_M68040
@@ -303,11 +353,15 @@ exit_work:
 do_signal_return:
 	|andw	#ALLOWINT,%sr
 	subql	#4,%sp			| dummy return address
+	movel	%curptr@(TASK_STACK),%a1
+	orb	#TIS_SWITCH_STACK, %a1@(TINFO_STATUS+3)
 	SAVE_SWITCH_STACK
 	pea	%sp@(SWITCH_STACK_SIZE)
 	bsrl	do_notify_resume
 	addql	#4,%sp
 	RESTORE_SWITCH_STACK
+	movel	%curptr@(TASK_STACK),%a1
+	andb	#TIS_NO_SWITCH_STACK, %a1@(TINFO_STATUS+3)
 	addql	#4,%sp
 	jbra	resume_userspace
 
diff --git a/arch/m68k/kernel/ptrace.c b/arch/m68k/kernel/ptrace.c
index 94b3b27..ae4ef61 100644
--- a/arch/m68k/kernel/ptrace.c
+++ b/arch/m68k/kernel/ptrace.c
@@ -68,6 +68,12 @@ static const int regoff[] = {
 	[18]	= PT_REG(pc),
 };
 
+static inline int test_ti_thread_status(struct thread_info *ti, int flag)
+{
+	return test_bit(flag, (unsigned long *)&ti->status);
+}
+
+
 /*
  * Get contents of register REGNO in task TASK.
  */
@@ -77,9 +83,22 @@ static inline long get_reg(struct task_struct *task, int regno)
 
 	if (regno == PT_USP)
 		addr = &task->thread.usp;
-	else if (regno < ARRAY_SIZE(regoff))
-		addr = (unsigned long *)(task->thread.esp0 + regoff[regno]);
-	else
+	else if (regno < ARRAY_SIZE(regoff)) {
+		int off  =regoff[regno];
+
+		if (WARN_ON_ONCE((off < PT_REG(d1)) &&
+			test_ti_thread_status(task_thread_info(task), TIS_TRACING) &&
+			!test_ti_thread_status(task_thread_info(task),
+					     TIS_ALLREGS_SAVED))) {
+			unsigned long *addr_d0;
+
+			addr_d0 = (unsigned long *)(task->thread.esp0 + regoff[16]);
+			pr_err("register read from incomplete stack, regno %d offs %d orig_d0 %lx\n",
+				regno, off, *addr_d0);
+			return 0;
+		}
+		addr = (unsigned long *)(task->thread.esp0 + off);
+	} else
 		return 0;
 	/* Need to take stkadj into account. */
 	if (regno == PT_SR || regno == PT_PC) {
@@ -102,9 +121,22 @@ static inline int put_reg(struct task_struct *task, int regno,
 
 	if (regno == PT_USP)
 		addr = &task->thread.usp;
-	else if (regno < ARRAY_SIZE(regoff))
-		addr = (unsigned long *)(task->thread.esp0 + regoff[regno]);
-	else
+	else if (regno < ARRAY_SIZE(regoff)) {
+		int off = regoff[regno];
+
+		if (WARN_ON_ONCE((off < PT_REG(d1)) &&
+			test_ti_thread_status(task_thread_info(task), TIS_TRACING) &&
+			!test_ti_thread_status(task_thread_info(task),
+					     TIS_ALLREGS_SAVED))) {
+			unsigned long *addr_d0;
+
+			addr_d0 = (unsigned long *)(task->thread.esp0 + regoff[16]);
+			pr_err("register write to incomplete stack, regno %d offs %d orig_d0 %lx\n",
+				regno, off, *addr_d0);
+			return -1;
+		}
+		addr = (unsigned long *)(task->thread.esp0 + off);
+	} else
 		return -1;
 	/* Need to take stkadj into account. */
 	if (regno == PT_SR || regno == PT_PC) {
-- 
2.7.4


  parent reply	other threads:[~2021-06-23  0:21 UTC|newest]

Thread overview: 37+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-06-23  0:21 [PATCH v4 0/3] m68k: Improved switch stack handling Michael Schmitz
2021-06-23  0:21 ` [PATCH v4 1/3] m68k: save extra registers on more syscall entry points Michael Schmitz
2021-06-23  0:21 ` [PATCH v4 2/3] m68k: correctly handle IO worker stack frame set-up Michael Schmitz
2021-06-23  0:21 ` Michael Schmitz [this message]
2021-07-25 10:05   ` [PATCH v4 3/3] m68k: track syscalls being traced with shallow user context stack Geert Uytterhoeven
2021-07-25 20:48     ` Michael Schmitz
2021-07-25 21:00       ` Linus Torvalds
2021-07-26 14:27         ` Greg Ungerer
2021-07-15 13:29 ` [PATCH v4 0/3] m68k: Improved switch stack handling Eric W. Biederman
2021-07-15 23:10   ` Michael Schmitz
2021-07-17  5:38     ` Michael Schmitz
2021-07-17 18:52       ` Eric W. Biederman
2021-07-17 20:09         ` Michael Schmitz
2021-07-17 23:04           ` Michael Schmitz
2021-07-18 10:47             ` Andreas Schwab
2021-07-18 19:47               ` Michael Schmitz
2021-07-18 20:59                 ` Brad Boyer
2021-07-19  3:15                   ` Michael Schmitz
2021-07-20 20:32             ` Eric W. Biederman
2021-07-20 22:16               ` Michael Schmitz
2021-07-22 14:49                 ` Eric W. Biederman
2021-07-23  4:23                   ` Michael Schmitz
2021-07-23 22:31                     ` Eric W. Biederman
2021-07-23 23:52                       ` Michael Schmitz
2021-07-24 12:05                         ` Andreas Schwab
2021-07-25  7:44                           ` Michael Schmitz
2021-07-25 10:12                             ` Brad Boyer
2021-07-26  2:00                               ` Michael Schmitz
2021-07-26 19:36                                 ` [RFC][PATCH] signal/m68k: Use force_sigsegv(SIGSEGV) in fpsp040_die Eric W. Biederman
2021-07-26 20:13                                   ` Andreas Schwab
2021-07-26 20:29                                     ` Eric W. Biederman
2021-07-26 21:25                                       ` Andreas Schwab
2021-07-26 20:29                                   ` Michael Schmitz
2021-07-26 21:08                                     ` [PATCH] " Eric W. Biederman
2021-08-25 15:56                                       ` Eric W. Biederman
2021-08-26 12:15                                       ` Geert Uytterhoeven
2021-07-25 11:53                             ` [PATCH v4 0/3] m68k: Improved switch stack handling Andreas Schwab

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1624407696-20180-4-git-send-email-schmitzmic@gmail.com \
    --to=schmitzmic@gmail.com \
    --cc=ebiederm@xmission.com \
    --cc=geert@linux-m68k.org \
    --cc=linux-arch@vger.kernel.org \
    --cc=linux-m68k@lists.linux-m68k.org \
    --cc=schwab@linux-m68k.org \
    --cc=torvalds@linux-foundation.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).