Alexandre Julliard : ntdll: Also handle stack guard page faults in virtual_handle_fault().

Alexandre Julliard julliard at winehq.org
Wed Jul 15 16:44:45 CDT 2020


Module: wine
Branch: master
Commit: 9a9fb47e24d3daa57aa24bc5529e33b6271b92bc
URL:    https://source.winehq.org/git/wine.git/?a=commit;h=9a9fb47e24d3daa57aa24bc5529e33b6271b92bc

Author: Alexandre Julliard <julliard at winehq.org>
Date:   Wed Jul 15 10:29:50 2020 +0200

ntdll: Also handle stack guard page faults in virtual_handle_fault().

Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 dlls/ntdll/unix/signal_arm.c    | 19 ++++++-------------
 dlls/ntdll/unix/signal_arm64.c  | 19 ++++++-------------
 dlls/ntdll/unix/signal_i386.c   | 28 ++++++----------------------
 dlls/ntdll/unix/signal_x86_64.c | 26 ++++++--------------------
 dlls/ntdll/unix/virtual.c       | 11 ++++++++---
 5 files changed, 32 insertions(+), 71 deletions(-)

diff --git a/dlls/ntdll/unix/signal_arm.c b/dlls/ntdll/unix/signal_arm.c
index b74dbd32de..e7a259f632 100644
--- a/dlls/ntdll/unix/signal_arm.c
+++ b/dlls/ntdll/unix/signal_arm.c
@@ -585,18 +585,14 @@ static void segv_handler( int signal, siginfo_t *info, void *ucontext )
     /* check for page fault inside the thread stack */
     if (get_trap_code(signal, context) == TRAP_ARM_PAGEFLT)
     {
-        switch (virtual_handle_stack_fault( info->si_addr ))
-        {
-        case 1:  /* handled */
-            return;
-        case -1:  /* overflow */
-            rec = setup_exception( context, raise_segv_exception );
-            rec->ExceptionCode = EXCEPTION_STACK_OVERFLOW;
-            return;
-        }
+        DWORD err = (get_error_code(context) & 0x800) != 0;
+        NTSTATUS status = virtual_handle_fault( info->si_addr, err, (void *)SP_sig(context) );
+        if (!status) return;
+        rec = setup_exception( context, raise_segv_exception );
+        rec->ExceptionCode = status;
     }
+    else rec = setup_exception( context, raise_segv_exception );
 
-    rec = setup_exception( context, raise_segv_exception );
     if (rec->ExceptionCode == EXCEPTION_STACK_OVERFLOW) return;
 
     switch(get_trap_code(signal, context))
@@ -609,9 +605,6 @@ static void segv_handler( int signal, siginfo_t *info, void *ucontext )
         rec->NumberParameters = 2;
         rec->ExceptionInformation[0] = (get_error_code(context) & 0x800) != 0;
         rec->ExceptionInformation[1] = (ULONG_PTR)info->si_addr;
-        if (!(rec->ExceptionCode = virtual_handle_fault( (void *)rec->ExceptionInformation[1],
-                                                         rec->ExceptionInformation[0], NULL )))
-            return;
         break;
     case TRAP_ARM_ALIGNFLT:  /* Alignment check exception */
         rec->ExceptionCode = EXCEPTION_DATATYPE_MISALIGNMENT;
diff --git a/dlls/ntdll/unix/signal_arm64.c b/dlls/ntdll/unix/signal_arm64.c
index b402ecb93d..27185dbb17 100644
--- a/dlls/ntdll/unix/signal_arm64.c
+++ b/dlls/ntdll/unix/signal_arm64.c
@@ -619,18 +619,14 @@ static void segv_handler( int signal, siginfo_t *info, void *ucontext )
     /* check for page fault inside the thread stack */
     if (signal == SIGSEGV)
     {
-        switch (virtual_handle_stack_fault( info->si_addr ))
-        {
-        case 1:  /* handled */
-            return;
-        case -1:  /* overflow */
-            stack = setup_exception( context );
-            stack->rec.ExceptionCode = EXCEPTION_STACK_OVERFLOW;
-            goto done;
-        }
+        DWORD err = (get_fault_esr( context ) & 0x40) != 0;
+        NTSTATUS status = virtual_handle_fault( info->si_addr, err, (void *)SP_sig(context) );
+        if (!status) return;
+        stack = setup_exception( context );
+        stack->rec.ExceptionCode = status;
     }
+    else stack = setup_exception( context );
 
-    stack = setup_exception( context );
     if (stack->rec.ExceptionCode == EXCEPTION_STACK_OVERFLOW) goto done;
 
     switch(signal)
@@ -642,9 +638,6 @@ static void segv_handler( int signal, siginfo_t *info, void *ucontext )
         stack->rec.NumberParameters = 2;
         stack->rec.ExceptionInformation[0] = (get_fault_esr( context ) & 0x40) != 0;
         stack->rec.ExceptionInformation[1] = (ULONG_PTR)info->si_addr;
-        if (!(stack->rec.ExceptionCode = virtual_handle_fault( (void *)stack->rec.ExceptionInformation[1],
-                                                         stack->rec.ExceptionInformation[0], NULL )))
-            return;
         break;
     case SIGBUS:  /* Alignment check exception */
         stack->rec.ExceptionCode = EXCEPTION_DATATYPE_MISALIGNMENT;
diff --git a/dlls/ntdll/unix/signal_i386.c b/dlls/ntdll/unix/signal_i386.c
index 3bdf7c38e9..9d7635bcf4 100644
--- a/dlls/ntdll/unix/signal_i386.c
+++ b/dlls/ntdll/unix/signal_i386.c
@@ -1665,29 +1665,16 @@ static void segv_handler( int signal, siginfo_t *siginfo, void *sigcontext )
     void *stack_ptr = init_handler( sigcontext );
 
     /* check for exceptions on the signal stack caused by write watches */
-    if (TRAP_sig(context) == TRAP_x86_PAGEFLT &&
-        (char *)stack_ptr >= (char *)get_signal_stack() &&
-        (char *)stack_ptr < (char *)get_signal_stack() + signal_stack_size &&
-        !virtual_handle_fault( siginfo->si_addr, (ERROR_sig(context) >> 1) & 0x09, stack_ptr ))
-    {
-        return;
-    }
-
-    /* check for page fault inside the thread stack */
     if (TRAP_sig(context) == TRAP_x86_PAGEFLT)
     {
-        switch (virtual_handle_stack_fault( siginfo->si_addr ))
-        {
-        case 1:  /* handled */
-            return;
-        case -1:  /* overflow */
-            stack = setup_exception_record( context, stack_ptr );
-            stack->rec.ExceptionCode = EXCEPTION_STACK_OVERFLOW;
-            goto done;
-        }
+        DWORD err = (ERROR_sig(context) >> 1) & 0x09;
+        NTSTATUS status = virtual_handle_fault( siginfo->si_addr, err, stack_ptr );
+        if (!status) return;
+        stack = setup_exception_record( context, stack_ptr );
+        stack->rec.ExceptionCode = status;
     }
+    else stack = setup_exception_record( context, stack_ptr );
 
-    stack = setup_exception_record( context, stack_ptr );
     if (stack->rec.ExceptionCode == EXCEPTION_STACK_OVERFLOW) goto done;
 
     switch (TRAP_sig(context))
@@ -1727,9 +1714,6 @@ static void segv_handler( int signal, siginfo_t *siginfo, void *sigcontext )
         stack->rec.NumberParameters = 2;
         stack->rec.ExceptionInformation[0] = (ERROR_sig(context) >> 1) & 0x09;
         stack->rec.ExceptionInformation[1] = (ULONG_PTR)siginfo->si_addr;
