Uploaded image for project: 'Core ReactOS'
  1. Core ReactOS
  2. CORE-20316

PSEH: Problematic RegistrationFrame in GCC-compiled SEH test app

    XMLWordPrintable

Details

    • Bug
    • Resolution: Unresolved
    • Critical
    • None
    • CRT, Other
    • None

    Description

      Commit 51ee32f5f8 unveiled a weird condition on GCC builds only (not happening with MSVC ones), wherein executing nested SEH handlers leads to either dereferencing a NULL RegistrationFrame, or having no RegistrationFrame available, when running in a specific environment alike to what winlogon.exe executes.

      In the above-mentioned commit, the problem was unveiled by moving the WNetClearConnections(NULL); function call (implemented in mpr.dll) from a separately-spawned thread, and into the main winlogon thread.
      This routine invoked a 3rd party module (nfs41_np.dll) that was executing the kernel32!OutputDebugStringA() function, and the crash happened while "executing" the PSEH implementation of an inner _SEH2_TRY .
      (A hack that hides the problem, is to surround the OutputDebugStringA() call, or the outer WNetClearConnections(NULL); call, within a _SEH2_TRY / _SEH2_EXCEPT / _SEH2_END; block. But this is only a hack, and not THE actual fix!)

      However, I managed to isolate the problem to the specific usage of nested SEH handlers and made a minimal test application that can reproduce the problem, without the need to invoke OutputDebugStringA.
      The nested SEH handlers pattern, also used by kernel32!OutputDebugStringA and that causes the problem is the following one:

          _SEH2_TRY
          {
              /* Throw a random exception to jump to the _SEH2_EXCEPT block below */
              RaiseException(0xDEADBEEF, 0, 0, NULL);   // NOTE: kernel32!OutputDebugStringA raises DBG_PRINTEXCEPTION_C
          }
          _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
          {
              _SEH2_TRY      // <------ This _SEH2_TRY crashes!!
              {
                  _SEH2_TRY
                  {
                      // Do soething useful, like: DbgPrint("%s", OutputString);
                  }
                  _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
                  {
                  }
                  _SEH2_END;
              }
              _SEH2_FINALLY
              {
              }
              _SEH2_END;
          }
          _SEH2_END;
      

      A MAJOR observation is that this problem happens when the test program is started in an environment similar to that winlogon.exe is started, i.e., using the ntdll!RtlCreateUserProcess() and manually registered with the CSR subsystem, and NOT when starting the process with kernel32!CreateProcess() !


      I attach two precompiled binaries + their PDB (only for MSVC build), together with the source-code in 0002-ROSTESTS-NTRTL_SEH-Add-tests-for-SEH-in-application.patch (see also the modules_rostests_win32_ntrtl_seh.zip archive):

      • an MSVC v19.29.30159 x86 compiled ntrtl_seh_msvc.exe binary, that does *NOT* reproduces the problem;
      • a RosBE-Windows 2.2.1 gcc v8.4.0 compiled ntrtl_seh_gcc.exe binary, with which the problem can be reproduced.

      (GUI interactive versions of these tests can also be found in the ntrtl_seh_interactive.zip archive.)

      I also join a launcher app, nativerun.exe, to easily start the test programs in an environment similar to that of winlogon.exe.

      To ease diagnostics, a patch to apply to ReactOS (on ntoskrnl and csrsrv), which adds extra detailed DPRINTs, is also attached: 0001-wip-Diagnose-SEH2-crashes.patch


      Testing procedure:

      • Locally patch ReactOS with the attached 0001-wip-Diagnose-SEH2-crashes.patch (optional);
      • Compile ReactOS with MSVC, so that you can easily obtain debugging traces etc. with WinDbg. (Or you can use a GCC build, as you wish!)
      • Install ReactOS;
      • Copy the nativerun.exe launcher app, as well as the two test binaries ntrtl_seh_msvc.exe and ntrtl_seh_gcc.exe in the system32 directory of your ReactOS installation;
      • From command-line, execute in turn ntrtl_seh_msvc.exe and ntrtl_seh_gcc.exe directly – this would use kernel32!CreateProcess to load them – , then, use the nativerun.exe launcher app to run these – now testing an execution environment similar to winlogon's. Observe the debug output in the attached kernel debugger.
      • Alternatively you can replace the winlogon.exe executable with any of the test programs (and renaming them to winlogon.exe) then reboot ReactOS and observe the debug output in the attached kernel debugger.

      Results:

      • ntrtl_seh_msvc.exe started directly (i.e. with kernel32!CreateProcess()): Works
        Output summary below; analysis of the exception RegistrationFrame's in ntrtl_seh_msvc_normal.txt

        Replaced Original unhandled exception filter: 0x00402490
        OutputDebugStringA with SEH test
        ODS(0x00403370) -> 'WL: WinMain(1)
        '
        MyOutputDebugStringA - Entering _SEH2_TRY(1)
        MyOutputDebugStringA - Inside _SEH2_TRY(1)
        MyOutputDebugStringA - Entering _SEH2_TRY(2)
        MyOutputDebugStringA - Inside _SEH2_TRY(2)
        WL: WinMain(1)
        MyOutputDebugStringA - Exited _SEH2_EXCEPT(2)
        MyOutputDebugStringA - Inside and exiting _SEH2_FINALLY(1)
        MyOutputDebugStringA - Exited _SEH2_TRY(1)/_SEH2_FINALLY(1)
        ODS(0x004033AC) -> 'WL: WinMain(2)
        '
        MyOutputDebugStringA - Entering _SEH2_TRY(1)
        MyOutputDebugStringA - Inside _SEH2_TRY(1)
        MyOutputDebugStringA - Entering _SEH2_TRY(2)
        MyOutputDebugStringA - Inside _SEH2_TRY(2)
        WL: WinMain(2)
        MyOutputDebugStringA - Exited _SEH2_EXCEPT(2)
        MyOutputDebugStringA - Inside and exiting _SEH2_FINALLY(1)
        MyOutputDebugStringA - Exited _SEH2_TRY(1)/_SEH2_FINALLY(1)
        ODS(0x004033BC) -> 'WL: WinMain(3)
        '
        MyOutputDebugStringA - Entering _SEH2_TRY(1)
        MyOutputDebugStringA - Inside _SEH2_TRY(1)
        MyOutputDebugStringA - Entering _SEH2_TRY(2)
        MyOutputDebugStringA - Inside _SEH2_TRY(2)
        WL: WinMain(3)
        MyOutputDebugStringA - Exited _SEH2_EXCEPT(2)
        MyOutputDebugStringA - Inside and exiting _SEH2_FINALLY(1)
        MyOutputDebugStringA - Exited _SEH2_TRY(1)/_SEH2_FINALLY(1)
        Test succeeded!
        

      • ntrtl_seh_gcc.exe started directly: Works
        Output summary below; analysis of the exception RegistrationFrame's in ntrtl_seh_gcc_normal.txt

        Replaced Original unhandled exception filter: 0x00401CFC
        OutputDebugStringA with SEH test
        ODS(0x00404272) -> 'WL: WinMain(1)
        '
        MyOutputDebugStringA - Entering _SEH2_TRY(1)
        MyOutputDebugStringA - Inside _SEH2_TRY(1)
        MyOutputDebugStringA - Entering _SEH2_TRY(2)
        MyOutputDebugStringA - Inside _SEH2_TRY(2)
        WL: WinMain(1)
        MyOutputDebugStringA - Exited _SEH2_EXCEPT(2)
        _SEH3$_FinallyFunction - Inside and exiting _SEH2_FINALLY(1)
        MyOutputDebugStringA - Exited _SEH2_TRY(1)/_SEH2_FINALLY(1)
        ODS(0x004042B0) -> 'WL: WinMain(2)
        '
        MyOutputDebugStringA - Entering _SEH2_TRY(1)
        MyOutputDebugStringA - Inside _SEH2_TRY(1)
        MyOutputDebugStringA - Entering _SEH2_TRY(2)
        MyOutputDebugStringA - Inside _SEH2_TRY(2)
        WL: WinMain(2)
        MyOutputDebugStringA - Exited _SEH2_EXCEPT(2)
        _SEH3$_FinallyFunction - Inside and exiting _SEH2_FINALLY(1)
        MyOutputDebugStringA - Exited _SEH2_TRY(1)/_SEH2_FINALLY(1)
        ODS(0x004042C0) -> 'WL: WinMain(3)
        '
        MyOutputDebugStringA - Entering _SEH2_TRY(1)
        MyOutputDebugStringA - Inside _SEH2_TRY(1)
        MyOutputDebugStringA - Entering _SEH2_TRY(2)
        MyOutputDebugStringA - Inside _SEH2_TRY(2)
        WL: WinMain(3)
        MyOutputDebugStringA - Exited _SEH2_EXCEPT(2)
        _SEH3$_FinallyFunction - Inside and exiting _SEH2_FINALLY(1)
        MyOutputDebugStringA - Exited _SEH2_TRY(1)/_SEH2_FINALLY(1)
        Test succeeded!
        

      • nativerun.exe ntrtl_seh_msvc.exe , i.e. environment similar to winlogon.exe (with ntdll!RtlCreateUserProcess()) : Works
        Output summary below; analysis of the exception RegistrationFrame's in ntrtl_seh_msvc_native.txt

        Win32 GUI process detected, registering with CSRSS
        Process 0x6F8 (1784) created successfully.
        Replaced Original unhandled exception filter: 0x00402490
        OutputDebugStringA with SEH test
        ODS(0x00403370) -> 'WL: WinMain(1)
        '
        MyOutputDebugStringA - Entering _SEH2_TRY(1)
        MyOutputDebugStringA - Inside _SEH2_TRY(1)
        MyOutputDebugStringA - Entering _SEH2_TRY(2)
        MyOutputDebugStringA - Inside _SEH2_TRY(2)
        WL: WinMain(1)
        MyOutputDebugStringA - Exited _SEH2_EXCEPT(2)
        MyOutputDebugStringA - Inside and exiting _SEH2_FINALLY(1)
        MyOutputDebugStringA - Exited _SEH2_TRY(1)/_SEH2_FINALLY(1)
        ODS(0x004033AC) -> 'WL: WinMain(2)
        '
        MyOutputDebugStringA - Entering _SEH2_TRY(1)
        MyOutputDebugStringA - Inside _SEH2_TRY(1)
        MyOutputDebugStringA - Entering _SEH2_TRY(2)
        MyOutputDebugStringA - Inside _SEH2_TRY(2)
        WL: WinMain(2)
        MyOutputDebugStringA - Exited _SEH2_EXCEPT(2)
        MyOutputDebugStringA - Inside and exiting _SEH2_FINALLY(1)
        MyOutputDebugStringA - Exited _SEH2_TRY(1)/_SEH2_FINALLY(1)
        ODS(0x004033BC) -> 'WL: WinMain(3)
        '
        MyOutputDebugStringA - Entering _SEH2_TRY(1)
        MyOutputDebugStringA - Inside _SEH2_TRY(1)
        MyOutputDebugStringA - Entering _SEH2_TRY(2)
        MyOutputDebugStringA - Inside _SEH2_TRY(2)
        WL: WinMain(3)
        MyOutputDebugStringA - Exited _SEH2_EXCEPT(2)
        MyOutputDebugStringA - Inside and exiting _SEH2_FINALLY(1)
        MyOutputDebugStringA - Exited _SEH2_TRY(1)/_SEH2_FINALLY(1)
        Test succeeded!
        

      • nativerun.exe ntrtl_seh_gcc.exe , i.e. environment similar to winlogon.exe (with ntdll!RtlCreateUserProcess()) : CRASH!
        Output summary below; analysis of the exception RegistrationFrame's in ntrtl_seh_gcc_native.txt

        Win32 GUI process detected, registering with CSRSS
        Process 0x740 (1856) created successfully.
        Replaced Original unhandled exception filter: 0x00401CFC
        OutputDebugStringA with SEH test
        ODS(0x00404272) -> 'WL: WinMain(1)
        '
        MyOutputDebugStringA - Entering _SEH2_TRY(1)
        MyOutputDebugStringA - Inside _SEH2_TRY(1)
        MyOutputDebugStringA - Entering _SEH2_TRY(2)
        MyOutputDebugStringA - Inside _SEH2_TRY(2)
        WL: WinMain(1)
        MyOutputDebugStringA - Exited _SEH2_EXCEPT(2)
        _SEH3$_FinallyFunction - Inside and exiting _SEH2_FINALLY(1)
        MyOutputDebugStringA - Exited _SEH2_TRY(1)/_SEH2_FINALLY(1)
        ODS(0x004042B0) -> 'WL: WinMain(2)
        '
        MyOutputDebugStringA - Entering _SEH2_TRY(1)
        DbgkForwardException: ExceptionRecord: F5C7BC90 (ExceptionCode: 0xc0000005, ExceptionAddress: 0x004017D2), Port: TRUE, SecondChance: FALSE
        DbgkForwardException: ExceptionRecord: F5C7B97C (ExceptionCode: 0xc0000005, ExceptionAddress: 0x004017D2), Port: TRUE, SecondChance: TRUE
        DbgkForwardException: ExceptionRecord: F5C7B97C (ExceptionCode: 0xc0000005, ExceptionAddress: 0x004017D2), Port: FALSE, SecondChance: TRUE
        CsrApiRequestThread() - Got LPC_EXCEPTION with:
          ExceptionCode: 0xc0000005, flags 0x0, ExceptionAddress: 0x004017D2 ; IsFirstChance: FALSE
          Info[0]: 0x00000000
          Info[1]: 0x0000000F
        CsrApiRequestThread() - LPC_EXCEPTION invoking NtTerminateProcess(ProcessHandle 0x000006E4, 128)
        

      Attachments

        1. 0001-wip-Diagnose-SEH2-crashes.patch
          3 kB
          hbelusca
        2. 0002-ROSTESTS-NTRTL_SEH-Add-tests-for-SEH-in-application.patch
          11 kB
          hbelusca
        3. nativerun.exe
          17 kB
          hbelusca
        4. nativerun.pdb
          188 kB
          hbelusca
        5. ntrtl_seh_gcc_native.txt
          13 kB
          hbelusca
        6. ntrtl_seh_gcc_normal.txt
          14 kB
          hbelusca
        7. ntrtl_seh_gcc.exe
          37 kB
          hbelusca
        8. ntrtl_seh_msvc_native.txt
          15 kB
          hbelusca
        9. ntrtl_seh_msvc_normal.txt
          19 kB
          hbelusca
        10. ntrtl_seh_msvc.exe
          13 kB
          hbelusca
        11. ntrtl_seh.pdb
          284 kB
          hbelusca

        Issue Links

          Activity

            People

              Unassigned Unassigned
              hbelusca hbelusca
              Votes:
              2 Vote for this issue
              Watchers:
              1 Start watching this issue

              Dates

                Created:
                Updated: