delorie.com/archives/browse.cgi   search  
Mail Archives: cygwin-developers/1999/09/07/03:58:08

Mailing-List: contact cygwin-developers-help AT sourceware DOT cygnus DOT com; run by ezmlm
List-Unsubscribe: <mailto:cygwin-developers-unsubscribe-archive-cygwin-developers=delorie DOT com AT sourceware DOT cygnus DOT com>
List-Subscribe: <mailto:cygwin-developers-subscribe AT sourceware DOT cygnus DOT com>
List-Archive: <http://sourceware.cygnus.com/ml/cygwin-developers/>
List-Post: <mailto:cygwin-developers AT sourceware DOT cygnus DOT com>
List-Help: <mailto:cygwin-developers-help AT sourceware DOT cygnus DOT com>,
<http://sourceware.cygnus.com/ml/#faqs>
Sender: cygwin-developers-owner AT sourceware DOT cygnus DOT com
Delivered-To: mailing list cygwin-developers AT sourceware DOT cygnus DOT com
Message-ID: <37D4C510.7C473183@1c.ru>
Date: Tue, 07 Sep 1999 11:56:00 +0400
From: Vadim Egorov <egorovv AT 1c DOT ru>
X-Mailer: Mozilla 4.61 [en] (WinNT; I)
X-Accept-Language: ru,en
MIME-Version: 1.0
To: "cygwin-developers AT sourceware DOT cygnus DOT com"
<cygwin-developers AT sourceware DOT cygnus DOT com>
Subject: setjmp/longjmp patch update
X-MDaemon-Deliver-To: cygwin-developers AT sourceware DOT cygnus DOT com
X-Return-Path: EgorovV AT 1c DOT ru

Hello,

Here is a path which fixes the problem with longjmp when it is called 
from signal handler.
setjmp is modified to store fs:0 (SEH handler) value at offset 44 of
jmp_buf. longjmp in turn checks this value and invokes seh_unwind if 
necessary. 
It handles win32 exceptions raised as signals such as SIGFPE and 
SIGSEGV and preserves SEH handler list in a consistent state.

This makes possible to use malicious SEH for good things.
In this patch I modified signal handler invocation code to call
signal handler guarded by a __try/__finally fashioned block.

It installs additional seh frame around the call which guarantees
that signal state will be restored even if handler doesn't return 
due to the longjmp call.

The patch follows.
Vadim



