Skip to content

Commit 194e8a4

Browse files
Al Virogregkh
authored andcommitted
m68k: Handle arrivals of multiple signals correctly
[ Upstream commit 4bb0bd8 ] When we have several pending signals, have entered with the kernel with large exception frame *and* have already built at least one sigframe, regs->stkadj is going to be non-zero and regs->format/sr/pc are going to be junk - the real values are in shifted exception stack frame we'd built when putting together the first sigframe. If that happens, subsequent sigframes are going to be garbage. Not hard to fix - just need to find the "adjusted" frame first and look for format/vector/sr/pc in it. Signed-off-by: Al Viro <viro@zeniv.linux.org.uk> Tested-by: Michael Schmitz <schmitzmic@gmail.com> Reviewed-by: Michael Schmitz <schmitzmic@gmail.com> Tested-by: Finn Thain <fthain@linux-m68k.org> Link: https://lore.kernel.org/r/YP2dBIAPTaVvHiZ6@zeniv-ca.linux.org.uk Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org> Signed-off-by: Sasha Levin <sashal@kernel.org>
1 parent 977aee5 commit 194e8a4

1 file changed

Lines changed: 42 additions & 46 deletions

File tree

arch/m68k/kernel/signal.c

Lines changed: 42 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -447,7 +447,7 @@ static inline void save_fpu_state(struct sigcontext *sc, struct pt_regs *regs)
447447

