Chromium Code Reviews| Index: client/crashpad_client_win.cc |
| diff --git a/client/crashpad_client_win.cc b/client/crashpad_client_win.cc |
| index 46b613726b8b1a9ac49606b94d5dc509de04ee5a..13ef3d622117755d768a9be6ddd2da5f485a9ba0 100644 |
| --- a/client/crashpad_client_win.cc |
| +++ b/client/crashpad_client_win.cc |
| @@ -19,6 +19,8 @@ |
| #include "base/atomicops.h" |
| #include "base/logging.h" |
| +#include "base/memory/scoped_ptr.h" |
| +#include "base/scoped_generic.h" |
| #include "base/strings/string16.h" |
| #include "base/strings/stringprintf.h" |
| #include "base/strings/utf_string_conversions.h" |
| @@ -26,6 +28,7 @@ |
| #include "util/file/file_io.h" |
| #include "util/win/command_line.h" |
| #include "util/win/critical_section_with_debug_info.h" |
| +#include "util/win/get_function.h" |
| #include "util/win/handle.h" |
| #include "util/win/registration_protocol_win.h" |
| #include "util/win/scoped_handle.h" |
| @@ -110,6 +113,40 @@ std::wstring FormatArgumentString(const std::string& name, |
| return std::wstring(L"--") + base::UTF8ToUTF16(name) + L"=" + value; |
| } |
| +struct ScopedProcThreadAttributeListTraits { |
| + static PPROC_THREAD_ATTRIBUTE_LIST InvalidValue() { |
| + return nullptr; |
| + } |
| + |
| + static void Free(PPROC_THREAD_ATTRIBUTE_LIST proc_thread_attribute_list) { |
| + // This is able to use GET_FUNCTION_REQUIRED() instead of GET_FUNCTION() |
| + // because it will only be called if InitializeProcThreadAttributeList() and |
| + // UpdateProcThreadAttribute() are present. |
| + static const auto delete_proc_thread_attribute_list = |
| + GET_FUNCTION_REQUIRED(L"kernel32.dll", ::DeleteProcThreadAttributeList); |
| + delete_proc_thread_attribute_list(proc_thread_attribute_list); |
| + } |
| +}; |
| + |
| +using ScopedProcThreadAttributeList = |
| + base::ScopedGeneric<PPROC_THREAD_ATTRIBUTE_LIST, |
| + ScopedProcThreadAttributeListTraits>; |
| + |
| +// Adds |handle| to |handle_list| if it appears valid. |
| +// |
| +// Invalid handles (including INVALID_HANDLE_VALUE and null handles) cannot be |
| +// added to a PPROC_THREAD_ATTRIBUTE_LIST’s PROC_THREAD_ATTRIBUTE_HANDLE_LIST. |
| +// If INVALID_HANDLE_VALUE appears, CreateProcess() will fail with |
| +// ERROR_INVALID_PARAMETER. If a null handle appears, the child process will |
| +// silently not inherit any handles. |
| +// |
| +// Use this function to add handles with uncertain validities. |
| +void AddHandleToListIfValid(std::vector<HANDLE>* handle_list, HANDLE handle) { |
| + if (handle && handle != INVALID_HANDLE_VALUE) { |
| + handle_list->push_back(handle); |
| + } |
| +} |
| + |
| } // namespace |
| namespace crashpad { |
| @@ -172,22 +209,85 @@ bool CrashpadClient::StartHandler( |
| HandleToInt(pipe_write))), |
| &command_line); |
| - STARTUPINFO startup_info = {}; |
| - startup_info.cb = sizeof(startup_info); |
| - startup_info.dwFlags = STARTF_USESTDHANDLES; |
| - startup_info.hStdInput = GetStdHandle(STD_INPUT_HANDLE); |
| - startup_info.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE); |
| - startup_info.hStdError = GetStdHandle(STD_ERROR_HANDLE); |
| + DWORD creation_flags; |
| + STARTUPINFOEX startup_info = {}; |
| + startup_info.StartupInfo.dwFlags = STARTF_USESTDHANDLES; |
| + startup_info.StartupInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE); |
| + startup_info.StartupInfo.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE); |
| + startup_info.StartupInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE); |
| + |
| + std::vector<HANDLE> handle_list; |
| + scoped_ptr<uint8_t[]> proc_thread_attribute_list_storage; |
| + ScopedProcThreadAttributeList proc_thread_attribute_list_owner; |
| + |
| + static const auto initialize_proc_thread_attribute_list = |
| + GET_FUNCTION(L"kernel32.dll", ::InitializeProcThreadAttributeList); |
|
scottmg
2015/11/06 20:15:02
Probably don't need :: on these?
Mark Mentovai
2015/11/06 21:49:09
scottmg wrote:
scottmg
2015/11/06 21:53:34
OK, that's fine then too.
|
| + static const auto update_proc_thread_attribute = |
| + initialize_proc_thread_attribute_list |
| + ? GET_FUNCTION(L"kernel32.dll", ::UpdateProcThreadAttribute) |
| + : nullptr; |
| + if (!initialize_proc_thread_attribute_list || !update_proc_thread_attribute) { |
| + // The OS doesn’t allow handle inheritance to be restricted, so the handler |
| + // will inherit every inheritable handle. |
| + creation_flags = 0; |
| + startup_info.StartupInfo.cb = sizeof(startup_info.StartupInfo); |
| + } else { |
| + // Restrict handle inheritance to just those needed in the handler. |
| + |
| + creation_flags = EXTENDED_STARTUPINFO_PRESENT; |
| + startup_info.StartupInfo.cb = sizeof(startup_info); |
| + SIZE_T size; |
| + rv = initialize_proc_thread_attribute_list(nullptr, 1, 0, &size); |
| + if (rv) { |
| + LOG(ERROR) << "InitializeProcThreadAttributeList (size) succeeded, " |
| + "expected failure"; |
| + return false; |
| + } else if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) { |
| + PLOG(ERROR) << "InitializeProcThreadAttributeList (size)"; |
| + return false; |
| + } |
| + |
| + proc_thread_attribute_list_storage.reset(new uint8_t[size]); |
| + startup_info.lpAttributeList = |
| + reinterpret_cast<PPROC_THREAD_ATTRIBUTE_LIST>( |
| + proc_thread_attribute_list_storage.get()); |
| + rv = initialize_proc_thread_attribute_list( |
| + startup_info.lpAttributeList, 1, 0, &size); |
| + if (!rv) { |
| + PLOG(ERROR) << "InitializeProcThreadAttributeList"; |
| + return false; |
| + } |
| + proc_thread_attribute_list_owner.reset(startup_info.lpAttributeList); |
| + |
| + handle_list.reserve(4); |
| + handle_list.push_back(pipe_write); |
| + AddHandleToListIfValid(&handle_list, startup_info.StartupInfo.hStdInput); |
| + AddHandleToListIfValid(&handle_list, startup_info.StartupInfo.hStdOutput); |
| + AddHandleToListIfValid(&handle_list, startup_info.StartupInfo.hStdError); |
| + rv = update_proc_thread_attribute( |
| + startup_info.lpAttributeList, |
| + 0, |
| + PROC_THREAD_ATTRIBUTE_HANDLE_LIST, |
| + &handle_list[0], |
| + handle_list.size() * sizeof(handle_list[0]), |
| + nullptr, |
| + nullptr); |
| + if (!rv) { |
| + PLOG(ERROR) << "UpdateProcThreadAttribute"; |
| + return false; |
| + } |
| + } |
| + |
| PROCESS_INFORMATION process_info; |
| rv = CreateProcess(handler.value().c_str(), |
| &command_line[0], |
| nullptr, |
| nullptr, |
| true, |
| - 0, |
| + creation_flags, |
| nullptr, |
| nullptr, |
| - &startup_info, |
| + &startup_info.StartupInfo, |
| &process_info); |
| if (!rv) { |
| PLOG(ERROR) << "CreateProcess"; |