--- config/i386/setjmp.c	Fri Oct 23 11:23:57 1998
+++ config/i386/setjmp.c.1	Fri Sep 03 08:29:54 1999
@@ -40,4 +40,6 @@ asm("	.globl	_setjmp  		\n"
 "	movw	%ss, %ax		\n"
 "	movw	%ax, 42(%edi)		\n"
+"	movl	%fs:0, %eax		\n"
+"	movl	%eax, 44(%edi)		\n"
 "	popl	%edi			\n"
 "	movl	$0,%eax			\n"
--- config/i386/longjmp.c	Fri Oct 23 11:23:57 1998
+++ config/i386/longjmp.c.1	Fri Sep 03 08:48:20 1999
@@ -11,4 +11,5 @@ details. */
 #ifdef __i386__
 #if 1
+
 asm ("	.globl	_longjmp          \n"
 "_longjmp:                        \n"
@@ -16,4 +17,12 @@ asm ("	.globl	_longjmp          \n"
 "	movl	%esp,%ebp	  \n"
 "	movl	8(%ebp),%edi	  \n"
+"      movl 8(%ebp),%eax         \n"
+"      movl 44(%eax),%eax        \n"
+"      cmpl %fs:0,%eax           \n"
+"      je L1                     \n"
+"      pushl %eax                \n"
+"      call _seh_unwind          \n"
+"      add   $4, %esp            \n"
+"L1:                             \n"
 "	movl	12(%ebp),%eax	  \n"
 "	testl	%eax,%eax	  \n"
--- exceptions.cc	Sun Sep 05 07:55:59 1999
+++ exceptions.cc.1	Tue Sep 07 11:24:49 1999
@@ -25,4 +25,6 @@ static int handle_exceptions (EXCEPTION_
 static void sigreturn ();
 static void sigbegin ();
+
+static void sig_call_try(void (*handler)(int), int sig, sigset_t
oldmask);
 };
 
@@ -578,12 +580,11 @@ got_mutex:
   *(--sp) = orig.Ebx;
   *(--sp) = orig.Eax;
-  *(--sp) = (DWORD)1;
   *(--sp) = oldmask;
   *(--sp) = sig;
-  *(--sp) = (DWORD) sigreturn;
   *(--sp) = (DWORD) thissig.sa_handler;
+  *(--sp) = (DWORD) sigreturn;
 
   orig.Esp = (DWORD) sp;
-  orig.Eip = (DWORD) sigbegin;
+  orig.Eip = (DWORD) sig_call_try;
 
   SetThreadContext (myself->getthread2signal(), &orig); /* Restart the
thread */
@@ -813,8 +814,5 @@ asm ("
 	.text
 _sigreturn:
-	addl	$4,%esp
-	call	_set_process_mask AT 8
-	pushl	$0
-	call	_SetLastError AT 4
+	addl	$12,%esp
 	popl	%eax
 	popl	%ebx
@@ -826,3 +824,96 @@ _sigreturn:
 	ret
 ");
+}
+
+extern "C"
+{
+
+/* Light-weight _RtlUnwind API function emulator which 
+does Win32 SEH stack unwinding. Walks from currently 
+installed at fs:0 SEH frame down to given frame and 
+and calls them to do cleanup. */
+
+void 
+seh_unwind(exception_list * frame)
+{
+    EXCEPTION_RECORD ex_rec;
+    CONTEXT ctx;
+    exception_list* dispatched_frame;
+        
+    exception_list* p = _except_list;
+    if (p != frame)
+        debug_printf ("unwinding SEH frames down to %p", frame);
+    else
+        return ;
+
+    ex_rec.ExceptionCode = 0; 
+    ex_rec.ExceptionFlags = 2; 
+    ex_rec.ExceptionRecord = 0; 
+    ex_rec.ExceptionAddress = 0; 
+
+    GetThreadContext(GetCurrentThread(), &ctx); 
+    while (p != (exception_list*)(-1))
+    {
+        if (p == frame)
+        {
+            _except_list = p;
+            return;
+        }
+        else
+        {
+            p->handler(&ex_rec, p, &ctx, &dispatched_frame);
+            debug_printf ("calling SEH frame %p", p);
+            p = p->prev;
+        }
+    }
+    // if we get here something is wrong
+    debug_printf ("failed to find SEH frame %p", frame);
+}
+
+/* extended SEH frame registration*/
+struct exception_list_ex
+{
+  struct _exception_list frame;
+  sigset_t mask;  
+};
+
+/* SEH handler which does nothing except setting stored signal
+mask in a case of seh unwinding */
+static int 
+sig_call_finally (EXCEPTION_RECORD *rec, exception_list_ex * frame_ex, 
+                  CONTEXT *, void *)
+{
+  if (rec->ExceptionFlags == 2) //unwind
+  {
+    set_process_mask (frame_ex->mask, 1);
+    SetLastError(0);
+  }
+  return 0;
+}
+
+/* Performs signal handler invocation within SEH frame
+and restores old signal mask on successful return */
+static void 
+sig_call_try(_sig_func_ptr handler, int sig, sigset_t oldmask)
+{
+  sigbegin();
+
+  //seh frame setup
+  exception_list_ex frame_ex;
+  frame_ex.frame.prev = _except_list;
+  frame_ex.frame.handler = sig_call_finally;
+  frame_ex.mask = oldmask;
+  _except_list = &frame_ex.frame;
+
+  //try
+  handler(sig);
+
+  //restore original seh frame
+  _except_list = frame_ex.frame.prev;
+
+  //finally
+  set_process_mask (oldmask, 1);
+  SetLastError(0);
+}
+
 }


-- 
*********************************************
Vadim Egorov, 1C      *        ,1C
egorovv AT 1c DOT ru         *         egorovv AT 1c DOT ru
*********************************************

- Raw text -


  webmaster     delorie software   privacy  
  Copyright 2019   by DJ Delorie     Updated Jul 2019