Bug 733892; block reverting to the null last chance expception handler. r=ehsan
authorNicholas Cameron <ncameron@mozilla.com>
Fri, 20 Apr 2012 21:07:55 +1200
changeset 92919 d65f0c082b1bf67cc025be574ba010409c619197
parent 92918 c608de1b6a53c6c0f88ed8a9648dacae886cd0c5
child 92920 423015379a53dfbf4bd6cce63893f89442ed1c09
push id22606
push useremorley@mozilla.com
push dateFri, 04 May 2012 08:42:45 +0000
treeherdermozilla-central@e1a40027dc7e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersehsan
bugs733892
milestone15.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 733892; block reverting to the null last chance expception handler. r=ehsan
toolkit/crashreporter/google-breakpad/src/client/windows/handler/exception_handler.h
toolkit/crashreporter/nsExceptionHandler.cpp
--- a/toolkit/crashreporter/google-breakpad/src/client/windows/handler/exception_handler.h
+++ b/toolkit/crashreporter/google-breakpad/src/client/windows/handler/exception_handler.h
@@ -233,16 +233,20 @@ class ExceptionHandler {
   // Returns whether out-of-process dump generation is used or not.
   bool IsOutOfProcess() const { return crash_generation_client_.get() != NULL; }
 
   // Calling RegisterAppMemory(p, len) causes len bytes starting
   // at address p to be copied to the minidump when a crash happens.
   void RegisterAppMemory(void *ptr, size_t length);
   void UnregisterAppMemory(void *ptr);
 
+  // Called on the exception thread when an unhandled exception occurs.
+  // Signals the exception handler thread to handle the exception.
+  static LONG WINAPI HandleException(EXCEPTION_POINTERS* exinfo);
+
  private:
   friend class AutoExceptionHandler;
 
   // Initializes the instance with given values.
   void Initialize(const wstring& dump_path,
                   FilterCallback filter,
                   MinidumpCallback callback,
                   void* callback_context,
@@ -263,20 +267,16 @@ class ExceptionHandler {
       CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam);
 
   // Function pointer type for UuidCreate, which is looked up dynamically.
   typedef RPC_STATUS (RPC_ENTRY *UuidCreate_type)(UUID* Uuid);
 
   // Runs the main loop for the exception handler thread.
   static DWORD WINAPI ExceptionHandlerThreadMain(void* lpParameter);
 
-  // Called on the exception thread when an unhandled exception occurs.
-  // Signals the exception handler thread to handle the exception.
-  static LONG WINAPI HandleException(EXCEPTION_POINTERS* exinfo);
-
 #if _MSC_VER >= 1400  // MSVC 2005/8
   // This function will be called by some CRT functions when they detect
   // that they were passed an invalid parameter.  Note that in _DEBUG builds,
   // the CRT may display an assertion dialog before calling this function,
   // and the function will not be called unless the assertion dialog is
   // dismissed by clicking "Ignore."
   static void HandleInvalidParameter(const wchar_t* expression,
                                      const wchar_t* function,
--- a/toolkit/crashreporter/nsExceptionHandler.cpp
+++ b/toolkit/crashreporter/nsExceptionHandler.cpp
@@ -52,16 +52,18 @@
 #undef WIN32_LEAN_AND_MEAN
 #endif
 
 #include "nsIWindowsRegKey.h"
 #include "client/windows/crash_generation/crash_generation_server.h"
 #include "client/windows/handler/exception_handler.h"
 #include <DbgHelp.h>
 #include <string.h>
+
+#include "nsWindowsDllInterceptor.h"
 #elif defined(XP_MACOSX)
 #include "client/mac/crash_generation/client_info.h"
 #include "client/mac/crash_generation/crash_generation_server.h"
 #include "client/mac/handler/exception_handler.h"
 #include <string>
 #include <Carbon/Carbon.h>
 #include <CoreFoundation/CoreFoundation.h>
 #include <crt_externs.h>
@@ -259,16 +261,41 @@ static const char* kSubprocessBlacklist[
   "URL"
 };
 
 // If annotations are attempted before the crash reporter is enabled,
 // they queue up here.
 class DelayedNote;
 nsTArray<nsAutoPtr<DelayedNote> >* gDelayedAnnotations;
 
+#if defined(XP_WIN)
+// the following are used to prevent other DLLs reverting the last chance
+// exception handler to the windows default. Any attempt to change the 
+// unhandled exception filter or to reset it is ignored and our crash
+// reporter is loaded instead (in case it became unloaded somehow)
+typedef LPTOP_LEVEL_EXCEPTION_FILTER (WINAPI *SetUnhandledExceptionFilter_func)
+  (LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter);
+static SetUnhandledExceptionFilter_func stub_SetUnhandledExceptionFilter = 0;
+static WindowsDllInterceptor gKernel32Intercept;
+static bool gBlockUnhandledExceptionFilter = true;
+
+static LPTOP_LEVEL_EXCEPTION_FILTER WINAPI
+patched_SetUnhandledExceptionFilter (LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter)
+{
+  if (!gBlockUnhandledExceptionFilter ||
+      lpTopLevelExceptionFilter == google_breakpad::ExceptionHandler::HandleException) {
+    // don't intercept
+    return stub_SetUnhandledExceptionFilter(lpTopLevelExceptionFilter);
+  }
+
+  // intercept attempts to change the filter
+  return NULL;
+}
+#endif
+
 #ifdef XP_MACOSX
 static cpu_type_t pref_cpu_types[2] = {
 #if defined(__i386__)
                                  CPU_TYPE_X86,
 #elif defined(__x86_64__)
                                  CPU_TYPE_X86_64,
 #elif defined(__ppc__)
                                  CPU_TYPE_POWERPC,
@@ -817,16 +844,27 @@ nsresult SetExceptionHandler(nsILocalFil
                       );
 #endif // XP_WIN32
 
   if (!gExceptionHandler)
     return NS_ERROR_OUT_OF_MEMORY;
 
 #ifdef XP_WIN
   gExceptionHandler->set_handle_debug_exceptions(true);
+  
+  // protect the crash reporter from being unloaded
+  gKernel32Intercept.Init("kernel32.dll");
+  bool ok = gKernel32Intercept.AddHook("SetUnhandledExceptionFilter",
+          reinterpret_cast<intptr_t>(patched_SetUnhandledExceptionFilter),
+          (void**) &stub_SetUnhandledExceptionFilter);
+
+#ifdef DEBUG
+  if (!ok)
+    printf_stderr ("SetUnhandledExceptionFilter hook failed; crash reporter is vulnerable.\n");
+#endif
 #endif
 
   // store application start time
   char timeString[32];
   time_t startupTime = time(NULL);
   XP_TTOA(startupTime, timeString, 10);
   AnnotateCrashReport(NS_LITERAL_CSTRING("StartupTime"),
                       nsDependentCString(timeString));
@@ -1077,16 +1115,21 @@ nsresult SetupExtraData(nsILocalFile* aA
 
   return NS_OK;
 }
 
 static void OOPDeinit();
 
 nsresult UnsetExceptionHandler()
 {
+#ifdef XP_WIN
+  // allow SetUnhandledExceptionFilter
+  gBlockUnhandledExceptionFilter = false;
+#endif
+
   delete gExceptionHandler;
 
   // do this here in the unlikely case that we succeeded in allocating
   // our strings but failed to allocate gExceptionHandler.
   delete crashReporterAPIData_Hash;
   crashReporterAPIData_Hash = nsnull;
 
   delete crashReporterAPILock;