[PATCH v4 4/5] ntdll: Implement __fastfail().

Jinoh Kang jinoh.kang.kr at gmail.com
Thu Dec 9 05:37:04 CST 2021


__fastfail() is used by the Visual C++ runtime and Windows system
libraries to signal that the in-process state is corrupted and
unrecoverable.

If __fastfail() is invoked, the NT kernel raises a second-chance
non-continuable exception STATUS_STACK_BUFFER_OVERRUN.  This quickly
terminates the process, bypassing all in-process exception handlers
(since they all rely on the potentially corrupted process state).

Signed-off-by: Jinoh Kang <jinoh.kang.kr at gmail.com>
---

Notes:
    v3 -> v4: fix BRK #0xF003 detection on ARM64
              add comments

 dlls/ntdll/tests/exception.c    |  1 -
 dlls/ntdll/unix/signal_arm.c    | 14 ++++++++++++--
 dlls/ntdll/unix/signal_arm64.c  | 15 +++++++++++++++
 dlls/ntdll/unix/signal_i386.c   |  7 +++++++
 dlls/ntdll/unix/signal_x86_64.c |  7 +++++++
 5 files changed, 41 insertions(+), 3 deletions(-)

diff --git a/dlls/ntdll/tests/exception.c b/dlls/ntdll/tests/exception.c
index c0d3ae19a51..14b1396dbc2 100644
--- a/dlls/ntdll/tests/exception.c
+++ b/dlls/ntdll/tests/exception.c
@@ -8429,7 +8429,6 @@ static void subtest_fastfail(unsigned int code)
 
     } while (de.dwDebugEventCode != EXIT_PROCESS_DEBUG_EVENT);
 
-    todo_wine
     ok(had_ff || broken(had_se) /* Win7 */, "fast fail did not occur\n");
 
     wait_child_process( pi.hProcess );
diff --git a/dlls/ntdll/unix/signal_arm.c b/dlls/ntdll/unix/signal_arm.c
index dbc2770f72e..1816e210644 100644
--- a/dlls/ntdll/unix/signal_arm.c
+++ b/dlls/ntdll/unix/signal_arm.c
@@ -809,13 +809,23 @@ static void segv_handler( int signal, siginfo_t *siginfo, void *sigcontext )
     switch (get_trap_code(signal, context))
     {
     case TRAP_ARM_PRIVINFLT:   /* Invalid opcode exception */
-        if (*(WORD *)PC_sig(context) == 0xdefe)  /* breakpoint */
+        switch (*(WORD *)PC_sig(context))
         {
+        case 0xdefb:  /* __fastfail */
+            rec.ExceptionCode = STATUS_STACK_BUFFER_OVERRUN;
+            rec.ExceptionFlags = EH_NONCONTINUABLE;
+            rec.NumberParameters = 1;
+            rec.ExceptionInformation[0] = REGn_sig(0, context);
+            setup_exception( context, &rec, FALSE );
+            return;
+        case 0xdefe:  /* breakpoint */
             rec.ExceptionCode = EXCEPTION_BREAKPOINT;
             rec.NumberParameters = 1;
             break;
+        default:
+            rec.ExceptionCode = EXCEPTION_ILLEGAL_INSTRUCTION;
+            break;
         }
-        rec.ExceptionCode = EXCEPTION_ILLEGAL_INSTRUCTION;
         break;
     case TRAP_ARM_PAGEFLT:  /* Page fault */
         rec.NumberParameters = 2;
diff --git a/dlls/ntdll/unix/signal_arm64.c b/dlls/ntdll/unix/signal_arm64.c
index 6349c72323c..ae44fb02982 100644
--- a/dlls/ntdll/unix/signal_arm64.c
+++ b/dlls/ntdll/unix/signal_arm64.c
@@ -905,6 +905,7 @@ static void bus_handler( int signal, siginfo_t *siginfo, void *sigcontext )
 static void trap_handler( int signal, siginfo_t *siginfo, void *sigcontext )
 {
     EXCEPTION_RECORD rec = { 0 };
+    ucontext_t *context = sigcontext;
 
     switch (siginfo->si_code)
     {
@@ -913,6 +914,20 @@ static void trap_handler( int signal, siginfo_t *siginfo, void *sigcontext )
         break;
     case TRAP_BRKPT:
     default:
+        /* debug exceptions do not update ESR on Linux,
+         * so we fetch the instruction directly. */
+        if (!(PSTATE_sig( context ) & 0x10) && /* AArch64 (not WoW) */
+            !(PC_sig( context ) & 3) &&
+            *(ULONG *)PC_sig( context ) == 0xd43e0060UL) /* brk #0xf003 */
+        {
+            /* __fastfail */
+            rec.ExceptionCode = STATUS_STACK_BUFFER_OVERRUN;
+            rec.ExceptionFlags = EH_NONCONTINUABLE;
+            rec.NumberParameters = 1;
+            rec.ExceptionInformation[0] = REGn_sig( 0, context );
+            setup_exception( sigcontext, &rec, FALSE );
+            return;
+        }
         rec.ExceptionCode = EXCEPTION_BREAKPOINT;
         rec.NumberParameters = 1;
         break;
diff --git a/dlls/ntdll/unix/signal_i386.c b/dlls/ntdll/unix/signal_i386.c
index e18aed2c222..1ec85240612 100644
--- a/dlls/ntdll/unix/signal_i386.c
+++ b/dlls/ntdll/unix/signal_i386.c
@@ -1660,6 +1660,13 @@ static BOOL handle_interrupt( unsigned int interrupt, ucontext_t *sigcontext, vo
 
     switch(interrupt)
     {
+    case 0x29:  /* __fastfail */
+        rec->ExceptionCode = STATUS_STACK_BUFFER_OVERRUN;
+        rec->ExceptionFlags = EH_NONCONTINUABLE;
+        rec->NumberParameters = 1;
+        rec->ExceptionInformation[0] = context->Ecx;
+        setup_raise_exception( sigcontext, stack, rec, xcontext, FALSE );
+        return TRUE;
     case 0x2d:
         if (!is_wow64)
         {
diff --git a/dlls/ntdll/unix/signal_x86_64.c b/dlls/ntdll/unix/signal_x86_64.c
index 7e920d31978..3d7b8e256b4 100644
--- a/dlls/ntdll/unix/signal_x86_64.c
+++ b/dlls/ntdll/unix/signal_x86_64.c
@@ -2441,6 +2441,13 @@ static inline BOOL handle_interrupt( ucontext_t *sigcontext, EXCEPTION_RECORD *r
 
     switch (ERROR_sig(sigcontext) >> 3)
     {
+    case 0x29:  /* __fastfail */
+        rec->ExceptionCode = STATUS_STACK_BUFFER_OVERRUN;
+        rec->ExceptionFlags = EH_NONCONTINUABLE;
+        rec->NumberParameters = 1;
+        rec->ExceptionInformation[0] = context->Rcx;
+        setup_raise_exception( sigcontext, rec, xcontext, FALSE );
+        return TRUE;
     case 0x2c:
         rec->ExceptionCode = STATUS_ASSERTION_FAILURE;
         break;
-- 
2.34.1




More information about the wine-devel mailing list