This commit updates the behavior of signal handling under !MMU
environment. 1) the stack preparation for the signal handlers and
2) restoration of stack after rt_sigreturn(2) syscall.  Those are needed
as the stack usage on vfork(2) syscall is different.

It also adds the follow up routine for SIGSEGV as a signal delivery runs
in the same stack frame while we have to avoid endless SIGSEGV.

Signed-off-by: Hajime Tazaki <thehaj...@gmail.com>
---
 arch/um/os-Linux/signal.c | 16 +++++++++++++++-
 arch/x86/um/signal.c      | 37 ++++++++++++++++++++++++++++++++++++-
 2 files changed, 51 insertions(+), 2 deletions(-)

diff --git a/arch/um/os-Linux/signal.c b/arch/um/os-Linux/signal.c
index c0d1fb1fc0c4..de3ed8fc0268 100644
--- a/arch/um/os-Linux/signal.c
+++ b/arch/um/os-Linux/signal.c
@@ -55,7 +55,15 @@ static void sig_handler_common(int sig, struct siginfo *si, 
mcontext_t *mc)
        struct uml_pt_regs r;
        int save_errno = errno;
 
-       r.is_user = 0;
+#ifndef CONFIG_MMU
+       memset(&r, 0, sizeof(r));
+       /* mark is_user=1 when the IP is from userspace code. */
+       if (mc && (REGS_IP(mc->gregs) > uml_reserved
+                  && REGS_IP(mc->gregs) < high_physmem))
+               r.is_user = 1;
+       else
+#endif
+               r.is_user = 0;
        if (sig == SIGSEGV) {
                /* For segfaults, we want the data from the sigcontext. */
                get_regs_from_mc(&r, mc);
@@ -69,6 +77,12 @@ static void sig_handler_common(int sig, struct siginfo *si, 
mcontext_t *mc)
        (*sig_info[sig])(sig, si, &r);
 
        errno = save_errno;
+
+#ifndef CONFIG_MMU
+       /* force handle signals after rt_sigreturn() */
+       if (r.is_user && sig == SIGSEGV)
+               mc_set_regs_ip_relay(mc);
+#endif
 }
 
 /*
diff --git a/arch/x86/um/signal.c b/arch/x86/um/signal.c
index 75087e85b6fd..e1b3a87ddc5d 100644
--- a/arch/x86/um/signal.c
+++ b/arch/x86/um/signal.c
@@ -370,6 +370,13 @@ int setup_signal_stack_si(unsigned long stack_top, struct 
ksignal *ksig,
        frame = (struct rt_sigframe __user *)
                round_down(stack_top - sizeof(struct rt_sigframe), 16);
 
+#ifndef CONFIG_MMU
+       /*
+        * the sig_frame on !MMU needs be aligned for SSE as
+        * the frame is used as-is.
+        */
+       math_size = round_down(math_size, 16);
+#endif
        /* Add required space for math frame */
        frame = (struct rt_sigframe __user *)((unsigned long)frame - math_size);
 
@@ -417,6 +424,18 @@ int setup_signal_stack_si(unsigned long stack_top, struct 
ksignal *ksig,
                /* could use a vstub here */
                return err;
 
+#ifndef CONFIG_MMU
+       /*
+        * we need to push handler address at top of stack, as
+        * __kernel_vsyscall, called after this returns with ret with
+        * stack contents, thus push the handler here.
+        */
+       frame = (struct rt_sigframe __user *) ((unsigned long) frame -
+                                              sizeof(unsigned long));
+       err |= __put_user((unsigned long)ksig->ka.sa.sa_handler,
+                         (unsigned long *)frame);
+#endif
+
        if (err)
                return err;
 
@@ -442,9 +461,25 @@ SYSCALL_DEFINE0(rt_sigreturn)
        unsigned long sp = PT_REGS_SP(&current->thread.regs);
        struct rt_sigframe __user *frame =
                (struct rt_sigframe __user *)(sp - sizeof(long));
-       struct ucontext __user *uc = &frame->uc;
+       struct ucontext __user *uc;
        sigset_t set;
 
+#ifndef CONFIG_MMU
+       /**
+        * we enter here with:
+        *
+        * __restore_rt:
+        *     mov $15, %rax
+        *     call *%rax (translated from syscall)
+        *
+        * (code is from musl libc)
+        * so, stack needs to be popped of "call"ed address before
+        * looking at rt_sigframe.
+        */
+       frame = (struct rt_sigframe __user *)((unsigned long)frame + 
sizeof(long));
+#endif
+       uc = &frame->uc;
+
        if (copy_from_user(&set, &uc->uc_sigmask, sizeof(set)))
                goto segfault;
 
-- 
2.43.0


Reply via email to