448448
if (CPU_IS_060 ? sc->sc_fpstate[2] : sc->sc_fpstate[0]) {
449449
fpu_version = sc->sc_fpstate[0];
450-
if (CPU_IS_020_OR_030 &&
450+
if (CPU_IS_020_OR_030 && !regs->stkadj &&
451451
regs->vector >= (VEC_FPBRUC * 4) &&
452452
regs->vector <= (VEC_FPNAN * 4)) {
453453
/* Clear pending exception in 68882 idle frame */
@@ -510,7 +510,7 @@ static inline int rt_save_fpu_state(struct ucontext __user *uc, struct pt_regs *
510510
if (!(CPU_IS_060 || CPU_IS_COLDFIRE))
511511
context_size = fpstate[1];
512512
fpu_version = fpstate[0];
513-
if (CPU_IS_020_OR_030 &&
513+
if (CPU_IS_020_OR_030 && !regs->stkadj &&
514514
regs->vector >= (VEC_FPBRUC * 4) &&
515515
regs->vector <= (VEC_FPNAN * 4)) {
516516
/* Clear pending exception in 68882 idle frame */
@@ -828,25 +828,32 @@ asmlinkage int do_rt_sigreturn(struct pt_regs *regs, struct switch_stack *sw)
828828
return 0;
829829
}
830830

831+
static inline struct pt_regs *rte_regs(struct pt_regs *regs)
832+
{
833+
return (void *)regs + regs->stkadj;
834+
}
835+
831836
static void setup_sigcontext(struct sigcontext *sc, struct pt_regs *regs,
832837
unsigned long mask)
833838
{
839+
struct pt_regs *tregs = rte_regs(regs);
834840
sc->sc_mask = mask;
835841
sc->sc_usp = rdusp();
836842
sc->sc_d0 = regs->d0;
837843
sc->sc_d1 = regs->d1;
838844
sc->sc_a0 = regs->a0;
839845
sc->sc_a1 = regs->a1;
840-
sc->sc_sr = regs->sr;
841-
sc->sc_pc = regs->pc;
842-
sc->sc_formatvec = regs->format << 12 | regs->vector;
846+
sc->sc_sr = tregs->sr;
847+
sc->sc_pc = tregs->pc;
848+
sc->sc_formatvec = tregs->format << 12 | tregs->vector;
843849
save_a5_state(sc, regs);
844850
save_fpu_state(sc, regs);
845851
}
846852

847853
static inline int rt_setup_ucontext(struct ucontext __user *uc, struct pt_regs *regs)
848854
{
849855
struct switch_stack *sw = (struct switch_stack *)regs - 1;
856+
struct pt_regs *tregs = rte_regs(regs);
850857
greg_t __user *gregs = uc->uc_mcontext.gregs;
851858
int err = 0;
852859

@@ -867,9 +874,9 @@ static inline int rt_setup_ucontext(struct ucontext __user *uc, struct pt_regs *
867874
err |= __put_user(sw->a5, &gregs[13]);
868875
err |= __put_user(sw->a6, &gregs[14]);
869876
err |= __put_user(rdusp(), &gregs[15]);
870-
err |= __put_user(regs->pc, &gregs[16]);
871-
err |= __put_user(regs->sr, &gregs[17]);
872-
err |= __put_user((regs->format << 12) | regs->vector, &uc->uc_formatvec);
877+
err |= __put_user(tregs->pc, &gregs[16]);
878+
err |= __put_user(tregs->sr, &gregs[17]);
879+
err |= __put_user((tregs->format << 12) | tregs->vector, &uc->uc_formatvec);
873880
err |= rt_save_fpu_state(uc, regs);
874881
return err;
875882
}
@@ -886,13 +893,14 @@ static int setup_frame(struct ksignal *ksig, sigset_t *set,
886893
struct pt_regs *regs)
887894
{
888895
struct sigframe __user *frame;
889-
int fsize = frame_extra_sizes(regs->format);
896+
struct pt_regs *tregs = rte_regs(regs);
897+
int fsize = frame_extra_sizes(tregs->format);
890898
struct sigcontext context;
891899
int err = 0, sig = ksig->sig;
892900

893901
if (fsize < 0) {
894902
pr_debug("setup_frame: Unknown frame format %#x\n",
895-
regs->format);
903+
tregs->format);
896904
return -EFAULT;
897905
}
898906

@@ -903,7 +911,7 @@ static int setup_frame(struct ksignal *ksig, sigset_t *set,
903911

904912
err |= __put_user(sig, &frame->sig);
905913

906-
err |= __put_user(regs->vector, &frame->code);
914+
err |= __put_user(tregs->vector, &frame->code);
907915
err |= __put_user(&frame->sc, &frame->psc);
908916

909917
if (_NSIG_WORDS > 1)
@@ -929,42 +937,37 @@ static int setup_frame(struct ksignal *ksig, sigset_t *set,
929937

930938
push_cache ((unsigned long) &frame->retcode);
931939

932-
/*
933-
* Set up registers for signal handler. All the state we are about
934-
* to destroy is successfully copied to sigframe.
935-
*/
936-
wrusp ((unsigned long) frame);
937-
regs->pc = (unsigned long) ksig->ka.sa.sa_handler;
938-
adjustformat(regs);
939-
940940
/*
941941
* This is subtle; if we build more than one sigframe, all but the
942942
* first one will see frame format 0 and have fsize == 0, so we won't
943943
* screw stkadj.
944944
*/
945-
if (fsize)
945+
if (fsize) {
946946
regs->stkadj = fsize;
947-
948-
/* Prepare to skip over the extra stuff in the exception frame. */
949-
if (regs->stkadj) {
950-
struct pt_regs *tregs =
951-
(struct pt_regs *)((ulong)regs + regs->stkadj);
947+
tregs = rte_regs(regs);
952948
pr_debug("Performing stackadjust=%04lx\n", regs->stkadj);
953-
/* This must be copied with decreasing addresses to
954-
handle overlaps. */
955949
tregs->vector = 0;
956950
tregs->format = 0;
957-
tregs->pc = regs->pc;
958951
tregs->sr = regs->sr;
959952
}
953+
954+
/*
955+
* Set up registers for signal handler. All the state we are about
956+
* to destroy is successfully copied to sigframe.
957+
*/
958+
wrusp ((unsigned long) frame);
959+
tregs->pc = (unsigned long) ksig->ka.sa.sa_handler;
960+
adjustformat(regs);
961+
960962
return 0;
961963
}
962964

963965
static int setup_rt_frame(struct ksignal *ksig, sigset_t *set,
964966
struct pt_regs *regs)
965967
{
966968
struct rt_sigframe __user *frame;
967-
int fsize = frame_extra_sizes(regs->format);
969+
struct pt_regs *tregs = rte_regs(regs);
970+
int fsize = frame_extra_sizes(tregs->format);
968971
int err = 0, sig = ksig->sig;
969972

970973
if (fsize < 0) {
@@ -1014,34 +1017,27 @@ static int setup_rt_frame(struct ksignal *ksig, sigset_t *set,
10141017

10151018
push_cache ((unsigned long) &frame->retcode);
10161019

1017-
/*
1018-
* Set up registers for signal handler. All the state we are about
1019-
* to destroy is successfully copied to sigframe.
1020-
*/
1021-
wrusp ((unsigned long) frame);
1022-
regs->pc = (unsigned long) ksig->ka.sa.sa_handler;
1023-
adjustformat(regs);
1024-
10251020
/*
10261021
* This is subtle; if we build more than one sigframe, all but the
10271022
* first one will see frame format 0 and have fsize == 0, so we won't
10281023
* screw stkadj.
10291024
*/
1030-
if (fsize)
1025+
if (fsize) {
10311026
regs->stkadj = fsize;
1032-
1033-
/* Prepare to skip over the extra stuff in the exception frame. */
1034-
if (regs->stkadj) {
1035-
struct pt_regs *tregs =
1036-
(struct pt_regs *)((ulong)regs + regs->stkadj);
1027+
tregs = rte_regs(regs);
10371028
pr_debug("Performing stackadjust=%04lx\n", regs->stkadj);
1038-
/* This must be copied with decreasing addresses to
1039-
handle overlaps. */
10401029
tregs->vector = 0;
10411030
tregs->format = 0;
1042-
tregs->pc = regs->pc;
10431031
tregs->sr = regs->sr;
10441032
}
1033+
1034+
/*
1035+
* Set up registers for signal handler. All the state we are about
1036+
* to destroy is successfully copied to sigframe.
1037+
*/
1038+
wrusp ((unsigned long) frame);
1039+
tregs->pc = (unsigned long) ksig->ka.sa.sa_handler;
1040+
adjustformat(regs);
10451041
return 0;
10461042
}
10471043

0 commit comments

Comments
 (0)