Skip to content

Commit b845b57

Browse files
fthaingeertu
authored andcommitted
m68k: Move signal frame following exception on 68020/030
On 68030/020, an instruction such as, moveml %a2-%a3/%a5,%sp@- may cause a stack page fault during instruction execution (i.e. not at an instruction boundary) and produce a format 0xB exception frame. In this situation, the value of USP will be unreliable. If a signal is to be delivered following the exception, this USP value is used to calculate the location for a signal frame. This can result in a corrupted user stack. The corruption was detected in dash (actually in glibc) where it showed up as an intermittent "stack smashing detected" message and crash following signal delivery for SIGCHLD. It was hard to reproduce that failure because delivery of the signal raced with the page fault and because the kernel places an unpredictable gap of up to 7 bytes between the USP and the signal frame. A format 0xB exception frame can be produced by a bus error or an address error. The 68030 Users Manual says that address errors occur immediately upon detection during instruction prefetch. The instruction pipeline allows prefetch to overlap with other instructions, which means an address error can arise during the execution of a different instruction. So it seems likely that this patch may help in the address error case also. Reported-and-tested-by: Stan Johnson <[email protected]> Link: https://lore.kernel.org/all/CAMuHMdW3yD22_ApemzW_6me3adq6A458u1_F0v-1EYwK_62jPA@mail.gmail.com/ Cc: Michael Schmitz <[email protected]> Cc: Andreas Schwab <[email protected]> Cc: [email protected] Co-developed-by: Michael Schmitz <[email protected]> Signed-off-by: Michael Schmitz <[email protected]> Signed-off-by: Finn Thain <[email protected]> Reviewed-by: Geert Uytterhoeven <[email protected]> Link: https://lore.kernel.org/r/9e66262a754fcba50208aa424188896cc52a1dd1.1683365892.git.fthain@linux-m68k.org Signed-off-by: Geert Uytterhoeven <[email protected]>
1 parent ac9a786 commit b845b57

File tree

1 file changed

+10
-4
lines changed

1 file changed

+10
-4
lines changed

arch/m68k/kernel/signal.c

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -858,11 +858,17 @@ static inline int rt_setup_ucontext(struct ucontext __user *uc, struct pt_regs *
858858
}
859859

860860
static inline void __user *
861-
get_sigframe(struct ksignal *ksig, size_t frame_size)
861+
get_sigframe(struct ksignal *ksig, struct pt_regs *tregs, size_t frame_size)
862862
{
863863
unsigned long usp = sigsp(rdusp(), ksig);
864+
unsigned long gap = 0;
864865

865-
return (void __user *)((usp - frame_size) & -8UL);
866+
if (CPU_IS_020_OR_030 && tregs->format == 0xb) {
867+
/* USP is unreliable so use worst-case value */
868+
gap = 256;
869+
}
870+
871+
return (void __user *)((usp - gap - frame_size) & -8UL);
866872
}
867873

868874
static int setup_frame(struct ksignal *ksig, sigset_t *set,
@@ -880,7 +886,7 @@ static int setup_frame(struct ksignal *ksig, sigset_t *set,
880886
return -EFAULT;
881887
}
882888

883-
frame = get_sigframe(ksig, sizeof(*frame) + fsize);
889+
frame = get_sigframe(ksig, tregs, sizeof(*frame) + fsize);
884890

885891
if (fsize)
886892
err |= copy_to_user (frame + 1, regs + 1, fsize);
@@ -952,7 +958,7 @@ static int setup_rt_frame(struct ksignal *ksig, sigset_t *set,
952958
return -EFAULT;
953959
}
954960

955-
frame = get_sigframe(ksig, sizeof(*frame));
961+
frame = get_sigframe(ksig, tregs, sizeof(*frame));
956962

957963
if (fsize)
958964
err |= copy_to_user (&frame->uc.uc_extra, regs + 1, fsize);

0 commit comments

Comments
 (0)