On stack overflow typically, we may not actually have room on the stack to
trampoline back from the signal handler.  We have to detect this before
locking the ss, otherwise the signal thread will be stuck on taking the
ss lock while trying to post SIGSEGV.
---
 sysdeps/mach/hurd/i386/sigreturn.c   | 13 ++++++++++++-
 sysdeps/mach/hurd/x86_64/sigreturn.c | 12 +++++++++++-
 2 files changed, 23 insertions(+), 2 deletions(-)

diff --git a/sysdeps/mach/hurd/i386/sigreturn.c 
b/sysdeps/mach/hurd/i386/sigreturn.c
index dc57d6122c..5a77ebdf31 100644
--- a/sysdeps/mach/hurd/i386/sigreturn.c
+++ b/sysdeps/mach/hurd/i386/sigreturn.c
@@ -89,10 +89,21 @@ __sigreturn (struct sigcontext *scp)
 {
   struct hurd_sigstate *ss;
   struct hurd_userlink *link = (void *) &scp[1];
+  int *usp;
+
+  /* Stack usage while trampolining back:
+   * register dump, parameters, and rough estimation of usage in __sigreturn2
+   * before unlocking ss.  */
+  size_t tramp_usage = 18 * sizeof (uintptr_t) + 32;
 
   if (__glibc_unlikely (scp == NULL || (scp->sc_mask & _SIG_CANT_MASK)))
     return __hurd_fail (EINVAL);
 
+  usp = (int *) scp->sc_uesp;
+
+  /* If we are to segfault, do it now before locking the ss.  */
+  memset ((void*) usp - tramp_usage, 0, tramp_usage);
+
   ss = _hurd_self_sigstate ();
   _hurd_sigstate_lock (ss);
 
@@ -160,7 +171,7 @@ __sigreturn (struct sigcontext *scp)
        copy the registers onto the user's stack, switch there, pop and
        return.  */
 
-    int usp_arg, *usp = (int *) scp->sc_uesp;
+    int usp_arg;
 
     *--usp = scp->sc_eip;
     *--usp = scp->sc_efl;
diff --git a/sysdeps/mach/hurd/x86_64/sigreturn.c 
b/sysdeps/mach/hurd/x86_64/sigreturn.c
index 773c00f86d..d2494c3681 100644
--- a/sysdeps/mach/hurd/x86_64/sigreturn.c
+++ b/sysdeps/mach/hurd/x86_64/sigreturn.c
@@ -83,9 +83,20 @@ __sigreturn (struct sigcontext *scp)
   uintptr_t *usp;
   mach_port_t sc_reply_port;
 
+  /* Stack usage while trampolining back:
+   * register dump, 16B round-up, and rough estimation of usage in __sigreturn2
+   * before unlocking ss.  */
+  size_t tramp_usage = 17 * sizeof (uintptr_t) + 16 + 64;
+
   if (__glibc_unlikely (scp == NULL || (scp->sc_mask & _SIG_CANT_MASK)))
     return __hurd_fail (EINVAL);
 
+  /* Respect the redzone.  */
+  usp = (uintptr_t *) (scp->sc_ursp - 128);
+
+  /* If we are to segfault, do it now before locking the ss.  */
+  memset ((void*) usp - tramp_usage, 0, tramp_usage);
+
   ss = _hurd_self_sigstate ();
   _hurd_sigstate_lock (ss);
 
@@ -160,7 +171,6 @@ __sigreturn (struct sigcontext *scp)
      located at a larger address than the sigcontext.  */
 
   sc_reply_port = scp->sc_reply_port;
-  usp = (uintptr_t *) (scp->sc_ursp - 128);
 
   *--usp = scp->sc_rip;
   *--usp = scp->sc_rfl;
-- 
2.51.0


Reply via email to