Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
1 // Copyright (c) 2009 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.
5 // We need extended process and thread attribute support
6 #undef _WIN32_WINNT
7 #define _WIN32_WINNT 0x0600
9 #include "base/process_util.h"
11 #include <windows.h>
12 #include <winternl.h>
13 #include <psapi.h>
15 #include "base/debug_util.h"
16 #include "base/histogram.h"
17 #include "base/logging.h"
18 #include "base/scoped_handle_win.h"
19 #include "base/scoped_ptr.h"
20 #include "base/win_util.h"
22 #include <algorithm>
24 namespace {
26 // System pagesize. This value remains constant on x86/64 architectures.
27 const int PAGESIZE_KB = 4;
29 // HeapSetInformation function pointer.
30 typedef BOOL (WINAPI* HeapSetFn)(HANDLE, HEAP_INFORMATION_CLASS, PVOID, SIZE_T);
32 typedef BOOL (WINAPI * InitializeProcThreadAttributeListFn)(
33 LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList,
34 DWORD dwAttributeCount,
35 DWORD dwFlags,
36 PSIZE_T lpSize
37 );
39 typedef BOOL (WINAPI * DeleteProcThreadAttributeListFn)(
40 LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList
41 );
43 typedef BOOL (WINAPI * UpdateProcThreadAttributeFn)(
44 LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList,
45 DWORD dwFlags,
46 DWORD_PTR Attribute,
47 PVOID lpValue,
48 SIZE_T cbSize,
49 PVOID lpPreviousValue,
50 PSIZE_T lpReturnSize
51 );
53 static InitializeProcThreadAttributeListFn InitializeProcThreadAttributeListPtr;
54 static DeleteProcThreadAttributeListFn DeleteProcThreadAttributeListPtr;
55 static UpdateProcThreadAttributeFn UpdateProcThreadAttributePtr;
57 static mozilla::EnvironmentLog gProcessLog("MOZ_PROCESS_LOG");
59 } // namespace
61 namespace base {
63 ProcessId GetCurrentProcId() {
64 return ::GetCurrentProcessId();
65 }
67 ProcessHandle GetCurrentProcessHandle() {
68 return ::GetCurrentProcess();
69 }
71 bool OpenProcessHandle(ProcessId pid, ProcessHandle* handle) {
72 // TODO(phajdan.jr): Take even more permissions out of this list.
73 ProcessHandle result = OpenProcess(PROCESS_DUP_HANDLE |
74 PROCESS_TERMINATE |
75 PROCESS_QUERY_INFORMATION |
76 SYNCHRONIZE,
77 FALSE, pid);
79 if (result == INVALID_HANDLE_VALUE)
80 return false;
82 *handle = result;
83 return true;
84 }
86 bool OpenPrivilegedProcessHandle(ProcessId pid, ProcessHandle* handle) {
87 ProcessHandle result = OpenProcess(PROCESS_DUP_HANDLE |
88 PROCESS_TERMINATE |
89 PROCESS_QUERY_INFORMATION |
90 PROCESS_VM_READ |
91 SYNCHRONIZE,
92 FALSE, pid);
94 if (result == INVALID_HANDLE_VALUE)
95 return false;
97 *handle = result;
98 return true;
99 }
101 void CloseProcessHandle(ProcessHandle process) {
102 // closing a handle twice on Windows can be catastrophic - after the first
103 // close the handle value may be reused, so the second close will kill that
104 // other new handle.
105 BOOL ok = CloseHandle(process);
106 DCHECK(ok);
107 }
109 // Helper for GetProcId()
110 bool GetProcIdViaGetProcessId(ProcessHandle process, DWORD* id) {
111 // Dynamically get a pointer to GetProcessId().
112 typedef DWORD (WINAPI *GetProcessIdFunction)(HANDLE);
113 static GetProcessIdFunction GetProcessIdPtr = NULL;
114 static bool initialize_get_process_id = true;
115 if (initialize_get_process_id) {
116 initialize_get_process_id = false;
117 HMODULE kernel32_handle = GetModuleHandle(L"kernel32.dll");
118 if (!kernel32_handle) {
119 NOTREACHED();
120 return false;
121 }
122 GetProcessIdPtr = reinterpret_cast<GetProcessIdFunction>(GetProcAddress(
123 kernel32_handle, "GetProcessId"));
124 }
125 if (!GetProcessIdPtr)
126 return false;
127 // Ask for the process ID.
128 *id = (*GetProcessIdPtr)(process);
129 return true;
130 }
132 // Helper for GetProcId()
133 bool GetProcIdViaNtQueryInformationProcess(ProcessHandle process, DWORD* id) {
134 // Dynamically get a pointer to NtQueryInformationProcess().
135 typedef NTSTATUS (WINAPI *NtQueryInformationProcessFunction)(
136 HANDLE, PROCESSINFOCLASS, PVOID, ULONG, PULONG);
137 static NtQueryInformationProcessFunction NtQueryInformationProcessPtr = NULL;
138 static bool initialize_query_information_process = true;
139 if (initialize_query_information_process) {
140 initialize_query_information_process = false;
141 // According to nsylvain, ntdll.dll is guaranteed to be loaded, even though
142 // the Windows docs seem to imply that you should LoadLibrary() it.
143 HMODULE ntdll_handle = GetModuleHandle(L"ntdll.dll");
144 if (!ntdll_handle) {
145 NOTREACHED();
146 return false;
147 }
148 NtQueryInformationProcessPtr =
149 reinterpret_cast<NtQueryInformationProcessFunction>(GetProcAddress(
150 ntdll_handle, "NtQueryInformationProcess"));
151 }
152 if (!NtQueryInformationProcessPtr)
153 return false;
154 // Ask for the process ID.
155 PROCESS_BASIC_INFORMATION info;
156 ULONG bytes_returned;
157 NTSTATUS status = (*NtQueryInformationProcessPtr)(process,
158 ProcessBasicInformation,
159 &info, sizeof info,
160 &bytes_returned);
161 if (!SUCCEEDED(status) || (bytes_returned != (sizeof info)))
162 return false;
164 *id = static_cast<DWORD>(info.UniqueProcessId);
165 return true;
166 }
168 ProcessId GetProcId(ProcessHandle process) {
169 // Get a handle to |process| that has PROCESS_QUERY_INFORMATION rights.
170 HANDLE current_process = GetCurrentProcess();
171 HANDLE process_with_query_rights;
172 if (DuplicateHandle(current_process, process, current_process,
173 &process_with_query_rights, PROCESS_QUERY_INFORMATION,
174 false, 0)) {
175 // Try to use GetProcessId(), if it exists. Fall back on
176 // NtQueryInformationProcess() otherwise (< Win XP SP1).
177 DWORD id;
178 bool success =
179 GetProcIdViaGetProcessId(process_with_query_rights, &id) ||
180 GetProcIdViaNtQueryInformationProcess(process_with_query_rights, &id);
181 CloseHandle(process_with_query_rights);
182 if (success)
183 return id;
184 }
186 // We're screwed.
187 NOTREACHED();
188 return 0;
189 }
191 // from sandbox_policy_base.cc in a later version of the chromium ipc code...
192 bool IsInheritableHandle(HANDLE handle) {
193 if (!handle)
194 return false;
195 if (handle == INVALID_HANDLE_VALUE)
196 return false;
197 // File handles (FILE_TYPE_DISK) and pipe handles are known to be
198 // inheritable. Console handles (FILE_TYPE_CHAR) are not
199 // inheritable via PROC_THREAD_ATTRIBUTE_HANDLE_LIST.
200 DWORD handle_type = GetFileType(handle);
201 return handle_type == FILE_TYPE_DISK || handle_type == FILE_TYPE_PIPE;
202 }
204 void LoadThreadAttributeFunctions() {
205 HMODULE kernel32 = GetModuleHandle(L"kernel32.dll");
206 InitializeProcThreadAttributeListPtr =
207 reinterpret_cast<InitializeProcThreadAttributeListFn>
208 (GetProcAddress(kernel32, "InitializeProcThreadAttributeList"));
209 DeleteProcThreadAttributeListPtr =
210 reinterpret_cast<DeleteProcThreadAttributeListFn>
211 (GetProcAddress(kernel32, "DeleteProcThreadAttributeList"));
212 UpdateProcThreadAttributePtr =
213 reinterpret_cast<UpdateProcThreadAttributeFn>
214 (GetProcAddress(kernel32, "UpdateProcThreadAttribute"));
215 }
217 // Creates and returns a "thread attribute list" to pass to the child process.
218 // On return, is a pointer to a THREAD_ATTRIBUTE_LIST or NULL if either the
219 // functions we need aren't available (eg, XP or earlier) or the functions we
220 // need failed.
221 // The result of this function must be passed to FreeThreadAttributeList.
222 // Note that the pointer to the HANDLE array ends up embedded in the result of
223 // this function and must stay alive until FreeThreadAttributeList is called,
224 // hence it is passed in so the owner is the caller of this function.
225 LPPROC_THREAD_ATTRIBUTE_LIST CreateThreadAttributeList(HANDLE *handlesToInherit,
226 int handleCount) {
227 if (!InitializeProcThreadAttributeListPtr ||
228 !DeleteProcThreadAttributeListPtr ||
229 !UpdateProcThreadAttributePtr)
230 LoadThreadAttributeFunctions();
231 // shouldn't happen as we are only called for Vista+, but better safe than sorry...
232 if (!InitializeProcThreadAttributeListPtr ||
233 !DeleteProcThreadAttributeListPtr ||
234 !UpdateProcThreadAttributePtr)
235 return NULL;
237 SIZE_T threadAttrSize;
238 LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList;
240 if (!(*InitializeProcThreadAttributeListPtr)(NULL, 1, 0, &threadAttrSize) &&
241 GetLastError() != ERROR_INSUFFICIENT_BUFFER)
242 goto fail;
243 lpAttributeList = reinterpret_cast<LPPROC_THREAD_ATTRIBUTE_LIST>
244 (malloc(threadAttrSize));
245 if (!lpAttributeList ||
246 !(*InitializeProcThreadAttributeListPtr)(lpAttributeList, 1, 0, &threadAttrSize))
247 goto fail;
249 if (!(*UpdateProcThreadAttributePtr)(lpAttributeList,
250 0, PROC_THREAD_ATTRIBUTE_HANDLE_LIST,
251 handlesToInherit,
252 sizeof(handlesToInherit[0]) * handleCount,
253 NULL, NULL)) {
254 (*DeleteProcThreadAttributeListPtr)(lpAttributeList);
255 goto fail;
256 }
257 return lpAttributeList;
259 fail:
260 if (lpAttributeList)
261 free(lpAttributeList);
262 return NULL;
263 }
265 // Frees the data returned by CreateThreadAttributeList.
266 void FreeThreadAttributeList(LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList) {
267 // must be impossible to get a NULL DeleteProcThreadAttributeListPtr, as
268 // we already checked it existed when creating the data we are now freeing.
269 (*DeleteProcThreadAttributeListPtr)(lpAttributeList);
270 free(lpAttributeList);
271 }
273 bool LaunchApp(const std::wstring& cmdline,
274 bool wait, bool start_hidden, ProcessHandle* process_handle) {
276 // We want to inherit the std handles so dump() statements and assertion
277 // messages in the child process can be seen - but we *do not* want to
278 // blindly have all handles inherited. Vista and later has a technique
279 // where only specified handles are inherited - so we use this technique if
280 // we can. If that technique isn't available (or it fails), we just don't
281 // inherit anything. This means that dump() etc isn't going to be seen on
282 // XP release builds, but that's OK (developers who really care can run a
283 // debug build on XP, where the processes are marked as "console" apps, so
284 // things work without these hoops)
285 DWORD dwCreationFlags = 0;
286 BOOL bInheritHandles = FALSE;
287 // We use a STARTUPINFOEX, but if we can't do the thread attribute thing, we
288 // just pass the size of a STARTUPINFO.
289 STARTUPINFOEX startup_info_ex;
290 ZeroMemory(&startup_info_ex, sizeof(startup_info_ex));
291 STARTUPINFO &startup_info = startup_info_ex.StartupInfo;
292 startup_info.cb = sizeof(startup_info);
293 startup_info.dwFlags = STARTF_USESHOWWINDOW;
294 startup_info.wShowWindow = start_hidden ? SW_HIDE : SW_SHOW;
296 LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList = NULL;
297 // Don't even bother trying pre-Vista...
298 if (win_util::GetWinVersion() >= win_util::WINVERSION_VISTA) {
299 // setup our handle array first - if we end up with no handles that can
300 // be inherited we can avoid trying to do the ThreadAttributeList dance...
301 HANDLE handlesToInherit[2];
302 int handleCount = 0;
303 HANDLE stdOut = ::GetStdHandle(STD_OUTPUT_HANDLE);
304 HANDLE stdErr = ::GetStdHandle(STD_ERROR_HANDLE);
306 if (IsInheritableHandle(stdOut))
307 handlesToInherit[handleCount++] = stdOut;
308 if (stdErr != stdOut && IsInheritableHandle(stdErr))
309 handlesToInherit[handleCount++] = stdErr;
311 if (handleCount)
312 lpAttributeList = CreateThreadAttributeList(handlesToInherit, handleCount);
313 }
315 if (lpAttributeList) {
316 // it's safe to inherit handles, so arrange for that...
317 startup_info.cb = sizeof(startup_info_ex);
318 startup_info.dwFlags |= STARTF_USESTDHANDLES;
319 startup_info.hStdOutput = ::GetStdHandle(STD_OUTPUT_HANDLE);
320 startup_info.hStdError = ::GetStdHandle(STD_ERROR_HANDLE);
321 startup_info.hStdInput = INVALID_HANDLE_VALUE;
322 startup_info_ex.lpAttributeList = lpAttributeList;
323 dwCreationFlags |= EXTENDED_STARTUPINFO_PRESENT;
324 bInheritHandles = TRUE;
325 }
326 PROCESS_INFORMATION process_info;
327 BOOL createdOK = CreateProcess(NULL,
328 const_cast<wchar_t*>(cmdline.c_str()), NULL, NULL,
329 bInheritHandles, dwCreationFlags, NULL, NULL,
330 &startup_info, &process_info);
331 if (lpAttributeList)
332 FreeThreadAttributeList(lpAttributeList);
333 if (!createdOK)
334 return false;
336 gProcessLog.print("==> process %d launched child process %d (%S)\n",
337 GetCurrentProcId(),
338 process_info.dwProcessId,
339 cmdline.c_str());
341 // Handles must be closed or they will leak
342 CloseHandle(process_info.hThread);
344 if (wait)
345 WaitForSingleObject(process_info.hProcess, INFINITE);
347 // If the caller wants the process handle, we won't close it.
348 if (process_handle) {
349 *process_handle = process_info.hProcess;
350 } else {
351 CloseHandle(process_info.hProcess);
352 }
353 return true;
354 }
356 bool LaunchApp(const CommandLine& cl,
357 bool wait, bool start_hidden, ProcessHandle* process_handle) {
358 return LaunchApp(cl.command_line_string(), wait,
359 start_hidden, process_handle);
360 }
362 bool KillProcess(ProcessHandle process, int exit_code, bool wait) {
363 bool result = (TerminateProcess(process, exit_code) != FALSE);
364 if (result && wait) {
365 // The process may not end immediately due to pending I/O
366 if (WAIT_OBJECT_0 != WaitForSingleObject(process, 60 * 1000))
367 DLOG(ERROR) << "Error waiting for process exit: " << GetLastError();
368 } else if (!result) {
369 DLOG(ERROR) << "Unable to terminate process: " << GetLastError();
370 }
371 return result;
372 }
374 bool DidProcessCrash(bool* child_exited, ProcessHandle handle) {
375 DWORD exitcode = 0;
377 if (child_exited)
378 *child_exited = true; // On Windows it an error to call this function if
379 // the child hasn't already exited.
380 if (!::GetExitCodeProcess(handle, &exitcode)) {
381 NOTREACHED();
382 return false;
383 }
384 if (exitcode == STILL_ACTIVE) {
385 // The process is likely not dead or it used 0x103 as exit code.
386 NOTREACHED();
387 return false;
388 }
390 // Warning, this is not generic code; it heavily depends on the way
391 // the rest of the code kills a process.
393 if (exitcode == PROCESS_END_NORMAL_TERMINATON ||
394 exitcode == PROCESS_END_KILLED_BY_USER ||
395 exitcode == PROCESS_END_PROCESS_WAS_HUNG ||
396 exitcode == 0xC0000354 || // STATUS_DEBUGGER_INACTIVE.
397 exitcode == 0xC000013A || // Control-C/end session.
398 exitcode == 0x40010004) { // Debugger terminated process/end session.
399 return false;
400 }
402 return true;
403 }
405 void SetCurrentProcessPrivileges(ChildPrivileges privs) {
407 }
409 NamedProcessIterator::NamedProcessIterator(const std::wstring& executable_name,
410 const ProcessFilter* filter)
411 : started_iteration_(false),
412 executable_name_(executable_name),
413 filter_(filter) {
414 snapshot_ = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
415 }
417 NamedProcessIterator::~NamedProcessIterator() {
418 CloseHandle(snapshot_);
419 }
422 const ProcessEntry* NamedProcessIterator::NextProcessEntry() {
423 bool result = false;
424 do {
425 result = CheckForNextProcess();
426 } while (result && !IncludeEntry());
428 if (result) {
429 return &entry_;
430 }
432 return NULL;
433 }
435 bool NamedProcessIterator::CheckForNextProcess() {
436 InitProcessEntry(&entry_);
438 if (!started_iteration_) {
439 started_iteration_ = true;
440 return !!Process32First(snapshot_, &entry_);
441 }
443 return !!Process32Next(snapshot_, &entry_);
444 }
446 bool NamedProcessIterator::IncludeEntry() {
447 return _wcsicmp(executable_name_.c_str(), entry_.szExeFile) == 0 &&
448 (!filter_ || filter_->Includes(entry_.th32ProcessID,
449 entry_.th32ParentProcessID));
450 }
452 void NamedProcessIterator::InitProcessEntry(ProcessEntry* entry) {
453 memset(entry, 0, sizeof(*entry));
454 entry->dwSize = sizeof(*entry);
455 }
457 ///////////////////////////////////////////////////////////////////////////////
458 // ProcesMetrics
460 ProcessMetrics::ProcessMetrics(ProcessHandle process) : process_(process),
461 last_time_(0),
462 last_system_time_(0) {
463 SYSTEM_INFO system_info;
464 GetSystemInfo(&system_info);
465 processor_count_ = system_info.dwNumberOfProcessors;
466 }
468 // static
469 ProcessMetrics* ProcessMetrics::CreateProcessMetrics(ProcessHandle process) {
470 return new ProcessMetrics(process);
471 }
473 ProcessMetrics::~ProcessMetrics() { }
475 static uint64_t FileTimeToUTC(const FILETIME& ftime) {
476 LARGE_INTEGER li;
477 li.LowPart = ftime.dwLowDateTime;
478 li.HighPart = ftime.dwHighDateTime;
479 return li.QuadPart;
480 }
482 int ProcessMetrics::GetCPUUsage() {
483 FILETIME now;
484 FILETIME creation_time;
485 FILETIME exit_time;
486 FILETIME kernel_time;
487 FILETIME user_time;
489 GetSystemTimeAsFileTime(&now);
491 if (!GetProcessTimes(process_, &creation_time, &exit_time,
492 &kernel_time, &user_time)) {
493 // We don't assert here because in some cases (such as in the Task Manager)
494 // we may call this function on a process that has just exited but we have
495 // not yet received the notification.
496 return 0;
497 }
498 int64_t system_time = (FileTimeToUTC(kernel_time) + FileTimeToUTC(user_time)) /
499 processor_count_;
500 int64_t time = FileTimeToUTC(now);
502 if ((last_system_time_ == 0) || (last_time_ == 0)) {
503 // First call, just set the last values.
504 last_system_time_ = system_time;
505 last_time_ = time;
506 return 0;
507 }
509 int64_t system_time_delta = system_time - last_system_time_;
510 int64_t time_delta = time - last_time_;
511 DCHECK(time_delta != 0);
512 if (time_delta == 0)
513 return 0;
515 // We add time_delta / 2 so the result is rounded.
516 int cpu = static_cast<int>((system_time_delta * 100 + time_delta / 2) /
517 time_delta);
519 last_system_time_ = system_time;
520 last_time_ = time;
522 return cpu;
523 }
525 } // namespace base