1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "components/crash/content/app/breakpad_win.h"
6 
7 #include <crtdbg.h>
8 #include <intrin.h>
9 #include <shellapi.h>
10 #include <stddef.h>
11 #include <tchar.h>
12 #include <userenv.h>
13 #include <windows.h>
14 #include <winnt.h>
15 
16 #include <algorithm>
17 #include <map>
18 #include <memory>
19 #include <vector>
20 
21 #include "base/base_switches.h"
22 #include "base/command_line.h"
23 #include "base/debug/crash_logging.h"
24 #include "base/debug/dump_without_crashing.h"
25 #include "base/environment.h"
26 #include "base/files/file_path.h"
27 #include "base/no_destructor.h"
28 #include "base/numerics/safe_conversions.h"
29 #include "base/stl_util.h"
30 #include "base/strings/string16.h"
31 #include "base/strings/string_number_conversions.h"
32 #include "base/strings/string_split.h"
33 #include "base/strings/string_util.h"
34 #include "base/strings/stringprintf.h"
35 #include "base/strings/utf_string_conversions.h"
36 #include "base/win/pe_image.h"
37 #include "base/win/win_util.h"
38 #include "components/crash/content/app/hard_error_handler_win.h"
39 #include "components/crash/core/app/crash_reporter_client.h"
40 #include "components/crash/core/common/crash_keys.h"
41 #include "content/public/common/result_codes.h"
42 #include "sandbox/win/src/nt_internals.h"
43 #include "sandbox/win/src/sidestep/preamble_patcher.h"
44 #include "third_party/breakpad/breakpad/src/client/windows/common/ipc_protocol.h"
45 #include "third_party/breakpad/breakpad/src/client/windows/handler/exception_handler.h"
46 
47 #pragma intrinsic(_AddressOfReturnAddress)
48 #pragma intrinsic(_ReturnAddress)
49 
50 #ifdef _WIN64
51 // See http://msdn.microsoft.com/en-us/library/ddssxxy8.aspx
52 typedef struct _UNWIND_INFO {
53   unsigned char Version : 3;
54   unsigned char Flags : 5;
55   unsigned char SizeOfProlog;
56   unsigned char CountOfCodes;
57   unsigned char FrameRegister : 4;
58   unsigned char FrameOffset : 4;
59   ULONG ExceptionHandler;
60 } UNWIND_INFO, *PUNWIND_INFO;
61 #endif
62 
63 namespace breakpad {
64 
65 using crash_reporter::GetCrashReporterClient;
66 
67 namespace {
68 
69 // Minidump with stacks, PEB, TEB, and unloaded module list.
70 const MINIDUMP_TYPE kSmallDumpType = static_cast<MINIDUMP_TYPE>(
71     MiniDumpWithProcessThreadData |  // Get PEB and TEB.
72     MiniDumpWithUnloadedModules);  // Get unloaded modules when available.
73 
74 // Minidump with all of the above, plus memory referenced from stack.
75 const MINIDUMP_TYPE kLargerDumpType = static_cast<MINIDUMP_TYPE>(
76     MiniDumpWithProcessThreadData |  // Get PEB and TEB.
77     MiniDumpWithUnloadedModules |  // Get unloaded modules when available.
78     MiniDumpWithIndirectlyReferencedMemory);  // Get memory referenced by stack.
79 
80 // Large dump with all process memory.
81 const MINIDUMP_TYPE kFullDumpType = static_cast<MINIDUMP_TYPE>(
82     MiniDumpWithFullMemory |  // Full memory from process.
83     MiniDumpWithProcessThreadData |  // Get PEB and TEB.
84     MiniDumpWithHandleData |  // Get all handle information.
85     MiniDumpWithUnloadedModules);  // Get unloaded modules when available.
86 
87 const char kPipeNameVar[] = "CHROME_BREAKPAD_PIPE_NAME";
88 
89 const wchar_t kGoogleUpdatePipeName[] = L"\\\\.\\pipe\\GoogleCrashServices\\";
90 const wchar_t kChromePipeName[] = L"\\\\.\\pipe\\ChromeCrashServices";
91 
92 // This is the well known SID for the system principal.
93 const wchar_t kSystemPrincipalSid[] = L"S-1-5-18";
94 
95 google_breakpad::ExceptionHandler* g_breakpad = nullptr;
96 google_breakpad::ExceptionHandler* g_dumphandler_no_crash = nullptr;
97 
98 #if !defined(_WIN64)
99 EXCEPTION_POINTERS g_surrogate_exception_pointers = {0};
100 EXCEPTION_RECORD g_surrogate_exception_record = {0};
101 CONTEXT g_surrogate_context = {0};
102 #endif  // !defined(_WIN64)
103 
104 typedef NTSTATUS (WINAPI* NtTerminateProcessPtr)(HANDLE ProcessHandle,
105                                                  NTSTATUS ExitStatus);
106 char* g_real_terminate_process_stub = nullptr;
107 
108 // Returns the custom info structure based on the dll in parameter and the
109 // process type.
GetCustomInfo(const std::wstring & exe_path,const std::wstring & type,const std::wstring & profile_type,base::CommandLine * cmd_line,crash_reporter::CrashReporterClient * crash_client)110 google_breakpad::CustomClientInfo* GetCustomInfo(
111     const std::wstring& exe_path,
112     const std::wstring& type,
113     const std::wstring& profile_type,
114     base::CommandLine* cmd_line,
115     crash_reporter::CrashReporterClient* crash_client) {
116   base::string16 version, product, special_build, channel_name;
117   crash_client->GetProductNameAndVersion(exe_path, &product, &version,
118                                          &special_build, &channel_name);
119 
120   // We only expect this method to be called once per process.
121   // Common enties
122   static base::NoDestructor<std::vector<google_breakpad::CustomInfoEntry>>
123       custom_entries;
124   custom_entries->push_back(
125       google_breakpad::CustomInfoEntry(L"ver", version.c_str()));
126   custom_entries->push_back(
127       google_breakpad::CustomInfoEntry(L"prod", product.c_str()));
128   custom_entries->push_back(
129       google_breakpad::CustomInfoEntry(L"plat", L"Win32"));
130   custom_entries->push_back(
131       google_breakpad::CustomInfoEntry(L"ptype", type.c_str()));
132   custom_entries->push_back(google_breakpad::CustomInfoEntry(
133       L"pid", base::NumberToString16(::GetCurrentProcessId()).c_str()));
134   custom_entries->push_back(
135       google_breakpad::CustomInfoEntry(L"channel", channel_name.c_str()));
136   custom_entries->push_back(
137       google_breakpad::CustomInfoEntry(L"profile-type", profile_type.c_str()));
138 
139   if (!special_build.empty()) {
140     custom_entries->push_back(
141         google_breakpad::CustomInfoEntry(L"special", special_build.c_str()));
142   }
143 
144   // Check whether configuration management controls crash reporting.
145   bool crash_reporting_enabled = true;
146   bool controlled_by_policy =
147       crash_client->ReportingIsEnforcedByPolicy(&crash_reporting_enabled);
148   bool use_crash_service = !controlled_by_policy &&
149                            (cmd_line->HasSwitch(switches::kNoErrorDialogs) ||
150                             crash_client->IsRunningUnattended());
151   if (use_crash_service) {
152     base::string16 crash_dumps_dir_path;
153     if (crash_client->GetAlternativeCrashDumpLocation(&crash_dumps_dir_path)) {
154       custom_entries->push_back(google_breakpad::CustomInfoEntry(
155           L"breakpad-dump-location", crash_dumps_dir_path.c_str()));
156     }
157   }
158 
159   static base::NoDestructor<google_breakpad::CustomClientInfo>
160       custom_client_info;
161   custom_client_info->entries = &custom_entries->front();
162   custom_client_info->count = custom_entries->size();
163 
164   return custom_client_info.get();
165 }
166 
167 }  // namespace
168 
169 // Dumps the current process memory.
DumpProcess()170 extern "C" void __declspec(dllexport) __cdecl DumpProcess() {
171   if (g_breakpad) {
172     g_breakpad->WriteMinidump();
173   }
174 }
175 
176 // Used for dumping a process state when there is no crash.
DumpProcessWithoutCrash()177 extern "C" void __declspec(dllexport) __cdecl DumpProcessWithoutCrash() {
178   if (g_dumphandler_no_crash) {
179     g_dumphandler_no_crash->WriteMinidump();
180   }
181 }
182 
183 namespace {
184 
DumpProcessWithoutCrashThread(void *)185 DWORD WINAPI DumpProcessWithoutCrashThread(void*) {
186   DumpProcessWithoutCrash();
187   return 0;
188 }
189 
190 }  // namespace
191 
InjectDumpForHungInput(HANDLE process)192 extern "C" HANDLE __declspec(dllexport) __cdecl InjectDumpForHungInput(
193     HANDLE process) {
194   // |serialized_crash_keys| is not propagated in breakpad but is in crashpad
195   // since breakpad is deprecated.
196   return CreateRemoteThread(process, nullptr, 0, DumpProcessWithoutCrashThread,
197                             nullptr, 0, nullptr);
198 }
199 
200 // Returns a string containing a list of all modifiers for the loaded profile.
GetProfileType()201 std::wstring GetProfileType() {
202   std::wstring profile_type;
203   DWORD profile_bits = 0;
204   if (::GetProfileType(&profile_bits)) {
205     static const struct {
206       DWORD bit;
207       const wchar_t* name;
208     } kBitNames[] = {
209       { PT_MANDATORY, L"mandatory" },
210       { PT_ROAMING, L"roaming" },
211       { PT_TEMPORARY, L"temporary" },
212     };
213     for (size_t i = 0; i < base::size(kBitNames); ++i) {
214       const DWORD this_bit = kBitNames[i].bit;
215       if ((profile_bits & this_bit) != 0) {
216         profile_type.append(kBitNames[i].name);
217         profile_bits &= ~this_bit;
218         if (profile_bits != 0)
219           profile_type.append(L", ");
220       }
221     }
222   } else {
223     DWORD last_error = ::GetLastError();
224     base::SStringPrintf(&profile_type, L"error %u", last_error);
225   }
226   return profile_type;
227 }
228 
229 namespace {
230 
231 // This callback is used when we want to get a dump without crashing the
232 // process.
DumpDoneCallbackWhenNoCrash(const wchar_t *,const wchar_t *,void *,EXCEPTION_POINTERS * ex_info,MDRawAssertionInfo *,bool succeeded)233 bool DumpDoneCallbackWhenNoCrash(const wchar_t*, const wchar_t*, void*,
234                                  EXCEPTION_POINTERS* ex_info,
235                                  MDRawAssertionInfo*, bool succeeded) {
236   return true;
237 }
238 
239 // This callback is executed when the browser process has crashed, after
240 // the crash dump has been created. We need to minimize the amount of work
241 // done here since we have potentially corrupted process. Our job is to
242 // spawn another instance of chrome which will show a 'chrome has crashed'
243 // dialog. This code needs to live in the exe and thus has no access to
244 // facilities such as the i18n helpers.
DumpDoneCallback(const wchar_t *,const wchar_t *,void *,EXCEPTION_POINTERS * ex_info,MDRawAssertionInfo *,bool succeeded)245 bool DumpDoneCallback(const wchar_t*, const wchar_t*, void*,
246                       EXCEPTION_POINTERS* ex_info,
247                       MDRawAssertionInfo*, bool succeeded) {
248   // Check if the exception is one of the kind which would not be solved
249   // by simply restarting chrome. In this case we show a message box with
250   // and exit silently. Remember that chrome is in a crashed state so we
251   // can't show our own UI from this process.
252   if (HardErrorHandler(ex_info))
253     return true;
254 
255   if (!GetCrashReporterClient()->AboutToRestart())
256     return true;
257 
258   // Now we just start chrome browser with the same command line.
259   STARTUPINFOW si = {sizeof(si)};
260   PROCESS_INFORMATION pi;
261   if (::CreateProcessW(nullptr, ::GetCommandLineW(), nullptr, nullptr, FALSE,
262                        CREATE_UNICODE_ENVIRONMENT, nullptr, nullptr, &si,
263                        &pi)) {
264     ::CloseHandle(pi.hProcess);
265     ::CloseHandle(pi.hThread);
266   }
267   // After this return we will be terminated. The actual return value is
268   // not used at all.
269   return true;
270 }
271 
272 // flag to indicate that we are already handling an exception.
273 volatile LONG handling_exception = 0;
274 
275 // This callback is used when there is no crash. Note: Unlike the
276 // |FilterCallback| below this does not do dupe detection. It is upto the caller
277 // to implement it.
FilterCallbackWhenNoCrash(void *,EXCEPTION_POINTERS *,MDRawAssertionInfo *)278 bool FilterCallbackWhenNoCrash(
279     void*, EXCEPTION_POINTERS*, MDRawAssertionInfo*) {
280   return true;
281 }
282 
283 // This callback is executed when the Chrome process has crashed and *before*
284 // the crash dump is created. To prevent duplicate crash reports we
285 // make every thread calling this method, except the very first one,
286 // go to sleep.
FilterCallback(void *,EXCEPTION_POINTERS *,MDRawAssertionInfo *)287 bool FilterCallback(void*, EXCEPTION_POINTERS*, MDRawAssertionInfo*) {
288   // Capture every thread except the first one in the sleep. We don't
289   // want multiple threads to concurrently report exceptions.
290   if (::InterlockedCompareExchange(&handling_exception, 1, 0) == 1) {
291     ::Sleep(INFINITE);
292   }
293   return true;
294 }
295 
296 // Previous unhandled filter. Will be called if not null when we
297 // intercept a crash.
298 LPTOP_LEVEL_EXCEPTION_FILTER previous_filter = nullptr;
299 
300 // Exception filter used when breakpad is not enabled. We just display
301 // the "Do you want to restart" message and then we call the previous filter.
ChromeExceptionFilter(EXCEPTION_POINTERS * info)302 long WINAPI ChromeExceptionFilter(EXCEPTION_POINTERS* info) {
303   DumpDoneCallback(nullptr, nullptr, nullptr, info, nullptr, false);
304 
305   if (previous_filter)
306     return previous_filter(info);
307 
308   return EXCEPTION_EXECUTE_HANDLER;
309 }
310 
311 // Exception filter for the Cloud Print service process used when breakpad is
312 // not enabled. We just display the "Do you want to restart" message and then
313 // die (without calling the previous filter).
CloudPrintServiceExceptionFilter(EXCEPTION_POINTERS * info)314 long WINAPI CloudPrintServiceExceptionFilter(EXCEPTION_POINTERS* info) {
315   DumpDoneCallback(nullptr, nullptr, nullptr, info, nullptr, false);
316   return EXCEPTION_EXECUTE_HANDLER;
317 }
318 
319 }  // namespace
320 
WrapMessageBoxWithSEH(const wchar_t * text,const wchar_t * caption,UINT flags,bool * exit_now)321 static bool WrapMessageBoxWithSEH(const wchar_t* text, const wchar_t* caption,
322                                   UINT flags, bool* exit_now) {
323   // We wrap the call to MessageBoxW with a SEH handler because it some
324   // machines with CursorXP, PeaDict or with FontExplorer installed it crashes
325   // uncontrollably here. Being this a best effort deal we better go away.
326   __try {
327     *exit_now = (IDOK != ::MessageBoxW(nullptr, text, caption, flags));
328   } __except(EXCEPTION_EXECUTE_HANDLER) {
329     // Its not safe to continue executing, exit silently here.
330     ::TerminateProcess(::GetCurrentProcess(),
331                        GetCrashReporterClient()->GetResultCodeRespawnFailed());
332   }
333 
334   return true;
335 }
336 
337 // This function is executed by the child process that DumpDoneCallback()
338 // spawned and basically just shows the 'chrome has crashed' dialog if
339 // the CHROME_CRASHED environment variable is present.
ShowRestartDialogIfCrashed(bool * exit_now)340 bool ShowRestartDialogIfCrashed(bool* exit_now) {
341   base::string16 message;
342   base::string16 title;
343   bool is_rtl_locale;
344   if (!GetCrashReporterClient()->ShouldShowRestartDialog(
345           &title, &message, &is_rtl_locale)) {
346     return false;
347   }
348 
349   // If the UI layout is right-to-left, we need to pass the appropriate MB_XXX
350   // flags so that an RTL message box is displayed.
351   UINT flags = MB_OKCANCEL | MB_ICONWARNING;
352   if (is_rtl_locale)
353     flags |= MB_RIGHT | MB_RTLREADING;
354 
355   return WrapMessageBoxWithSEH(message.c_str(), title.c_str(), flags, exit_now);
356 }
357 
TerminateProcessWithoutDump()358 extern "C" void __declspec(dllexport) TerminateProcessWithoutDump() {
359   // Patched stub exists based on conditions (See InitCrashReporter).
360   // As a side note this function also gets called from
361   // WindowProcExceptionFilter.
362   if (g_real_terminate_process_stub == nullptr) {
363     ::TerminateProcess(::GetCurrentProcess(), content::RESULT_CODE_KILLED);
364   } else {
365     NtTerminateProcessPtr real_terminate_proc =
366         reinterpret_cast<NtTerminateProcessPtr>(
367             static_cast<char*>(g_real_terminate_process_stub));
368     real_terminate_proc(::GetCurrentProcess(), content::RESULT_CODE_KILLED);
369   }
370 }
371 
372 // Crashes the process after generating a dump for the provided exception. Note
373 // that the crash reporter should be initialized before calling this function
374 // for it to do anything.
CrashForException(EXCEPTION_POINTERS * info)375 extern "C" int __declspec(dllexport) CrashForException(
376     EXCEPTION_POINTERS* info) {
377   if (g_breakpad) {
378     g_breakpad->WriteMinidumpForException(info);
379     TerminateProcessWithoutDump();
380   }
381   return EXCEPTION_CONTINUE_SEARCH;
382 }
383 
384 #ifndef _WIN64
HookNtTerminateProcess(HANDLE ProcessHandle,NTSTATUS ExitStatus)385 static NTSTATUS WINAPI HookNtTerminateProcess(HANDLE ProcessHandle,
386                                               NTSTATUS ExitStatus) {
387   if (g_breakpad &&
388       (ProcessHandle == ::GetCurrentProcess() || ProcessHandle == NULL)) {
389     NT_TIB* tib = reinterpret_cast<NT_TIB*>(NtCurrentTeb());
390     void* address_on_stack = _AddressOfReturnAddress();
391     if (address_on_stack < tib->StackLimit ||
392         address_on_stack > tib->StackBase) {
393       g_surrogate_exception_record.ExceptionAddress = _ReturnAddress();
394       g_surrogate_exception_record.ExceptionCode = DBG_TERMINATE_PROCESS;
395       g_surrogate_exception_record.ExceptionFlags = EXCEPTION_NONCONTINUABLE;
396       CrashForException(&g_surrogate_exception_pointers);
397     }
398   }
399 
400   NtTerminateProcessPtr real_proc =
401       reinterpret_cast<NtTerminateProcessPtr>(
402           static_cast<char*>(g_real_terminate_process_stub));
403   return real_proc(ProcessHandle, ExitStatus);
404 }
405 
InitTerminateProcessHooks()406 static void InitTerminateProcessHooks() {
407   NtTerminateProcessPtr terminate_process_func_address =
408       reinterpret_cast<NtTerminateProcessPtr>(::GetProcAddress(
409           ::GetModuleHandle(L"ntdll.dll"), "NtTerminateProcess"));
410   if (terminate_process_func_address == NULL)
411     return;
412 
413   DWORD old_protect = 0;
414   if (!::VirtualProtect(reinterpret_cast<void*>(terminate_process_func_address),
415                         5, PAGE_EXECUTE_READWRITE, &old_protect))
416     return;
417 
418   g_real_terminate_process_stub = reinterpret_cast<char*>(VirtualAllocEx(
419       ::GetCurrentProcess(), NULL, sidestep::kMaxPreambleStubSize,
420       MEM_COMMIT, PAGE_EXECUTE_READWRITE));
421   if (g_real_terminate_process_stub == NULL)
422     return;
423 
424   g_surrogate_exception_pointers.ContextRecord = &g_surrogate_context;
425   g_surrogate_exception_pointers.ExceptionRecord =
426       &g_surrogate_exception_record;
427 
428   sidestep::SideStepError patch_result = sidestep::PreamblePatcher::Patch(
429       reinterpret_cast<void*>(terminate_process_func_address),
430       reinterpret_cast<void*>(HookNtTerminateProcess),
431       g_real_terminate_process_stub, sidestep::kMaxPreambleStubSize);
432   if (patch_result != sidestep::SIDESTEP_SUCCESS) {
433     CHECK(::VirtualFreeEx(::GetCurrentProcess(), g_real_terminate_process_stub,
434                     0, MEM_RELEASE));
435     CHECK(::VirtualProtect(
436         reinterpret_cast<void*>(terminate_process_func_address), 5, old_protect,
437         &old_protect));
438     return;
439   }
440 
441   DWORD dummy = 0;
442   CHECK(
443       ::VirtualProtect(reinterpret_cast<void*>(terminate_process_func_address),
444                        5, old_protect, &dummy));
445   CHECK(::VirtualProtect(g_real_terminate_process_stub,
446                          sidestep::kMaxPreambleStubSize,
447                          old_protect,
448                          &old_protect));
449 }
450 #endif
451 
InitPipeNameEnvVar(bool is_per_user_install)452 static void InitPipeNameEnvVar(bool is_per_user_install) {
453   std::unique_ptr<base::Environment> env(base::Environment::Create());
454   if (env->HasVar(kPipeNameVar)) {
455     // The Breakpad pipe name is already configured: nothing to do.
456     return;
457   }
458 
459   // Check whether configuration management controls crash reporting.
460   bool crash_reporting_enabled = true;
461   bool controlled_by_policy =
462       GetCrashReporterClient()->ReportingIsEnforcedByPolicy(
463           &crash_reporting_enabled);
464 
465   const base::CommandLine& command = *base::CommandLine::ForCurrentProcess();
466   bool use_crash_service = !controlled_by_policy &&
467                            (command.HasSwitch(switches::kNoErrorDialogs) ||
468                             GetCrashReporterClient()->IsRunningUnattended());
469 
470   std::wstring pipe_name;
471   if (use_crash_service) {
472     // Crash reporting is done by crash_service.exe.
473     pipe_name = kChromePipeName;
474   } else {
475     // We want to use the Google Update crash reporting. We need to check if the
476     // user allows it first (in case the administrator didn't already decide
477     // via policy).
478     if (!controlled_by_policy)
479       crash_reporting_enabled =
480           GetCrashReporterClient()->GetCollectStatsConsent();
481 
482     if (!crash_reporting_enabled) {
483       // Crash reporting is disabled, don't set the environment variable.
484       return;
485     }
486 
487     // Build the pipe name. It can be either:
488     // System-wide install: "NamedPipe\GoogleCrashServices\S-1-5-18"
489     // Per-user install: "NamedPipe\GoogleCrashServices\<user SID>"
490     std::wstring user_sid;
491     if (is_per_user_install) {
492       if (!base::win::GetUserSidString(&user_sid)) {
493         return;
494       }
495     } else {
496       user_sid = kSystemPrincipalSid;
497     }
498 
499     pipe_name = kGoogleUpdatePipeName;
500     pipe_name += user_sid;
501   }
502   env->SetVar(kPipeNameVar, base::UTF16ToASCII(pipe_name));
503 }
504 
InitDefaultCrashCallback(LPTOP_LEVEL_EXCEPTION_FILTER filter)505 void InitDefaultCrashCallback(LPTOP_LEVEL_EXCEPTION_FILTER filter) {
506   previous_filter = SetUnhandledExceptionFilter(filter);
507 }
508 
InitCrashReporter(const std::string & process_type_switch)509 void InitCrashReporter(const std::string& process_type_switch) {
510   const base::CommandLine& command = *base::CommandLine::ForCurrentProcess();
511   if (command.HasSwitch(switches::kDisableBreakpad))
512     return;
513 
514   // Disable the message box for assertions.
515   _CrtSetReportMode(_CRT_ASSERT, 0);
516 
517   base::string16 process_type = base::ASCIIToUTF16(process_type_switch);
518   if (process_type.empty())
519     process_type = L"browser";
520 
521   wchar_t exe_path[MAX_PATH];
522   exe_path[0] = 0;
523   GetModuleFileNameW(nullptr, exe_path, MAX_PATH);
524 
525   google_breakpad::CustomClientInfo* custom_info = GetCustomInfo(
526       exe_path, process_type, GetProfileType(),
527       base::CommandLine::ForCurrentProcess(), GetCrashReporterClient());
528 
529   google_breakpad::ExceptionHandler::MinidumpCallback callback = nullptr;
530   LPTOP_LEVEL_EXCEPTION_FILTER default_filter = nullptr;
531   // We install the post-dump callback only for the browser and service
532   // processes. It spawns a new browser/service process.
533   if (process_type == L"browser") {
534     callback = &DumpDoneCallback;
535     default_filter = &ChromeExceptionFilter;
536   } else if (process_type == L"service") {
537     callback = &DumpDoneCallback;
538     default_filter = &CloudPrintServiceExceptionFilter;
539   }
540 
541   if (GetCrashReporterClient()->ShouldCreatePipeName(process_type))
542     InitPipeNameEnvVar(GetCrashReporterClient()->GetIsPerUserInstall());
543 
544   std::unique_ptr<base::Environment> env(base::Environment::Create());
545   std::string pipe_name_ascii;
546   if (!env->GetVar(kPipeNameVar, &pipe_name_ascii)) {
547     // Breakpad is not enabled.  Configuration is managed or the user
548     // did not allow Google Update to send crashes.  We need to use
549     // our default crash handler instead, but only for the
550     // browser/service processes.
551     if (default_filter)
552       InitDefaultCrashCallback(default_filter);
553     return;
554   }
555   base::string16 pipe_name = base::ASCIIToUTF16(pipe_name_ascii);
556 
557 #ifdef _WIN64
558   // The protocol for connecting to the out-of-process Breakpad crash
559   // reporter is different for x86-32 and x86-64: the message sizes
560   // are different because the message struct contains a pointer.  As
561   // a result, there are two different named pipes to connect to.  The
562   // 64-bit one is distinguished with an "-x64" suffix.
563   pipe_name += L"-x64";
564 #endif
565 
566   // Get the alternate dump directory. We use the temp path.
567   wchar_t temp_dir[MAX_PATH] = {0};
568   ::GetTempPathW(MAX_PATH, temp_dir);
569 
570   MINIDUMP_TYPE dump_type = kSmallDumpType;
571   // Capture full memory if explicitly instructed to.
572   if (command.HasSwitch(switches::kFullMemoryCrashReport))
573     dump_type = kFullDumpType;
574   else if (GetCrashReporterClient()->GetShouldDumpLargerDumps())
575     dump_type = kLargerDumpType;
576 
577   g_breakpad = new google_breakpad::ExceptionHandler(
578       temp_dir, &FilterCallback, callback, nullptr,
579       google_breakpad::ExceptionHandler::HANDLER_ALL, dump_type,
580       pipe_name.c_str(), custom_info);
581 
582   // Now initialize the non crash dump handler.
583   g_dumphandler_no_crash = new google_breakpad::ExceptionHandler(
584       temp_dir, &FilterCallbackWhenNoCrash, &DumpDoneCallbackWhenNoCrash,
585       nullptr,
586       // Set the handler to none so this handler would not be added to
587       // |handler_stack_| in |ExceptionHandler| which is a list of exception
588       // handlers.
589       google_breakpad::ExceptionHandler::HANDLER_NONE, dump_type,
590       pipe_name.c_str(), custom_info);
591 
592   // Set the DumpWithoutCrashingFunction for this instance of base.lib.  Other
593   // executable images linked with base should set this again for
594   // DumpWithoutCrashing to function correctly.
595   // See chrome_main.cc for example.
596   base::debug::SetDumpWithoutCrashingFunction(&DumpProcessWithoutCrash);
597 
598   if (g_breakpad->IsOutOfProcess()) {
599     // Tells breakpad to handle breakpoint and single step exceptions.
600     // This might break JIT debuggers, but at least it will always
601     // generate a crashdump for these exceptions.
602     g_breakpad->set_handle_debug_exceptions(true);
603 
604 #ifndef _WIN64
605     if (process_type != L"browser" &&
606         !GetCrashReporterClient()->IsRunningUnattended()) {
607       // Initialize the hook TerminateProcess to catch unexpected exits.
608       InitTerminateProcessHooks();
609     }
610 #endif
611   }
612 }
613 
ConsumeInvalidHandleExceptions()614 void ConsumeInvalidHandleExceptions() {
615   if (g_breakpad) {
616     g_breakpad->set_consume_invalid_handle_exceptions(true);
617   }
618   if (g_dumphandler_no_crash) {
619     g_dumphandler_no_crash->set_consume_invalid_handle_exceptions(true);
620   }
621 }
622 
623 // If the user has disabled crash reporting uploads and restarted Chrome, the
624 // restarted instance will still contain the pipe environment variable, which
625 // will allow the restarted process to still upload crash reports. This function
626 // clears the environment variable, so that the restarted Chrome, which inherits
627 // its environment from the current Chrome, will no longer contain the variable.
628 extern "C" void __declspec(dllexport) __cdecl
ClearBreakpadPipeEnvironmentVariable()629 ClearBreakpadPipeEnvironmentVariable() {
630   std::unique_ptr<base::Environment> env(base::Environment::Create());
631   env->UnSetVar(kPipeNameVar);
632 }
633 
634 }  // namespace breakpad
635