[PATCH RFC 1/2] m68k: Don't deliver signals except at instruction boundary

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Andreas Schwab <schwab@xxxxxxxxxxxxxx>

Signal delivery should only happen at insn boundaries, but due to the
way the 030 handles return from bus error exceptions (the insn is resumed,
not restarted like on the 040/060) the kernel may do it in the middle of
the faulting insn.

For example, a page fault can happen during execution of
        moveml %a2-%a3/%a5,%sp@-
This then produces a format 0xB exception frame containing an unreliable
USP value. That value gets used to calculate the location for a signal
frame and the end result is a corrupted the user stack.

This stack corruption was observed in dash (actually in glibc) where it
showed up as an intermittent "stack smashing detected" failure following
SIGCHLD signal delivery.

The failure was hard to reproduce because delivery of the signal races
with the page fault and because the kernel places an unpredictable gap
of up to 7 bytes between the USP and the signal frame, which is often
sufficient to prevent stack corruption.

Reported-and-tested-by: Stan Johnson <userm57@xxxxxxxxx>
Link: https://lore.kernel.org/all/CAMuHMdW3yD22_ApemzW_6me3adq6A458u1_F0v-1EYwK_62jPA@xxxxxxxxxxxxxx/
Cc: Michael Schmitz <schmitzmic@xxxxxxxxx>
Cc: Andreas Schwab <schwab@xxxxxxxxxxxxxx>
Signed-off-by: Finn Thain <fthain@xxxxxxxxxxxxxx>
---
This is the same patch that Andreas sent, excepting a minor change to the
commentary and a 'fallthrough' statement.
Andreas, as the author, this will need your signed-off-by.
---
 arch/m68k/kernel/entry.S |  6 +++++-
 arch/m68k/kernel/traps.c | 10 ++++++++--
 2 files changed, 13 insertions(+), 3 deletions(-)

diff --git a/arch/m68k/kernel/entry.S b/arch/m68k/kernel/entry.S
index 4dd2fd7acba9..77b558dad14b 100644
--- a/arch/m68k/kernel/entry.S
+++ b/arch/m68k/kernel/entry.S
@@ -117,7 +117,11 @@ ENTRY(buserr)
 	movel	%sp,%sp@-		| stack frame pointer argument
 	jbsr	buserr_c
 	addql	#4,%sp
-	jra	ret_from_exception
+	| deliver no signals if the fault occurred with an insn in progress
+	| (on the 020/030)
+	tstl	%d0
+	jeq	ret_from_exception
+	RESTORE_ALL
 
 ENTRY(trap)
 	SAVE_ALL_INT
diff --git a/arch/m68k/kernel/traps.c b/arch/m68k/kernel/traps.c
index a700807c9b6d..f535054d1e2a 100644
--- a/arch/m68k/kernel/traps.c
+++ b/arch/m68k/kernel/traps.c
@@ -751,8 +751,10 @@ static inline void access_errorcf(unsigned int fs, struct frame *fp)
 }
 #endif /* CONFIG_COLDFIRE CONFIG_MMU */
 
-asmlinkage void buserr_c(struct frame *fp)
+asmlinkage int buserr_c(struct frame *fp)
 {
+	int not_insn_boundary = 0;
+
 	/* Only set esp0 if coming from user mode */
 	if (user_mode(&fp->ptregs))
 		current->thread.esp0 = (unsigned long) fp;
@@ -793,8 +795,10 @@ asmlinkage void buserr_c(struct frame *fp)
 	  break;
 #endif
 #if defined (CPU_M68020_OR_M68030)
-	case 0xa:
 	case 0xb:
+	  not_insn_boundary = 1;
+	  fallthrough;
+	case 0xa:
 	  bus_error030 (fp);
 	  break;
 #endif
@@ -803,6 +807,8 @@ asmlinkage void buserr_c(struct frame *fp)
 	  pr_debug("Unknown SIGSEGV - 4\n");
 	  force_sig(SIGSEGV);
 	}
+
+	return not_insn_boundary;
 }
 
 
-- 
2.37.5




[Index of Archives]     [Video for Linux]     [Yosemite News]     [Linux S/390]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux