diff options
Diffstat (limited to '')
7 files changed, 848 insertions, 0 deletions
diff --git a/security/sandbox/chromium/base/process/environment_internal.cc b/security/sandbox/chromium/base/process/environment_internal.cc new file mode 100644 index 0000000000..357140fa6f --- /dev/null +++ b/security/sandbox/chromium/base/process/environment_internal.cc @@ -0,0 +1,128 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/process/environment_internal.h" + +#include <stddef.h> + +#include <vector> + +namespace base { +namespace internal { + +namespace { + +#if defined(OS_POSIX) || defined(OS_FUCHSIA) || defined(OS_WIN) +// Parses a null-terminated input string of an environment block. The key is +// placed into the given string, and the total length of the line, including +// the terminating null, is returned. +size_t ParseEnvLine(const NativeEnvironmentString::value_type* input, + NativeEnvironmentString* key) { + // Skip to the equals or end of the string, this is the key. + size_t cur = 0; + while (input[cur] && input[cur] != '=') + cur++; + *key = NativeEnvironmentString(&input[0], cur); + + // Now just skip to the end of the string. + while (input[cur]) + cur++; + return cur + 1; +} +#endif + +} // namespace + +#if defined(OS_POSIX) || defined(OS_FUCHSIA) + +std::unique_ptr<char* []> AlterEnvironment(const char* const* const env, + const EnvironmentMap& changes) { + std::string value_storage; // Holds concatenated null-terminated strings. + std::vector<size_t> result_indices; // Line indices into value_storage. + + // First build up all of the unchanged environment strings. These are + // null-terminated of the form "key=value". + std::string key; + for (size_t i = 0; env[i]; i++) { + size_t line_length = ParseEnvLine(env[i], &key); + + // Keep only values not specified in the change vector. + auto found_change = changes.find(key); + if (found_change == changes.end()) { + result_indices.push_back(value_storage.size()); + value_storage.append(env[i], line_length); + } + } + + // Now append all modified and new values. + for (const auto& i : changes) { + if (!i.second.empty()) { + result_indices.push_back(value_storage.size()); + value_storage.append(i.first); + value_storage.push_back('='); + value_storage.append(i.second); + value_storage.push_back(0); + } + } + + size_t pointer_count_required = + result_indices.size() + 1 + // Null-terminated array of pointers. + (value_storage.size() + sizeof(char*) - 1) / sizeof(char*); // Buffer. + std::unique_ptr<char*[]> result(new char*[pointer_count_required]); + + // The string storage goes after the array of pointers. + char* storage_data = + reinterpret_cast<char*>(&result.get()[result_indices.size() + 1]); + if (!value_storage.empty()) + memcpy(storage_data, value_storage.data(), value_storage.size()); + + // Fill array of pointers at the beginning of the result. + for (size_t i = 0; i < result_indices.size(); i++) + result[i] = &storage_data[result_indices[i]]; + result[result_indices.size()] = 0; // Null terminator. + + return result; +} + +#elif defined(OS_WIN) + +NativeEnvironmentString AlterEnvironment(const wchar_t* env, + const EnvironmentMap& changes) { + NativeEnvironmentString result; + + // First build up all of the unchanged environment strings. + const wchar_t* ptr = env; + while (*ptr) { + std::wstring key; + size_t line_length = ParseEnvLine(ptr, &key); + + // Keep only values not specified in the change vector. + if (changes.find(key) == changes.end()) { + result.append(ptr, line_length); + } + ptr += line_length; + } + + // Now append all modified and new values. + for (const auto& i : changes) { + // Windows environment blocks cannot handle keys or values with NULs. + CHECK_EQ(std::wstring::npos, i.first.find(L'\0')); + CHECK_EQ(std::wstring::npos, i.second.find(L'\0')); + if (!i.second.empty()) { + result += i.first; + result.push_back('='); + result += i.second; + result.push_back('\0'); + } + } + + // Add the terminating NUL. + result.push_back('\0'); + return result; +} + +#endif // OS_POSIX || OS_FUCHSIA + +} // namespace internal +} // namespace base diff --git a/security/sandbox/chromium/base/process/environment_internal.h b/security/sandbox/chromium/base/process/environment_internal.h new file mode 100644 index 0000000000..31338f1320 --- /dev/null +++ b/security/sandbox/chromium/base/process/environment_internal.h @@ -0,0 +1,52 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// This file contains internal routines that are called by other files in +// base/process/. + +#ifndef BASE_PROCESS_ENVIRONMENT_INTERNAL_H_ +#define BASE_PROCESS_ENVIRONMENT_INTERNAL_H_ + +#include <memory> + +#include "base/environment.h" +#include "build/build_config.h" + +namespace base { +namespace internal { + +#if defined(OS_POSIX) || defined(OS_FUCHSIA) +// Returns a modified environment vector constructed from the given environment +// and the list of changes given in |changes|. Each key in the environment is +// matched against the first element of the pairs. In the event of a match, the +// value is replaced by the second of the pair, unless the second is empty, in +// which case the key-value is removed. +// +// This POSIX version takes and returns a POSIX-style environment block, which +// is a null-terminated list of pointers to null-terminated strings. The +// returned array will have appended to it the storage for the array itself so +// there is only one pointer to manage, but this means that you can't copy the +// array without keeping the original around. +BASE_EXPORT std::unique_ptr<char*[]> AlterEnvironment( + const char* const* env, + const EnvironmentMap& changes); +#elif defined(OS_WIN) +// Returns a modified environment vector constructed from the given environment +// and the list of changes given in |changes|. Each key in the environment is +// matched against the first element of the pairs. In the event of a match, the +// value is replaced by the second of the pair, unless the second is empty, in +// which case the key-value is removed. +// +// This Windows version takes and returns a Windows-style environment block, +// which is a string containing several null-terminated strings followed by an +// extra terminating null character. So, e.g., the environment A=1 B=2 is +// represented as L"A=1\0B=2\0\0". +BASE_EXPORT NativeEnvironmentString +AlterEnvironment(const wchar_t* env, const EnvironmentMap& changes); +#endif // OS_* + +} // namespace internal +} // namespace base + +#endif // BASE_PROCESS_ENVIRONMENT_INTERNAL_H_ diff --git a/security/sandbox/chromium/base/process/kill.h b/security/sandbox/chromium/base/process/kill.h new file mode 100644 index 0000000000..70a04d97e5 --- /dev/null +++ b/security/sandbox/chromium/base/process/kill.h @@ -0,0 +1,162 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// This file contains routines to kill processes and get the exit code and +// termination status. + +#ifndef BASE_PROCESS_KILL_H_ +#define BASE_PROCESS_KILL_H_ + +#include "base/files/file_path.h" +#include "base/process/process.h" +#include "base/process/process_handle.h" +#include "base/time/time.h" +#include "build/build_config.h" + +namespace base { + +class ProcessFilter; + +#if defined(OS_WIN) +namespace win { + +// See definition in sandbox/win/src/sandbox_types.h +const DWORD kSandboxFatalMemoryExceeded = 7012; + +// Exit codes with special meanings on Windows. +const DWORD kNormalTerminationExitCode = 0; +const DWORD kDebuggerInactiveExitCode = 0xC0000354; +const DWORD kKeyboardInterruptExitCode = 0xC000013A; +const DWORD kDebuggerTerminatedExitCode = 0x40010004; +const DWORD kStatusInvalidImageHashExitCode = 0xC0000428; + +// This exit code is used by the Windows task manager when it kills a +// process. It's value is obviously not that unique, and it's +// surprising to me that the task manager uses this value, but it +// seems to be common practice on Windows to test for it as an +// indication that the task manager has killed something if the +// process goes away. +const DWORD kProcessKilledExitCode = 1; + +} // namespace win + +#endif // OS_WIN + +// Return status values from GetTerminationStatus. Don't use these as +// exit code arguments to KillProcess*(), use platform/application +// specific values instead. +enum TerminationStatus { + // clang-format off + TERMINATION_STATUS_NORMAL_TERMINATION, // zero exit status + TERMINATION_STATUS_ABNORMAL_TERMINATION, // non-zero exit status + TERMINATION_STATUS_PROCESS_WAS_KILLED, // e.g. SIGKILL or task manager kill + TERMINATION_STATUS_PROCESS_CRASHED, // e.g. Segmentation fault + TERMINATION_STATUS_STILL_RUNNING, // child hasn't exited yet +#if defined(OS_CHROMEOS) + // Used for the case when oom-killer kills a process on ChromeOS. + TERMINATION_STATUS_PROCESS_WAS_KILLED_BY_OOM, +#endif +#if defined(OS_ANDROID) + // On Android processes are spawned from the system Zygote and we do not get + // the termination status. We can't know if the termination was a crash or an + // oom kill for sure, but we can use status of the strong process bindings as + // a hint. + TERMINATION_STATUS_OOM_PROTECTED, // child was protected from oom kill +#endif + TERMINATION_STATUS_LAUNCH_FAILED, // child process never launched + TERMINATION_STATUS_OOM, // Process died due to oom +#if defined(OS_WIN) + // On Windows, the OS terminated process due to code integrity failure. + TERMINATION_STATUS_INTEGRITY_FAILURE, +#endif + TERMINATION_STATUS_MAX_ENUM + // clang-format on +}; + +// Attempts to kill all the processes on the current machine that were launched +// from the given executable name, ending them with the given exit code. If +// filter is non-null, then only processes selected by the filter are killed. +// Returns true if all processes were able to be killed off, false if at least +// one couldn't be killed. +BASE_EXPORT bool KillProcesses(const FilePath::StringType& executable_name, + int exit_code, + const ProcessFilter* filter); + +#if defined(OS_POSIX) +// Attempts to kill the process group identified by |process_group_id|. Returns +// true on success. +BASE_EXPORT bool KillProcessGroup(ProcessHandle process_group_id); +#endif // defined(OS_POSIX) + +// Get the termination status of the process by interpreting the +// circumstances of the child process' death. |exit_code| is set to +// the status returned by waitpid() on POSIX, and from GetExitCodeProcess() on +// Windows, and may not be null. Note that on Linux, this function +// will only return a useful result the first time it is called after +// the child exits (because it will reap the child and the information +// will no longer be available). +BASE_EXPORT TerminationStatus GetTerminationStatus(ProcessHandle handle, + int* exit_code); + +#if defined(OS_POSIX) +// Send a kill signal to the process and then wait for the process to exit +// and get the termination status. +// +// This is used in situations where it is believed that the process is dead +// or dying (because communication with the child process has been cut). +// In order to avoid erroneously returning that the process is still running +// because the kernel is still cleaning it up, this will wait for the process +// to terminate. In order to avoid the risk of hanging while waiting for the +// process to terminate, send a SIGKILL to the process before waiting for the +// termination status. +// +// Note that it is not an option to call WaitForExitCode and then +// GetTerminationStatus as the child will be reaped when WaitForExitCode +// returns, and this information will be lost. +// +BASE_EXPORT TerminationStatus GetKnownDeadTerminationStatus( + ProcessHandle handle, int* exit_code); + +#if defined(OS_LINUX) +// Spawns a thread to wait asynchronously for the child |process| to exit +// and then reaps it. +BASE_EXPORT void EnsureProcessGetsReaped(Process process); +#endif // defined(OS_LINUX) +#endif // defined(OS_POSIX) + +// Registers |process| to be asynchronously monitored for termination, forcibly +// terminated if necessary, and reaped on exit. The caller should have signalled +// |process| to exit before calling this API. The API will allow a couple of +// seconds grace period before forcibly terminating |process|. +// TODO(https://crbug.com/806451): The Mac implementation currently blocks the +// calling thread for up to two seconds. +BASE_EXPORT void EnsureProcessTerminated(Process process); + +// These are only sparingly used, and not needed on Fuchsia. They could be +// implemented if necessary. +#if !defined(OS_FUCHSIA) +// Wait for all the processes based on the named executable to exit. If filter +// is non-null, then only processes selected by the filter are waited on. +// Returns after all processes have exited or wait_milliseconds have expired. +// Returns true if all the processes exited, false otherwise. +BASE_EXPORT bool WaitForProcessesToExit( + const FilePath::StringType& executable_name, + base::TimeDelta wait, + const ProcessFilter* filter); + +// Waits a certain amount of time (can be 0) for all the processes with a given +// executable name to exit, then kills off any of them that are still around. +// If filter is non-null, then only processes selected by the filter are waited +// on. Killed processes are ended with the given exit code. Returns false if +// any processes needed to be killed, true if they all exited cleanly within +// the wait_milliseconds delay. +BASE_EXPORT bool CleanupProcesses(const FilePath::StringType& executable_name, + base::TimeDelta wait, + int exit_code, + const ProcessFilter* filter); +#endif // !defined(OS_FUCHSIA) + +} // namespace base + +#endif // BASE_PROCESS_KILL_H_ diff --git a/security/sandbox/chromium/base/process/memory.h b/security/sandbox/chromium/base/process/memory.h new file mode 100644 index 0000000000..ddbb9d957c --- /dev/null +++ b/security/sandbox/chromium/base/process/memory.h @@ -0,0 +1,89 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef BASE_PROCESS_MEMORY_H_ +#define BASE_PROCESS_MEMORY_H_ + +#include <stddef.h> + +#include "base/base_export.h" +#include "base/process/process_handle.h" +#include "build/build_config.h" + +namespace base { + +// Enables 'terminate on heap corruption' flag. Helps protect against heap +// overflow. Has no effect if the OS doesn't provide the necessary facility. +BASE_EXPORT void EnableTerminationOnHeapCorruption(); + +// Turns on process termination if memory runs out. +BASE_EXPORT void EnableTerminationOnOutOfMemory(); + +// Terminates process. Should be called only for out of memory errors. +// Crash reporting classifies such crashes as OOM. +BASE_EXPORT void TerminateBecauseOutOfMemory(size_t size); + +#if defined(OS_LINUX) || defined(OS_ANDROID) || defined(OS_AIX) +BASE_EXPORT extern size_t g_oom_size; + +// The maximum allowed value for the OOM score. +const int kMaxOomScore = 1000; + +// This adjusts /proc/<pid>/oom_score_adj so the Linux OOM killer will +// prefer to kill certain process types over others. The range for the +// adjustment is [-1000, 1000], with [0, 1000] being user accessible. +// If the Linux system doesn't support the newer oom_score_adj range +// of [0, 1000], then we revert to using the older oom_adj, and +// translate the given value into [0, 15]. Some aliasing of values +// may occur in that case, of course. +BASE_EXPORT bool AdjustOOMScore(ProcessId process, int score); +#endif + +namespace internal { +// Returns true if address-space was released. Some configurations reserve part +// of the process address-space for special allocations (e.g. WASM). +bool ReleaseAddressSpaceReservation(); +} // namespace internal + +#if defined(OS_WIN) +namespace win { + +// Custom Windows exception code chosen to indicate an out of memory error. +// See https://msdn.microsoft.com/en-us/library/het71c37.aspx. +// "To make sure that you do not define a code that conflicts with an existing +// exception code" ... "The resulting error code should therefore have the +// highest four bits set to hexadecimal E." +// 0xe0000008 was chosen arbitrarily, as 0x00000008 is ERROR_NOT_ENOUGH_MEMORY. +const DWORD kOomExceptionCode = 0xe0000008; + +} // namespace win +#endif + +namespace internal { + +// Handles out of memory, with the failed allocation |size|, or 0 when it is not +// known. +BASE_EXPORT void OnNoMemoryInternal(size_t size); + +} // namespace internal + +// Special allocator functions for callers that want to check for OOM. +// These will not abort if the allocation fails even if +// EnableTerminationOnOutOfMemory has been called. +// This can be useful for huge and/or unpredictable size memory allocations. +// Please only use this if you really handle the case when the allocation +// fails. Doing otherwise would risk security. +// These functions may still crash on OOM when running under memory tools, +// specifically ASan and other sanitizers. +// Return value tells whether the allocation succeeded. If it fails |result| is +// set to NULL, otherwise it holds the memory address. +BASE_EXPORT WARN_UNUSED_RESULT bool UncheckedMalloc(size_t size, + void** result); +BASE_EXPORT WARN_UNUSED_RESULT bool UncheckedCalloc(size_t num_items, + size_t size, + void** result); + +} // namespace base + +#endif // BASE_PROCESS_MEMORY_H_ diff --git a/security/sandbox/chromium/base/process/process.h b/security/sandbox/chromium/base/process/process.h new file mode 100644 index 0000000000..d6f8d83e36 --- /dev/null +++ b/security/sandbox/chromium/base/process/process.h @@ -0,0 +1,223 @@ +// Copyright 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef BASE_PROCESS_PROCESS_H_ +#define BASE_PROCESS_PROCESS_H_ + +#include "base/base_export.h" +#include "base/macros.h" +#include "base/process/process_handle.h" +#include "base/time/time.h" +#include "build/build_config.h" + +#if defined(OS_WIN) +#include "base/win/scoped_handle.h" +#endif + +#if defined(OS_FUCHSIA) +#include <lib/zx/process.h> +#endif + +#if defined(OS_MACOSX) +#include "base/feature_list.h" +#include "base/process/port_provider_mac.h" +#endif + +namespace base { + +#if defined(OS_MACOSX) +extern const Feature kMacAllowBackgroundingProcesses; +#endif + +// Provides a move-only encapsulation of a process. +// +// This object is not tied to the lifetime of the underlying process: the +// process may be killed and this object may still around, and it will still +// claim to be valid. The actual behavior in that case is OS dependent like so: +// +// Windows: The underlying ProcessHandle will be valid after the process dies +// and can be used to gather some information about that process, but most +// methods will obviously fail. +// +// POSIX: The underlying ProcessHandle is not guaranteed to remain valid after +// the process dies, and it may be reused by the system, which means that it may +// end up pointing to the wrong process. +class BASE_EXPORT Process { + public: + // On Windows, this takes ownership of |handle|. On POSIX, this does not take + // ownership of |handle|. + explicit Process(ProcessHandle handle = kNullProcessHandle); + + Process(Process&& other); + + // The destructor does not terminate the process. + ~Process(); + + Process& operator=(Process&& other); + + // Returns an object for the current process. + static Process Current(); + + // Returns a Process for the given |pid|. + static Process Open(ProcessId pid); + + // Returns a Process for the given |pid|. On Windows the handle is opened + // with more access rights and must only be used by trusted code (can read the + // address space and duplicate handles). + static Process OpenWithExtraPrivileges(ProcessId pid); + +#if defined(OS_WIN) + // Returns a Process for the given |pid|, using some |desired_access|. + // See ::OpenProcess documentation for valid |desired_access|. + static Process OpenWithAccess(ProcessId pid, DWORD desired_access); +#endif + + // Creates an object from a |handle| owned by someone else. + // Don't use this for new code. It is only intended to ease the migration to + // a strict ownership model. + // TODO(rvargas) crbug.com/417532: Remove this code. + static Process DeprecatedGetProcessFromHandle(ProcessHandle handle); + + // Returns true if processes can be backgrounded. + static bool CanBackgroundProcesses(); + + // Terminates the current process immediately with |exit_code|. + [[noreturn]] static void TerminateCurrentProcessImmediately(int exit_code); + + // Returns true if this objects represents a valid process. + bool IsValid() const; + + // Returns a handle for this process. There is no guarantee about when that + // handle becomes invalid because this object retains ownership. + ProcessHandle Handle() const; + + // Returns a second object that represents this process. + Process Duplicate() const; + + // Get the PID for this process. + ProcessId Pid() const; + +#if !defined(OS_ANDROID) + // Get the creation time for this process. Since the Pid can be reused after a + // process dies, it is useful to use both the Pid and the creation time to + // uniquely identify a process. + // + // Not available on Android because /proc/stat/ cannot be accessed on O+. + // https://issuetracker.google.com/issues/37140047 + Time CreationTime() const; +#endif // !defined(OS_ANDROID) + + // Returns true if this process is the current process. + bool is_current() const; + + // Close the process handle. This will not terminate the process. + void Close(); + + // Returns true if this process is still running. This is only safe on Windows + // (and maybe Fuchsia?), because the ProcessHandle will keep the zombie + // process information available until itself has been released. But on Posix, + // the OS may reuse the ProcessId. +#if defined(OS_WIN) + bool IsRunning() const { + return !WaitForExitWithTimeout(base::TimeDelta(), nullptr); + } +#endif + + // Terminates the process with extreme prejudice. The given |exit_code| will + // be the exit code of the process. If |wait| is true, this method will wait + // for up to one minute for the process to actually terminate. + // Returns true if the process terminates within the allowed time. + // NOTE: On POSIX |exit_code| is ignored. + bool Terminate(int exit_code, bool wait) const; + + // Waits for the process to exit. Returns true on success. + // On POSIX, if the process has been signaled then |exit_code| is set to -1. + // On Linux this must be a child process, however on Mac and Windows it can be + // any process. + // NOTE: |exit_code| is optional, nullptr can be passed if the exit code is + // not required. + bool WaitForExit(int* exit_code) const; + + // Same as WaitForExit() but only waits for up to |timeout|. + // NOTE: |exit_code| is optional, nullptr can be passed if the exit code + // is not required. + bool WaitForExitWithTimeout(TimeDelta timeout, int* exit_code) const; + + // Indicates that the process has exited with the specified |exit_code|. + // This should be called if process exit is observed outside of this class. + // (i.e. Not because Terminate or WaitForExit, above, was called.) + // Note that nothing prevents this being called multiple times for a dead + // process though that should be avoided. + void Exited(int exit_code) const; + +#if defined(OS_MACOSX) + // The Mac needs a Mach port in order to manipulate a process's priority, + // and there's no good way to get that from base given the pid. These Mac + // variants of the IsProcessBackgrounded and SetProcessBackgrounded API take + // a port provider for this reason. See crbug.com/460102 + // + // A process is backgrounded when its task priority is + // |TASK_BACKGROUND_APPLICATION|. + // + // Returns true if the port_provider can locate a task port for the process + // and it is backgrounded. If port_provider is null, returns false. + bool IsProcessBackgrounded(PortProvider* port_provider) const; + + // Set the process as backgrounded. If value is + // true, the priority of the associated task will be set to + // TASK_BACKGROUND_APPLICATION. If value is false, the + // priority of the process will be set to TASK_FOREGROUND_APPLICATION. + // + // Returns true if the priority was changed, false otherwise. If + // |port_provider| is null, this is a no-op and it returns false. + bool SetProcessBackgrounded(PortProvider* port_provider, bool value); +#else + // A process is backgrounded when it's priority is lower than normal. + // Return true if this process is backgrounded, false otherwise. + bool IsProcessBackgrounded() const; + + // Set a process as backgrounded. If value is true, the priority of the + // process will be lowered. If value is false, the priority of the process + // will be made "normal" - equivalent to default process priority. + // Returns true if the priority was changed, false otherwise. + bool SetProcessBackgrounded(bool value); +#endif // defined(OS_MACOSX) + // Returns an integer representing the priority of a process. The meaning + // of this value is OS dependent. + int GetPriority() const; + +#if defined(OS_CHROMEOS) + // Get the PID in its PID namespace. + // If the process is not in a PID namespace or /proc/<pid>/status does not + // report NSpid, kNullProcessId is returned. + ProcessId GetPidInNamespace() const; +#endif + + private: +#if defined(OS_WIN) + win::ScopedHandle process_; +#elif defined(OS_FUCHSIA) + zx::process process_; +#else + ProcessHandle process_; +#endif + +#if defined(OS_WIN) || defined(OS_FUCHSIA) + bool is_current_process_; +#endif + + DISALLOW_COPY_AND_ASSIGN(Process); +}; + +#if defined(OS_CHROMEOS) +// Exposed for testing. +// Given the contents of the /proc/<pid>/cgroup file, determine whether the +// process is backgrounded or not. +BASE_EXPORT bool IsProcessBackgroundedCGroup( + const StringPiece& cgroup_contents); +#endif // defined(OS_CHROMEOS) + +} // namespace base + +#endif // BASE_PROCESS_PROCESS_H_ diff --git a/security/sandbox/chromium/base/process/process_handle.h b/security/sandbox/chromium/base/process/process_handle.h new file mode 100644 index 0000000000..94f7006119 --- /dev/null +++ b/security/sandbox/chromium/base/process/process_handle.h @@ -0,0 +1,142 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef BASE_PROCESS_PROCESS_HANDLE_H_ +#define BASE_PROCESS_PROCESS_HANDLE_H_ + +#include <stdint.h> +#include <sys/types.h> + +#include "base/base_export.h" +#include "base/files/file_path.h" +#include "build/build_config.h" + +#if defined(OS_WIN) +#include "base/win/windows_types.h" +#endif + +#if defined(OS_FUCHSIA) +#include <zircon/types.h> +#endif + +namespace base { + +// ProcessHandle is a platform specific type which represents the underlying OS +// handle to a process. +// ProcessId is a number which identifies the process in the OS. +#if defined(OS_WIN) +typedef HANDLE ProcessHandle; +typedef DWORD ProcessId; +typedef HANDLE UserTokenHandle; +const ProcessHandle kNullProcessHandle = NULL; +const ProcessId kNullProcessId = 0; +#elif defined(OS_FUCHSIA) +typedef zx_handle_t ProcessHandle; +typedef zx_koid_t ProcessId; +const ProcessHandle kNullProcessHandle = ZX_HANDLE_INVALID; +const ProcessId kNullProcessId = ZX_KOID_INVALID; +#elif defined(OS_POSIX) +// On POSIX, our ProcessHandle will just be the PID. +typedef pid_t ProcessHandle; +typedef pid_t ProcessId; +const ProcessHandle kNullProcessHandle = 0; +const ProcessId kNullProcessId = 0; +#endif // defined(OS_WIN) + +// To print ProcessIds portably use CrPRIdPid (based on PRIuS and friends from +// C99 and format_macros.h) like this: +// base::StringPrintf("PID is %" CrPRIdPid ".\n", pid); +#if defined(OS_WIN) || defined(OS_FUCHSIA) +#define CrPRIdPid "ld" +#else +#define CrPRIdPid "d" +#endif + +class UniqueProcId { + public: + explicit UniqueProcId(ProcessId value) : value_(value) {} + UniqueProcId(const UniqueProcId& other) = default; + UniqueProcId& operator=(const UniqueProcId& other) = default; + + // Returns the process PID. WARNING: On some platforms, the pid may not be + // valid within the current process sandbox. + ProcessId GetUnsafeValue() const { return value_; } + + bool operator==(const UniqueProcId& other) const { + return value_ == other.value_; + } + + bool operator!=(const UniqueProcId& other) const { + return value_ != other.value_; + } + + bool operator<(const UniqueProcId& other) const { + return value_ < other.value_; + } + + bool operator<=(const UniqueProcId& other) const { + return value_ <= other.value_; + } + + bool operator>(const UniqueProcId& other) const { + return value_ > other.value_; + } + + bool operator>=(const UniqueProcId& other) const { + return value_ >= other.value_; + } + + private: + ProcessId value_; +}; + +std::ostream& operator<<(std::ostream& os, const UniqueProcId& obj); + +// Returns the id of the current process. +// Note that on some platforms, this is not guaranteed to be unique across +// processes (use GetUniqueIdForProcess if uniqueness is required). +BASE_EXPORT ProcessId GetCurrentProcId(); + +// Returns a unique ID for the current process. The ID will be unique across all +// currently running processes within the chrome session, but IDs of terminated +// processes may be reused. +BASE_EXPORT UniqueProcId GetUniqueIdForProcess(); + +#if defined(OS_LINUX) +// When a process is started in a different PID namespace from the browser +// process, this function must be called with the process's PID in the browser's +// PID namespace in order to initialize its unique ID. Not thread safe. +// WARNING: To avoid inconsistent results from GetUniqueIdForProcess, this +// should only be called very early after process startup - ideally as soon +// after process creation as possible. +BASE_EXPORT void InitUniqueIdForProcessInPidNamespace( + ProcessId pid_outside_of_namespace); +#endif + +// Returns the ProcessHandle of the current process. +BASE_EXPORT ProcessHandle GetCurrentProcessHandle(); + +// Returns the process ID for the specified process. This is functionally the +// same as Windows' GetProcessId(), but works on versions of Windows before Win +// XP SP1 as well. +// DEPRECATED. New code should be using Process::Pid() instead. +// Note that on some platforms, this is not guaranteed to be unique across +// processes. +BASE_EXPORT ProcessId GetProcId(ProcessHandle process); + +#if !defined(OS_FUCHSIA) +// Returns the ID for the parent of the given process. Not available on Fuchsia. +// Returning a negative value indicates an error, such as if the |process| does +// not exist. Returns 0 when |process| has no parent process. +BASE_EXPORT ProcessId GetParentProcessId(ProcessHandle process); +#endif // !defined(OS_FUCHSIA) + +#if defined(OS_POSIX) +// Returns the path to the executable of the given process. +BASE_EXPORT FilePath GetProcessExecutablePath(ProcessHandle process); +#endif + +} // namespace base + +#endif // BASE_PROCESS_PROCESS_HANDLE_H_ diff --git a/security/sandbox/chromium/base/process/process_handle_win.cc b/security/sandbox/chromium/base/process/process_handle_win.cc new file mode 100644 index 0000000000..ccc759039d --- /dev/null +++ b/security/sandbox/chromium/base/process/process_handle_win.cc @@ -0,0 +1,52 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/process/process_handle.h" + +#include <windows.h> +#include <tlhelp32.h> + +#include "base/win/scoped_handle.h" +#include "base/win/windows_version.h" + +namespace base { + +ProcessId GetCurrentProcId() { + return ::GetCurrentProcessId(); +} + +ProcessHandle GetCurrentProcessHandle() { + return ::GetCurrentProcess(); +} + +ProcessId GetProcId(ProcessHandle process) { + if (process == base::kNullProcessHandle) + return 0; + // This returns 0 if we have insufficient rights to query the process handle. + // Invalid handles or non-process handles will cause a hard failure. + ProcessId result = GetProcessId(process); + CHECK(result != 0 || GetLastError() != ERROR_INVALID_HANDLE) + << "process handle = " << process; + return result; +} + +ProcessId GetParentProcessId(ProcessHandle process) { + ProcessId child_pid = GetProcId(process); + PROCESSENTRY32 process_entry; + process_entry.dwSize = sizeof(PROCESSENTRY32); + + win::ScopedHandle snapshot(CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0)); + if (snapshot.IsValid() && Process32First(snapshot.Get(), &process_entry)) { + do { + if (process_entry.th32ProcessID == child_pid) + return process_entry.th32ParentProcessID; + } while (Process32Next(snapshot.Get(), &process_entry)); + } + + // TODO(zijiehe): To match other platforms, -1 (UINT32_MAX) should be returned + // if |child_id| cannot be found in the |snapshot|. + return 0u; +} + +} // namespace base |