]> git.ipfire.org Git - thirdparty/glibc.git/commitdiff
hurd: catch SIGSEGV on returning from signal handler
authorSamuel Thibault <samuel.thibault@ens-lyon.org>
Sun, 21 Sep 2025 21:45:40 +0000 (23:45 +0200)
committerSamuel Thibault <samuel.thibault@ens-lyon.org>
Sun, 21 Sep 2025 21:45:40 +0000 (23:45 +0200)
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
sysdeps/mach/hurd/x86_64/sigreturn.c

index dc57d6122c2bbcf72c8df8139cf8b016187b6bd0..5a77ebdf3197bfee73c20d3485921376ccbc286b 100644 (file)
@@ -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;
index 773c00f86d3923e83c0ba8e11f59b42cb99ca00e..d2494c368118ce930f8480364d3d0139cdede12a 100644 (file)
@@ -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;