| // Copyright 2022 The Crashpad Authors |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #include <string.h> |
| |
| #include "base/check.h" |
| #include "base/files/file_path.h" |
| #include "base/logging.h" |
| #include "base/notreached.h" |
| #include "client/crashpad_client.h" |
| #include "util/misc/paths.h" |
| |
| #include <Windows.h> |
| |
| // We set up a program that crashes with a CFG exception so must be built and |
| // linked with /guard:cf. We register the crashpad runtime exception helper |
| // module to intercept and trigger the crashpad handler. Note that Windows only |
| // loads the module in WerFault after the crash for Windows 10 >= 20h1 (19041). |
| namespace crashpad { |
| namespace { |
| |
| // This function should not be on our stack as CFG prevents the modified |
| // icall from happening. |
| int CallRffeManyTimes() { |
| RaiseFailFastException(nullptr, nullptr, 0); |
| RaiseFailFastException(nullptr, nullptr, 0); |
| RaiseFailFastException(nullptr, nullptr, 0); |
| RaiseFailFastException(nullptr, nullptr, 0); |
| return 1; |
| } |
| |
| using FuncType = decltype(&CallRffeManyTimes); |
| void IndirectCall(FuncType* func) { |
| // This code always generates CFG guards. |
| (*func)(); |
| } |
| |
| void CfgCrash() { |
| // Call into the middle of the Crashy function. |
| FuncType func = reinterpret_cast<FuncType>( |
| (reinterpret_cast<uintptr_t>(CallRffeManyTimes)) + 16); |
| __try { |
| // Generates a STATUS_STACK_BUFFER_OVERRUN exception if CFG triggers. |
| IndirectCall(&func); |
| } __except (EXCEPTION_EXECUTE_HANDLER) { |
| // CFG fast fail should never be caught. |
| NOTREACHED(); |
| } |
| // Should only reach here if CFG is disabled. |
| abort(); |
| } |
| |
| void FastFailCrash() { |
| __fastfail(77); |
| } |
| |
| int CrashyMain(int argc, wchar_t* argv[]) { |
| static CrashpadClient* client = new crashpad::CrashpadClient(); |
| |
| std::wstring type; |
| if (argc == 3) { |
| type = argv[2]; |
| // We call this from end_to_end_test.py. |
| if (!client->SetHandlerIPCPipe(argv[1])) { |
| LOG(ERROR) << "SetHandler"; |
| return EXIT_FAILURE; |
| } |
| } else if (argc == 4) { |
| type = argv[3]; |
| // This is helpful for debugging. |
| if (!client->StartHandler(base::FilePath(argv[1]), |
| base::FilePath(argv[2]), |
| base::FilePath(), |
| std::string(), |
| std::map<std::string, std::string>(), |
| std::vector<std::string>(), |
| false, |
| true)) { |
| LOG(ERROR) << "StartHandler"; |
| return EXIT_FAILURE; |
| } |
| // Got to have a handler & registration. |
| if (!client->WaitForHandlerStart(10000)) { |
| LOG(ERROR) << "Handler failed to start"; |
| return EXIT_FAILURE; |
| } |
| } else { |
| fprintf(stderr, "Usage: %ls <server_pipe_name> [cf|ff]\n", argv[0]); |
| fprintf( |
| stderr, " %ls <handler_path> <database_path> [cf|ff]\n", argv[0]); |
| return EXIT_FAILURE; |
| } |
| |
| base::FilePath exe_path; |
| if (!Paths::Executable(&exe_path)) { |
| LOG(ERROR) << "Failed getting path"; |
| return EXIT_FAILURE; |
| } |
| |
| // Find the module. |
| auto mod_path = exe_path.DirName().Append(L"crashpad_wer.dll"); |
| |
| // Make sure it is registered in the registry. |
| DWORD dwOne = 1; |
| LSTATUS reg_res = |
| RegSetKeyValueW(HKEY_CURRENT_USER, |
| L"Software\\Microsoft\\Windows\\Windows Error Reporting\\" |
| L"RuntimeExceptionHelperModules", |
| mod_path.value().c_str(), |
| REG_DWORD, |
| &dwOne, |
| sizeof(DWORD)); |
| if (reg_res != ERROR_SUCCESS) { |
| LOG(ERROR) << "RegSetKeyValueW"; |
| return EXIT_FAILURE; |
| } |
| |
| if (!client->RegisterWerModule(mod_path.value())) { |
| LOG(ERROR) << "WerRegisterRuntimeExceptionModule"; |
| return EXIT_FAILURE; |
| } |
| |
| // Some versions of python call SetErrorMode() which extends to children, and |
| // prevents the WerFault infrastructure from running. |
| SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX); |
| |
| if (type == L"cf") |
| CfgCrash(); |
| if (type == L"ff") |
| FastFailCrash(); |
| |
| LOG(ERROR) << "Invalid type or exception failed."; |
| return EXIT_FAILURE; |
| } |
| |
| } // namespace |
| } // namespace crashpad |
| |
| int wmain(int argc, wchar_t* argv[]) { |
| return crashpad::CrashyMain(argc, argv); |
| } |