-        stack->rec.ExceptionCode = virtual_handle_fault( (void *)stack->rec.ExceptionInformation[1],
-                                                         stack->rec.ExceptionInformation[0], NULL );
-        if (!stack->rec.ExceptionCode) return;
         if (stack->rec.ExceptionCode == EXCEPTION_ACCESS_VIOLATION &&
             stack->rec.ExceptionInformation[0] == EXCEPTION_EXECUTE_FAULT)
         {
diff --git a/dlls/ntdll/unix/signal_x86_64.c b/dlls/ntdll/unix/signal_x86_64.c
index 9b56044c70..1c8648c243 100644
--- a/dlls/ntdll/unix/signal_x86_64.c
+++ b/dlls/ntdll/unix/signal_x86_64.c
@@ -2125,27 +2125,16 @@ static void segv_handler( int signal, siginfo_t *siginfo, void *sigcontext )
     stack = (struct stack_layout *)(RSP_sig(ucontext) & ~15);
 
     /* check for exceptions on the signal stack caused by write watches */
-    if (TRAP_sig(ucontext) == TRAP_x86_PAGEFLT && is_inside_signal_stack( stack ) &&
-        !virtual_handle_fault( siginfo->si_addr, (ERROR_sig(ucontext) >> 1) & 0x09, stack ))
-    {
-        return;
-    }
-
-    /* check for page fault inside the thread stack */
     if (TRAP_sig(ucontext) == TRAP_x86_PAGEFLT)
     {
-        switch (virtual_handle_stack_fault( siginfo->si_addr ))
-        {
-        case 1:  /* handled */
-            return;
-        case -1:  /* overflow */
-            stack = setup_exception( sigcontext );
-            stack->rec.ExceptionCode = EXCEPTION_STACK_OVERFLOW;
-            goto done;
-        }
+        DWORD err = (ERROR_sig(ucontext) >> 1) & 0x09;
+        NTSTATUS status = virtual_handle_fault( siginfo->si_addr, err, stack );
+        if (!status) return;
+        stack = setup_exception( sigcontext );
+        stack->rec.ExceptionCode = status;
     }
+    else stack = setup_exception( sigcontext );
 
-    stack = setup_exception( sigcontext );
     if (stack->rec.ExceptionCode == EXCEPTION_STACK_OVERFLOW) goto done;
 
     switch(TRAP_sig(ucontext))
@@ -2178,9 +2167,6 @@ static void segv_handler( int signal, siginfo_t *siginfo, void *sigcontext )
         stack->rec.NumberParameters = 2;
         stack->rec.ExceptionInformation[0] = (ERROR_sig(ucontext) >> 1) & 0x09;
         stack->rec.ExceptionInformation[1] = (ULONG_PTR)siginfo->si_addr;
-        if (!(stack->rec.ExceptionCode = virtual_handle_fault((void *)stack->rec.ExceptionInformation[1],
-                                                              stack->rec.ExceptionInformation[0], NULL )))
-            return;
         break;
     case TRAP_x86_ALIGNFLT:  /* Alignment check exception */
         stack->rec.ExceptionCode = EXCEPTION_DATATYPE_MISALIGNMENT;
diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c
index 122f372978..8775f94fba 100644
--- a/dlls/ntdll/unix/virtual.c
+++ b/dlls/ntdll/unix/virtual.c
@@ -2884,9 +2884,14 @@ NTSTATUS virtual_handle_fault( void *addr, DWORD err, void *stack )
     vprot = get_page_vprot( page );
     if (!is_inside_signal_stack( stack ) && (vprot & VPROT_GUARD))
     {
-        set_page_vprot_bits( page, page_size, 0, VPROT_GUARD );
-        mprotect_range( page, page_size, 0, 0 );
-        ret = STATUS_GUARD_PAGE_VIOLATION;
+        if (page < (char *)NtCurrentTeb()->DeallocationStack ||
+            page >= (char *)NtCurrentTeb()->Tib.StackBase)
+        {
+            set_page_vprot_bits( page, page_size, 0, VPROT_GUARD );
+            mprotect_range( page, page_size, 0, 0 );
+            ret = STATUS_GUARD_PAGE_VIOLATION;
+        }
+        else ret = grow_thread_stack( page );
     }
     else if (err & EXCEPTION_WRITE_FAULT)
     {




More information about the wine-cvs mailing list