Avi Drissman | e4622aa | 2022-09-08 20:36:06 | [diff] [blame] | 1 | // Copyright 2013 The Chromium Authors |
[email protected] | 307af21 | 2013-07-10 18:36:09 | [diff] [blame] | 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 "base/process/kill.h" |
| 6 | |
[email protected] | 307af21 | 2013-07-10 18:36:09 | [diff] [blame] | 7 | #include <windows.h> |
Bruce Dawson | a1e1cfcb | 2022-11-22 20:04:35 | [diff] [blame] | 8 | |
avi | beced7c | 2015-12-24 06:47:59 | [diff] [blame] | 9 | #include <io.h> |
| 10 | #include <stdint.h> |
[email protected] | 307af21 | 2013-07-10 18:36:09 | [diff] [blame] | 11 | |
Takuto Ikuta | c8d6b16f | 2024-04-15 16:59:19 | [diff] [blame] | 12 | #include <algorithm> |
| 13 | |
[email protected] | 307af21 | 2013-07-10 18:36:09 | [diff] [blame] | 14 | #include "base/logging.h" |
Hans Wennborg | afeb390 | 2020-06-17 14:42:29 | [diff] [blame] | 15 | #include "base/notreached.h" |
wfh | fa40c272 | 2016-07-26 01:12:28 | [diff] [blame] | 16 | #include "base/process/memory.h" |
[email protected] | 307af21 | 2013-07-10 18:36:09 | [diff] [blame] | 17 | #include "base/process/process_iterator.h" |
[email protected] | 307af21 | 2013-07-10 18:36:09 | [diff] [blame] | 18 | |
| 19 | namespace base { |
| 20 | |
[email protected] | 307af21 | 2013-07-10 18:36:09 | [diff] [blame] | 21 | TerminationStatus GetTerminationStatus(ProcessHandle handle, int* exit_code) { |
Wez | 05c2c68 | 2017-08-17 16:20:11 | [diff] [blame] | 22 | DCHECK(exit_code); |
| 23 | |
[email protected] | 307af21 | 2013-07-10 18:36:09 | [diff] [blame] | 24 | DWORD tmp_exit_code = 0; |
| 25 | |
| 26 | if (!::GetExitCodeProcess(handle, &tmp_exit_code)) { |
[email protected] | ad8cfa9 | 2014-05-21 20:06:23 | [diff] [blame] | 27 | DPLOG(FATAL) << "GetExitCodeProcess() failed"; |
Wez | 05c2c68 | 2017-08-17 16:20:11 | [diff] [blame] | 28 | |
| 29 | // This really is a random number. We haven't received any |
| 30 | // information about the exit code, presumably because this |
| 31 | // process doesn't have permission to get the exit code, or |
| 32 | // because of some other cause for GetExitCodeProcess to fail |
| 33 | // (MSDN docs don't give the possible failure error codes for |
| 34 | // this function, so it could be anything). But we don't want |
| 35 | // to leave exit_code uninitialized, since that could cause |
| 36 | // random interpretations of the exit code. So we assume it |
| 37 | // terminated "normally" in this case. |
Bruce Dawson | ec015851 | 2017-11-16 09:10:40 | [diff] [blame] | 38 | *exit_code = win::kNormalTerminationExitCode; |
Wez | 05c2c68 | 2017-08-17 16:20:11 | [diff] [blame] | 39 | |
[email protected] | 307af21 | 2013-07-10 18:36:09 | [diff] [blame] | 40 | // Assume the child has exited normally if we can't get the exit |
| 41 | // code. |
| 42 | return TERMINATION_STATUS_NORMAL_TERMINATION; |
| 43 | } |
| 44 | if (tmp_exit_code == STILL_ACTIVE) { |
| 45 | DWORD wait_result = WaitForSingleObject(handle, 0); |
| 46 | if (wait_result == WAIT_TIMEOUT) { |
Peter Kasting | 4d3664b | 2022-06-16 19:27:54 | [diff] [blame] | 47 | *exit_code = static_cast<int>(wait_result); |
[email protected] | 307af21 | 2013-07-10 18:36:09 | [diff] [blame] | 48 | return TERMINATION_STATUS_STILL_RUNNING; |
| 49 | } |
| 50 | |
| 51 | if (wait_result == WAIT_FAILED) { |
[email protected] | ad8cfa9 | 2014-05-21 20:06:23 | [diff] [blame] | 52 | DPLOG(ERROR) << "WaitForSingleObject() failed"; |
Sorin Jianu | 08f9612 | 2024-03-23 00:42:44 | [diff] [blame] | 53 | *exit_code = static_cast<int>(wait_result); |
[email protected] | 307af21 | 2013-07-10 18:36:09 | [diff] [blame] | 54 | } else { |
| 55 | DCHECK_EQ(WAIT_OBJECT_0, wait_result); |
Sorin Jianu | 08f9612 | 2024-03-23 00:42:44 | [diff] [blame] | 56 | DLOG(ERROR) << "The process used 0x103 (STILL_ACTIVE) as exit code."; |
| 57 | *exit_code = static_cast<int>(tmp_exit_code); |
[email protected] | 307af21 | 2013-07-10 18:36:09 | [diff] [blame] | 58 | } |
| 59 | |
| 60 | return TERMINATION_STATUS_ABNORMAL_TERMINATION; |
| 61 | } |
| 62 | |
Peter Kasting | 4d3664b | 2022-06-16 19:27:54 | [diff] [blame] | 63 | *exit_code = static_cast<int>(tmp_exit_code); |
[email protected] | 307af21 | 2013-07-10 18:36:09 | [diff] [blame] | 64 | |
Will Harris | 07925d1 | 2019-10-31 03:03:05 | [diff] [blame] | 65 | // clang-format off |
[email protected] | 307af21 | 2013-07-10 18:36:09 | [diff] [blame] | 66 | switch (tmp_exit_code) { |
Bruce Dawson | ec015851 | 2017-11-16 09:10:40 | [diff] [blame] | 67 | case win::kNormalTerminationExitCode: |
[email protected] | 307af21 | 2013-07-10 18:36:09 | [diff] [blame] | 68 | return TERMINATION_STATUS_NORMAL_TERMINATION; |
Bruce Dawson | ec015851 | 2017-11-16 09:10:40 | [diff] [blame] | 69 | case win::kDebuggerInactiveExitCode: // STATUS_DEBUGGER_INACTIVE. |
| 70 | case win::kKeyboardInterruptExitCode: // Control-C/end session. |
| 71 | case win::kDebuggerTerminatedExitCode: // Debugger terminated process. |
| 72 | case win::kProcessKilledExitCode: // Task manager kill. |
[email protected] | 307af21 | 2013-07-10 18:36:09 | [diff] [blame] | 73 | return TERMINATION_STATUS_PROCESS_WAS_KILLED; |
Bruce Dawson | ec015851 | 2017-11-16 09:10:40 | [diff] [blame] | 74 | case win::kSandboxFatalMemoryExceeded: // Terminated process due to |
| 75 | // exceeding the sandbox job |
| 76 | // object memory limits. |
| 77 | case win::kOomExceptionCode: // Ran out of memory. |
wfh | fa40c272 | 2016-07-26 01:12:28 | [diff] [blame] | 78 | return TERMINATION_STATUS_OOM; |
Will Harris | 07925d1 | 2019-10-31 03:03:05 | [diff] [blame] | 79 | // This exit code means the process failed an OS integrity check. |
| 80 | // This is tested in ProcessMitigationsTest.* in sandbox. |
| 81 | case win::kStatusInvalidImageHashExitCode: |
| 82 | return TERMINATION_STATUS_INTEGRITY_FAILURE; |
[email protected] | 307af21 | 2013-07-10 18:36:09 | [diff] [blame] | 83 | default: |
| 84 | // All other exit codes indicate crashes. |
| 85 | return TERMINATION_STATUS_PROCESS_CRASHED; |
| 86 | } |
Will Harris | 07925d1 | 2019-10-31 03:03:05 | [diff] [blame] | 87 | // clang-format on |
[email protected] | 307af21 | 2013-07-10 18:36:09 | [diff] [blame] | 88 | } |
| 89 | |
[email protected] | 307af21 | 2013-07-10 18:36:09 | [diff] [blame] | 90 | bool WaitForProcessesToExit(const FilePath::StringType& executable_name, |
rvargas | 2f70a15 | 2015-02-24 00:28:11 | [diff] [blame] | 91 | TimeDelta wait, |
[email protected] | 307af21 | 2013-07-10 18:36:09 | [diff] [blame] | 92 | const ProcessFilter* filter) { |
[email protected] | 307af21 | 2013-07-10 18:36:09 | [diff] [blame] | 93 | bool result = true; |
| 94 | DWORD start_time = GetTickCount(); |
| 95 | |
| 96 | NamedProcessIterator iter(executable_name, filter); |
[email protected] | ed8e57da | 2014-07-03 07:03:39 | [diff] [blame] | 97 | for (const ProcessEntry* entry = iter.NextProcessEntry(); entry; |
| 98 | entry = iter.NextProcessEntry()) { |
avi | beced7c | 2015-12-24 06:47:59 | [diff] [blame] | 99 | DWORD remaining_wait = static_cast<DWORD>( |
| 100 | std::max(static_cast<int64_t>(0), |
| 101 | wait.InMilliseconds() - (GetTickCount() - start_time))); |
Peter Kasting | 134ef9af | 2024-12-28 02:30:09 | [diff] [blame] | 102 | HANDLE process = OpenProcess(SYNCHRONIZE, FALSE, entry->th32ProcessID); |
brucedawson | d350943 | 2015-09-18 18:28:13 | [diff] [blame] | 103 | DWORD wait_result = WaitForSingleObject(process, remaining_wait); |
| 104 | CloseHandle(process); |
[email protected] | ed8e57da | 2014-07-03 07:03:39 | [diff] [blame] | 105 | result &= (wait_result == WAIT_OBJECT_0); |
[email protected] | 307af21 | 2013-07-10 18:36:09 | [diff] [blame] | 106 | } |
| 107 | |
| 108 | return result; |
| 109 | } |
| 110 | |
[email protected] | 307af21 | 2013-07-10 18:36:09 | [diff] [blame] | 111 | bool CleanupProcesses(const FilePath::StringType& executable_name, |
rvargas | 2f70a15 | 2015-02-24 00:28:11 | [diff] [blame] | 112 | TimeDelta wait, |
[email protected] | 307af21 | 2013-07-10 18:36:09 | [diff] [blame] | 113 | int exit_code, |
| 114 | const ProcessFilter* filter) { |
Peter Kasting | 134ef9af | 2024-12-28 02:30:09 | [diff] [blame] | 115 | if (WaitForProcessesToExit(executable_name, wait, filter)) { |
[email protected] | ed8e57da | 2014-07-03 07:03:39 | [diff] [blame] | 116 | return true; |
Peter Kasting | 134ef9af | 2024-12-28 02:30:09 | [diff] [blame] | 117 | } |
[email protected] | ed8e57da | 2014-07-03 07:03:39 | [diff] [blame] | 118 | KillProcesses(executable_name, exit_code, filter); |
| 119 | return false; |
[email protected] | 307af21 | 2013-07-10 18:36:09 | [diff] [blame] | 120 | } |
| 121 | |
[email protected] | 307af21 | 2013-07-10 18:36:09 | [diff] [blame] | 122 | } // namespace base |