Handling a pending signal calls _hurd_setup_sighandler() once again after the 
initial signal handling. In this case a pointer to the previous sigcontext is 
available to supply the interrupted thread's original basic state, fpu state 
and fpu XSTATE. The original XSTATE was not being preserved by the pending 
signal but instead overwritten with the active XSTATE. XSTATE register values 
modified by the signal handling code could therefore be wrongly propogated back 
to the interrupted user code.
---
 sysdeps/mach/hurd/x86/trampoline.c | 30 ++++++++++++++++++++++--------
 1 file changed, 22 insertions(+), 8 deletions(-)

diff --git a/sysdeps/mach/hurd/x86/trampoline.c 
b/sysdeps/mach/hurd/x86/trampoline.c
index d1c30fbb49..514bb9a503 100644
--- a/sysdeps/mach/hurd/x86/trampoline.c
+++ b/sysdeps/mach/hurd/x86/trampoline.c
@@ -283,15 +283,25 @@ _hurd_setup_sighandler (struct hurd_sigstate *ss, const 
struct sigaction *action
 #ifdef i386_XFLOAT_STATE
       if (xstate_size > 0)
         {
-          mach_msg_type_number_t got = (xstate_size / sizeof (int));
+         if (ss->context != NULL)
+           {
+             /* Copy the xstate preserved at the time of handling the first
+                signal rather than that currently in the FPU. */
+             memcpy(stackframe->xstate, ss->context->xstate, xstate_size);
+             ok = 1;
+           }
+         else
+           {
+             mach_msg_type_number_t got = (xstate_size / sizeof (int));
 
-          ok = (! __thread_get_state (ss->thread, i386_XFLOAT_STATE,
-                                      (thread_state_t) stackframe->xstate, 
&got)
-                && got == (xstate_size / sizeof (int)));
+             ok = (! __thread_get_state (ss->thread, i386_XFLOAT_STATE,
+                                         (thread_state_t) stackframe->xstate, 
&got)
+                   && got == (xstate_size / sizeof (int)));
 
-         if (ok && ((struct i386_xfloat_state*) 
stackframe->xstate)->fp_save_kind > 5)
-           /* We support up to XSAVES */
-           ok = 0;
+             if (ok && ((struct i386_xfloat_state*) 
stackframe->xstate)->fp_save_kind > 5)
+               /* We support up to XSAVES */
+               ok = 0;
+           }
 
           if (ok)
            {
@@ -305,7 +315,11 @@ _hurd_setup_sighandler (struct hurd_sigstate *ss, const 
struct sigaction *action
       if (!ok)
         {
           /* struct sigcontext is laid out so that starting at sc_fpkind mimics
-            a struct i386_float_state.  */
+            a struct i386_float_state. In the event that we are processing a
+           previous sigcontext (ss->context != NULL) 'state' correctly contains
+           the FPU state saved from the previous handler (see memcpy above)
+           rather than that currently in the FPU */
+
           _Static_assert (offsetof (struct sigcontext, sc_i386_float_state)
                          % __alignof__ (struct i386_float_state) == 0,
                          "sc_i386_float_state layout mismatch");
-- 
2.47.3


Reply via email to