diff options
author | haven@chromium.org <haven@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-02-11 14:45:35 +0000 |
---|---|---|
committer | haven@chromium.org <haven@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-02-11 14:45:35 +0000 |
commit | fa01e47350050ca5be93589414a21d4dc5579107 (patch) | |
tree | 82f43d07d7ccba3bbd5ff275a6f6d92e8d72bc51 | |
parent | bfd21809b814c4773725497791b841499af9e0b5 (diff) | |
download | chromium_src-fa01e47350050ca5be93589414a21d4dc5579107.zip chromium_src-fa01e47350050ca5be93589414a21d4dc5579107.tar.gz chromium_src-fa01e47350050ca5be93589414a21d4dc5579107.tar.bz2 |
Creates a way to launch the utility process with elevated privileges on Windows systems for the rare operations that require administrator access.
IPCs to the utility process will be filtered when it is running elevated.
BUG=331881
Review URL: https://codereview.chromium.org/98603007
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@250409 0039d316-1c4b-4281-b951-d872f2087c98
31 files changed, 224 insertions, 17 deletions
diff --git a/base/process/launch.h b/base/process/launch.h index e11d1c0..c25a9be 100644 --- a/base/process/launch.h +++ b/base/process/launch.h @@ -159,6 +159,16 @@ BASE_EXPORT bool LaunchProcess(const string16& cmdline, const LaunchOptions& options, win::ScopedHandle* process_handle); +// Launches a process with elevated privileges. This does not behave exactly +// like LaunchProcess as it uses ShellExecuteEx instead of CreateProcess to +// create the process. This means the process will have elevated privileges +// and thus some common operations like OpenProcess will fail. The process will +// be available through the |process_handle| argument. Currently the only +// supported LaunchOptions are |start_hidden| and |wait|. +BASE_EXPORT bool LaunchElevatedProcess(const CommandLine& cmdline, + const LaunchOptions& options, + ProcessHandle* process_handle); + #elif defined(OS_POSIX) // A POSIX-specific version of LaunchProcess that takes an argv array // instead of a CommandLine. Useful for situations where you need to diff --git a/base/process/launch_win.cc b/base/process/launch_win.cc index 0c831cf..de05255 100644 --- a/base/process/launch_win.cc +++ b/base/process/launch_win.cc @@ -6,6 +6,7 @@ #include <fcntl.h> #include <io.h> +#include <shellapi.h> #include <windows.h> #include <userenv.h> #include <psapi.h> @@ -239,6 +240,41 @@ bool LaunchProcess(const CommandLine& cmdline, return rv; } +bool LaunchElevatedProcess(const CommandLine& cmdline, + const LaunchOptions& options, + ProcessHandle* process_handle) { + const string16 file = cmdline.GetProgram().value(); + const string16 arguments = cmdline.GetArgumentsString(); + + SHELLEXECUTEINFO shex_info = {0}; + shex_info.cbSize = sizeof(shex_info); + shex_info.fMask = SEE_MASK_NOCLOSEPROCESS; + shex_info.hwnd = GetActiveWindow(); + shex_info.lpVerb = L"runas"; + shex_info.lpFile = file.c_str(); + shex_info.lpParameters = arguments.c_str(); + shex_info.lpDirectory = NULL; + shex_info.nShow = options.start_hidden ? SW_HIDE : SW_SHOW; + shex_info.hInstApp = NULL; + + if (!ShellExecuteEx(&shex_info)) { + DPLOG(ERROR); + return false; + } + + if (options.wait) + WaitForSingleObject(shex_info.hProcess, INFINITE); + + // If the caller wants the process handle give it to them, otherwise just + // close it. Closing it does not terminate the process. + if (process_handle) + *process_handle = shex_info.hProcess; + else + CloseHandle(shex_info.hProcess); + + return true; +} + bool SetJobObjectLimitFlags(HANDLE job_object, DWORD limit_flags) { JOBOBJECT_EXTENDED_LIMIT_INFORMATION limit_info = {0}; limit_info.BasicLimitInformation.LimitFlags = limit_flags; diff --git a/chrome/chrome.gyp b/chrome/chrome.gyp index ed0692d..b3ea39d 100644 --- a/chrome/chrome.gyp +++ b/chrome/chrome.gyp @@ -257,6 +257,8 @@ 'sources': [ 'utility/chrome_content_utility_client.cc', 'utility/chrome_content_utility_client.h', + 'utility/chrome_content_utility_ipc_whitelist.cc', + 'utility/chrome_content_utility_ipc_whitelist.h', 'utility/cloud_print/bitmap_image.cc', 'utility/cloud_print/bitmap_image.h', 'utility/cloud_print/pwg_encoder.cc', diff --git a/chrome/service/service_utility_process_host.cc b/chrome/service/service_utility_process_host.cc index 3e8ee3d..3054adc 100644 --- a/chrome/service/service_utility_process_host.cc +++ b/chrome/service/service_utility_process_host.cc @@ -268,6 +268,10 @@ bool ServiceUtilityProcessHost::OnMessageReceived(const IPC::Message& message) { return handled; } +base::ProcessHandle ServiceUtilityProcessHost::GetHandle() const { + return handle_; +} + void ServiceUtilityProcessHost::OnRenderPDFPagesToMetafileSucceeded( int highest_rendered_page_number, double scale_factor) { diff --git a/chrome/service/service_utility_process_host.h b/chrome/service/service_utility_process_host.h index ab27d20..fd1fad9 100644 --- a/chrome/service/service_utility_process_host.h +++ b/chrome/service/service_utility_process_host.h @@ -121,6 +121,7 @@ class ServiceUtilityProcessHost : public content::ChildProcessHostDelegate { // ChildProcessHostDelegate implementation: virtual void OnChildDisconnected() OVERRIDE; virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE; + virtual base::ProcessHandle GetHandle() const OVERRIDE; private: // Starts a process. Returns true iff it succeeded. |exposed_dir| is the diff --git a/chrome/utility/OWNERS b/chrome/utility/OWNERS new file mode 100644 index 0000000..fbfb968 --- /dev/null +++ b/chrome/utility/OWNERS @@ -0,0 +1,13 @@ +# For security review of utility process message whitelisting +per-file chrome_content_utility_ipc_whitelist.cc=set noparent +per-file chrome_content_utility_ipc_whitelist.cc=cdn@chromium.org +per-file chrome_content_utility_ipc_whitelist.cc=cevans@chromium.org +per-file chrome_content_utility_ipc_whitelist.cc=dcheng@chromium.org +per-file chrome_content_utility_ipc_whitelist.cc=inferno@chromium.org +per-file chrome_content_utility_ipc_whitelist.cc=jln@chromium.org +per-file chrome_content_utility_ipc_whitelist.cc=jorgelo@chromium.org +per-file chrome_content_utility_ipc_whitelist.cc=jschuh@chromium.org +per-file chrome_content_utility_ipc_whitelist.cc=kenrb@chromium.org +per-file chrome_content_utility_ipc_whitelist.cc=nasko@chromium.org +per-file chrome_content_utility_ipc_whitelist.cc=palmer@chromium.org +per-file chrome_content_utility_ipc_whitelist.cc=tsepez@chromium.org diff --git a/chrome/utility/chrome_content_utility_client.cc b/chrome/utility/chrome_content_utility_client.cc index e5a689c..c66abcf 100644 --- a/chrome/utility/chrome_content_utility_client.cc +++ b/chrome/utility/chrome_content_utility_client.cc @@ -20,6 +20,7 @@ #include "chrome/common/extensions/extension_l10n_util.h" #include "chrome/common/extensions/update_manifest.h" #include "chrome/common/safe_browsing/zip_analyzer.h" +#include "chrome/utility/chrome_content_utility_ipc_whitelist.h" #include "chrome/utility/cloud_print/bitmap_image.h" #include "chrome/utility/cloud_print/pwg_encoder.h" #include "chrome/utility/extensions/unpacker.h" @@ -27,6 +28,7 @@ #include "chrome/utility/web_resource_unpacker.h" #include "content/public/child/image_decoder_utils.h" #include "content/public/common/content_paths.h" +#include "content/public/common/content_switches.h" #include "content/public/utility/utility_thread.h" #include "extensions/common/extension.h" #include "extensions/common/manifest.h" @@ -72,7 +74,6 @@ #if defined(ENABLE_MDNS) #include "chrome/utility/local_discovery/service_discovery_message_handler.h" -#include "content/public/common/content_switches.h" #endif // ENABLE_MDNS namespace chrome { @@ -305,7 +306,8 @@ static base::LazyInstance<PdfFunctions> g_pdf_lib = LAZY_INSTANCE_INITIALIZER; } // namespace -ChromeContentUtilityClient::ChromeContentUtilityClient() { +ChromeContentUtilityClient::ChromeContentUtilityClient() + : filter_messages_(false) { #if !defined(OS_ANDROID) handlers_.push_back(new ProfileImportHandler()); #endif // OS_ANDROID @@ -326,10 +328,22 @@ void ChromeContentUtilityClient::UtilityThreadStarted() { std::string lang = command_line->GetSwitchValueASCII(switches::kLang); if (!lang.empty()) extension_l10n_util::SetProcessLocale(lang); + + if (command_line->HasSwitch(switches::kUtilityProcessRunningElevated)) { + message_id_whitelist_.insert(kMessageWhitelist, + kMessageWhitelist + kMessageWhitelistSize); + filter_messages_ = true; + } } bool ChromeContentUtilityClient::OnMessageReceived( const IPC::Message& message) { + if (filter_messages_ && + (message_id_whitelist_.find(message.type()) == + message_id_whitelist_.end())) { + return false; + } + bool handled = true; IPC_BEGIN_MESSAGE_MAP(ChromeContentUtilityClient, message) IPC_MESSAGE_HANDLER(ChromeUtilityMsg_UnpackExtension, OnUnpackExtension) diff --git a/chrome/utility/chrome_content_utility_client.h b/chrome/utility/chrome_content_utility_client.h index 8b914f8..fcc5da9 100644 --- a/chrome/utility/chrome_content_utility_client.h +++ b/chrome/utility/chrome_content_utility_client.h @@ -129,6 +129,11 @@ class ChromeContentUtilityClient : public content::ContentUtilityClient { scoped_ptr<metadata::MediaMetadataParser> media_metadata_parser_; #endif // !defined(OS_ANDROID) && !defined(OS_IOS) + // Flag to enable whitelisting. + bool filter_messages_; + // A list of message_ids to filter. + std::set<int> message_id_whitelist_; + DISALLOW_COPY_AND_ASSIGN(ChromeContentUtilityClient); }; diff --git a/chrome/utility/chrome_content_utility_ipc_whitelist.cc b/chrome/utility/chrome_content_utility_ipc_whitelist.cc new file mode 100644 index 0000000..5715a9cc --- /dev/null +++ b/chrome/utility/chrome_content_utility_ipc_whitelist.cc @@ -0,0 +1,12 @@ +// Copyright 2014 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 "chrome/utility/chrome_content_utility_ipc_whitelist.h" + +namespace chrome { + +const uint32 kMessageWhitelist[] = {0}; +const size_t kMessageWhitelistSize = arraysize(kMessageWhitelist); + +} // namespace chrome diff --git a/chrome/utility/chrome_content_utility_ipc_whitelist.h b/chrome/utility/chrome_content_utility_ipc_whitelist.h new file mode 100644 index 0000000..fcbd36c --- /dev/null +++ b/chrome/utility/chrome_content_utility_ipc_whitelist.h @@ -0,0 +1,21 @@ +// Copyright 2014 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 CHROME_UTILITY_CHROME_CONTENT_UTILITY_IPC_WHITELIST_H_ +#define CHROME_UTILITY_CHROME_CONTENT_UTILITY_IPC_WHITELIST_H_ + +#include "base/basictypes.h" + +namespace chrome { + +// This array contains the list of IPC messages that the utility process will +// accept when running with elevated privileges. When new messages need to run +// with elevated privileges, add them here and be sure to add a security +// reviewer. +extern const uint32 kMessageWhitelist[]; +extern const size_t kMessageWhitelistSize; + +} // namespace chrome + +#endif // CHROME_UTILITY_CHROME_CONTENT_UTILITY_IPC_WHITELIST_H_ diff --git a/components/nacl/browser/nacl_broker_host_win.cc b/components/nacl/browser/nacl_broker_host_win.cc index 878ca6e..ca54e67 100644 --- a/components/nacl/browser/nacl_broker_host_win.cc +++ b/components/nacl/browser/nacl_broker_host_win.cc @@ -67,7 +67,9 @@ bool NaClBrokerHost::Init() { if (NaClBrowser::GetDelegate()->DialogsAreSuppressed()) cmd_line->AppendSwitch(switches::kNoErrorDialogs); - process_->Launch(new NaClBrokerSandboxedProcessLauncherDelegate, cmd_line); + process_->Launch(new NaClBrokerSandboxedProcessLauncherDelegate, + false, + cmd_line); return true; } diff --git a/components/nacl/browser/nacl_process_host.cc b/components/nacl/browser/nacl_process_host.cc index cb430eb..a5a1341 100644 --- a/components/nacl/browser/nacl_process_host.cc +++ b/components/nacl/browser/nacl_process_host.cc @@ -537,6 +537,7 @@ bool NaClProcessHost::LaunchSelLdr() { } } else { process_->Launch(new NaClSandboxedProcessLauncherDelegate, + false, cmd_line.release()); } #elif defined(OS_POSIX) diff --git a/content/browser/browser_child_process_host_impl.cc b/content/browser/browser_child_process_host_impl.cc index fd1b286..c69e5db 100644 --- a/content/browser/browser_child_process_host_impl.cc +++ b/content/browser/browser_child_process_host_impl.cc @@ -131,6 +131,7 @@ void BrowserChildProcessHostImpl::TerminateAll() { void BrowserChildProcessHostImpl::Launch( #if defined(OS_WIN) SandboxedProcessLauncherDelegate* delegate, + bool launch_elevated, #elif defined(OS_POSIX) bool use_zygote, const base::EnvironmentMap& environ, @@ -163,6 +164,7 @@ void BrowserChildProcessHostImpl::Launch( child_process_.reset(new ChildProcessLauncher( #if defined(OS_WIN) delegate, + launch_elevated, #elif defined(OS_POSIX) use_zygote, environ, @@ -318,6 +320,11 @@ bool BrowserChildProcessHostImpl::Send(IPC::Message* message) { return child_process_host_->Send(message); } +void BrowserChildProcessHostImpl::OnProcessLaunchFailed() { + delegate_->OnProcessLaunchFailed(); + delete delegate_; // Will delete us +} + void BrowserChildProcessHostImpl::OnProcessLaunched() { base::ProcessHandle handle = child_process_->GetHandle(); if (!handle) { diff --git a/content/browser/browser_child_process_host_impl.h b/content/browser/browser_child_process_host_impl.h index 67ce9e2..3bcab7c 100644 --- a/content/browser/browser_child_process_host_impl.h +++ b/content/browser/browser_child_process_host_impl.h @@ -45,6 +45,7 @@ class CONTENT_EXPORT BrowserChildProcessHostImpl virtual void Launch( #if defined(OS_WIN) SandboxedProcessLauncherDelegate* delegate, + bool launch_elevated, #elif defined(OS_POSIX) bool use_zygote, const base::EnvironmentMap& environ, @@ -58,9 +59,13 @@ class CONTENT_EXPORT BrowserChildProcessHostImpl virtual void SetName(const base::string16& name) OVERRIDE; virtual void SetHandle(base::ProcessHandle handle) OVERRIDE; - // Returns the handle of the child process. This can be called only after - // OnProcessLaunched is called or it will be invalid and may crash. - base::ProcessHandle GetHandle() const; + // ChildProcessHostDelegate implementation: + virtual bool CanShutdown() OVERRIDE; + virtual void OnChildDisconnected() OVERRIDE; + virtual base::ProcessHandle GetHandle() const OVERRIDE; + virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE; + virtual void OnChannelConnected(int32 peer_pid) OVERRIDE; + virtual void OnChannelError() OVERRIDE; // Removes this host from the host list. Calls ChildProcessHost::ForceShutdown void ForceShutdown(); @@ -90,15 +95,9 @@ class CONTENT_EXPORT BrowserChildProcessHostImpl static void AddObserver(BrowserChildProcessObserver* observer); static void RemoveObserver(BrowserChildProcessObserver* observer); - // ChildProcessHostDelegate implementation: - virtual bool CanShutdown() OVERRIDE; - virtual void OnChildDisconnected() OVERRIDE; - virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE; - virtual void OnChannelConnected(int32 peer_pid) OVERRIDE; - virtual void OnChannelError() OVERRIDE; - // ChildProcessLauncher::Client implementation. virtual void OnProcessLaunched() OVERRIDE; + virtual void OnProcessLaunchFailed() OVERRIDE; #if defined(OS_WIN) void DeleteProcessWaitableEvent(base::WaitableEvent* event); diff --git a/content/browser/child_process_launcher.cc b/content/browser/child_process_launcher.cc index 3a16211..7dfad56 100644 --- a/content/browser/child_process_launcher.cc +++ b/content/browser/child_process_launcher.cc @@ -73,6 +73,7 @@ class ChildProcessLauncher::Context void Launch( #if defined(OS_WIN) SandboxedProcessLauncherDelegate* delegate, + bool launch_elevated, #elif defined(OS_ANDROID) int ipcfd, #elif defined(OS_POSIX) @@ -102,6 +103,7 @@ class ChildProcessLauncher::Context child_process_id, #if defined(OS_WIN) delegate, + launch_elevated, #elif defined(OS_ANDROID) ipcfd, #elif defined(OS_POSIX) @@ -185,6 +187,7 @@ class ChildProcessLauncher::Context int child_process_id, #if defined(OS_WIN) SandboxedProcessLauncherDelegate* delegate, + bool launch_elevated, #elif defined(OS_ANDROID) int ipcfd, #elif defined(OS_POSIX) @@ -197,8 +200,15 @@ class ChildProcessLauncher::Context base::TimeTicks begin_launch_time = base::TimeTicks::Now(); #if defined(OS_WIN) - scoped_ptr<SandboxedProcessLauncherDelegate> delegate_deleter(delegate); - base::ProcessHandle handle = StartSandboxedProcess(delegate, cmd_line); + base::ProcessHandle handle = base::kNullProcessHandle; + if (launch_elevated) { + base::LaunchOptions options; + options.start_hidden = true; + base::LaunchElevatedProcess(*cmd_line, options, &handle); + } else { + scoped_ptr<SandboxedProcessLauncherDelegate> delegate_deleter(delegate); + handle = StartSandboxedProcess(delegate, cmd_line); + } #elif defined(OS_POSIX) std::string process_type = cmd_line->GetSwitchValueASCII(switches::kProcessType); @@ -335,7 +345,11 @@ class ChildProcessLauncher::Context zygote_ = zygote; #endif if (client_) { - client_->OnProcessLaunched(); + if (handle) { + client_->OnProcessLaunched(); + } else { + client_->OnProcessLaunchFailed(); + } } else { Terminate(); } @@ -418,6 +432,7 @@ class ChildProcessLauncher::Context ChildProcessLauncher::ChildProcessLauncher( #if defined(OS_WIN) SandboxedProcessLauncherDelegate* delegate, + bool launch_elevated, #elif defined(OS_POSIX) bool use_zygote, const base::EnvironmentMap& environ, @@ -430,6 +445,7 @@ ChildProcessLauncher::ChildProcessLauncher( context_->Launch( #if defined(OS_WIN) delegate, + launch_elevated, #elif defined(OS_ANDROID) ipcfd, #elif defined(OS_POSIX) diff --git a/content/browser/child_process_launcher.h b/content/browser/child_process_launcher.h index 7ce7805..965a914 100644 --- a/content/browser/child_process_launcher.h +++ b/content/browser/child_process_launcher.h @@ -27,6 +27,8 @@ class CONTENT_EXPORT ChildProcessLauncher { // constructed on. virtual void OnProcessLaunched() = 0; + virtual void OnProcessLaunchFailed() {}; + protected: virtual ~Client() {} }; @@ -39,6 +41,7 @@ class CONTENT_EXPORT ChildProcessLauncher { ChildProcessLauncher( #if defined(OS_WIN) SandboxedProcessLauncherDelegate* delegate, + bool launch_elevated, #elif defined(OS_POSIX) bool use_zygote, const base::EnvironmentMap& environ, diff --git a/content/browser/gpu/gpu_process_host.cc b/content/browser/gpu/gpu_process_host.cc index eb0b254..41007d4 100644 --- a/content/browser/gpu/gpu_process_host.cc +++ b/content/browser/gpu/gpu_process_host.cc @@ -1144,6 +1144,7 @@ bool GpuProcessHost::LaunchGpuProcess(const std::string& channel_id) { process_->Launch( #if defined(OS_WIN) new GpuSandboxedProcessLauncherDelegate(cmd_line), + false, #elif defined(OS_POSIX) false, base::EnvironmentMap(), diff --git a/content/browser/plugin_process_host.cc b/content/browser/plugin_process_host.cc index 068858b..e329dcc 100644 --- a/content/browser/plugin_process_host.cc +++ b/content/browser/plugin_process_host.cc @@ -245,6 +245,7 @@ bool PluginProcessHost::Init(const WebPluginInfo& info) { process_->Launch( #if defined(OS_WIN) new PluginSandboxedProcessLauncherDelegate, + false, #elif defined(OS_POSIX) false, env, diff --git a/content/browser/ppapi_plugin_process_host.cc b/content/browser/ppapi_plugin_process_host.cc index 953f84c..f1a3171 100644 --- a/content/browser/ppapi_plugin_process_host.cc +++ b/content/browser/ppapi_plugin_process_host.cc @@ -340,6 +340,7 @@ bool PpapiPluginProcessHost::Init(const PepperPluginInfo& info) { process_->Launch( #if defined(OS_WIN) new PpapiPluginSandboxedProcessLauncherDelegate(is_broker_), + false, #elif defined(OS_POSIX) use_zygote, base::EnvironmentMap(), diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc index 03ce20c..f6b4832 100644 --- a/content/browser/renderer_host/render_process_host_impl.cc +++ b/content/browser/renderer_host/render_process_host_impl.cc @@ -567,6 +567,7 @@ bool RenderProcessHostImpl::Init() { child_process_launcher_.reset(new ChildProcessLauncher( #if defined(OS_WIN) new RendererSandboxedProcessLauncherDelegate, + false, #elif defined(OS_POSIX) renderer_prefix.empty(), base::EnvironmentMap(), diff --git a/content/browser/utility_process_host_impl.cc b/content/browser/utility_process_host_impl.cc index e2f45245..013c62a 100644 --- a/content/browser/utility_process_host_impl.cc +++ b/content/browser/utility_process_host_impl.cc @@ -73,6 +73,9 @@ UtilityProcessHostImpl::UtilityProcessHostImpl( is_batch_mode_(false), is_mdns_enabled_(false), no_sandbox_(false), +#if defined(OS_WIN) + run_elevated_(false), +#endif #if defined(OS_LINUX) child_flags_(ChildProcessHost::CHILD_ALLOW_SELF), #else @@ -119,6 +122,13 @@ void UtilityProcessHostImpl::DisableSandbox() { no_sandbox_ = true; } +#if defined(OS_WIN) +void UtilityProcessHostImpl::ElevatePrivileges() { + no_sandbox_ = true; + run_elevated_ = true; +} +#endif + const ChildProcessData& UtilityProcessHostImpl::GetData() { return process_->GetData(); } @@ -210,6 +220,12 @@ bool UtilityProcessHostImpl::StartProcess() { if (is_mdns_enabled_) cmd_line->AppendSwitch(switches::kUtilityProcessEnableMDns); +#if defined(OS_WIN) + // Let the utility process know if it is intended to be elevated. + if (run_elevated_) + cmd_line->AppendSwitch(switches::kUtilityProcessRunningElevated); +#endif + bool use_zygote = false; #if defined(OS_LINUX) @@ -221,6 +237,7 @@ bool UtilityProcessHostImpl::StartProcess() { process_->Launch( #if defined(OS_WIN) new UtilitySandboxedProcessLauncherDelegate(exposed_dir_), + run_elevated_, #elif defined(OS_POSIX) use_zygote, env_, @@ -240,6 +257,13 @@ bool UtilityProcessHostImpl::OnMessageReceived(const IPC::Message& message) { return true; } +void UtilityProcessHostImpl::OnProcessLaunchFailed() { + client_task_runner_->PostTask( + FROM_HERE, + base::Bind(&UtilityProcessHostClient::OnProcessLaunchFailed, + client_.get())); +} + void UtilityProcessHostImpl::OnProcessCrashed(int exit_code) { client_task_runner_->PostTask( FROM_HERE, diff --git a/content/browser/utility_process_host_impl.h b/content/browser/utility_process_host_impl.h index 3083b22..dd663dd 100644 --- a/content/browser/utility_process_host_impl.h +++ b/content/browser/utility_process_host_impl.h @@ -40,6 +40,9 @@ class CONTENT_EXPORT UtilityProcessHostImpl virtual void SetExposedDir(const base::FilePath& dir) OVERRIDE; virtual void EnableMDns() OVERRIDE; virtual void DisableSandbox() OVERRIDE; +#if defined(OS_WIN) + virtual void ElevatePrivileges() OVERRIDE; +#endif virtual const ChildProcessData& GetData() OVERRIDE; #if defined(OS_POSIX) virtual void SetEnv(const base::EnvironmentMap& env) OVERRIDE; @@ -54,6 +57,7 @@ class CONTENT_EXPORT UtilityProcessHostImpl // BrowserChildProcessHost: virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE; + virtual void OnProcessLaunchFailed() OVERRIDE; virtual void OnProcessCrashed(int exit_code) OVERRIDE; // A pointer to our client interface, who will be informed of progress. @@ -72,6 +76,11 @@ class CONTENT_EXPORT UtilityProcessHostImpl // Whether to pass switches::kNoSandbox to the child. bool no_sandbox_; +#if defined(OS_WIN) + // Whether to launch the process with elevated privileges. + bool run_elevated_; +#endif + // Flags defined in ChildProcessHost with which to start the process. int child_flags_; diff --git a/content/browser/worker_host/worker_process_host.cc b/content/browser/worker_host/worker_process_host.cc index be50d51..91b7938 100644 --- a/content/browser/worker_host/worker_process_host.cc +++ b/content/browser/worker_host/worker_process_host.cc @@ -223,6 +223,7 @@ bool WorkerProcessHost::Init(int render_process_id, int render_frame_id) { process_->Launch( #if defined(OS_WIN) new WorkerSandboxedProcessLauncherDelegate, + false, #elif defined(OS_POSIX) use_zygote, base::EnvironmentMap(), diff --git a/content/common/child_process_host_impl.cc b/content/common/child_process_host_impl.cc index 4e7b862..efdd925 100644 --- a/content/common/child_process_host_impl.cc +++ b/content/common/child_process_host_impl.cc @@ -270,7 +270,9 @@ bool ChildProcessHostImpl::OnMessageReceived(const IPC::Message& msg) { } void ChildProcessHostImpl::OnChannelConnected(int32 peer_pid) { - if (!base::OpenPrivilegedProcessHandle(peer_pid, &peer_handle_)) { + if (!peer_handle_ && + !base::OpenPrivilegedProcessHandle(peer_pid, &peer_handle_) && + !(peer_handle_ = delegate_->GetHandle())) { NOTREACHED(); } opening_channel_ = false; diff --git a/content/public/browser/browser_child_process_host.h b/content/public/browser/browser_child_process_host.h index 182dd8d..690a015 100644 --- a/content/public/browser/browser_child_process_host.h +++ b/content/public/browser/browser_child_process_host.h @@ -46,6 +46,7 @@ class CONTENT_EXPORT BrowserChildProcessHost : public IPC::Sender { virtual void Launch( #if defined(OS_WIN) SandboxedProcessLauncherDelegate* delegate, + bool run_elevated, #elif defined(OS_POSIX) bool use_zygote, const base::EnvironmentMap& environ, diff --git a/content/public/browser/browser_child_process_host_delegate.h b/content/public/browser/browser_child_process_host_delegate.h index 2efbeab..25ff00a 100644 --- a/content/public/browser/browser_child_process_host_delegate.h +++ b/content/public/browser/browser_child_process_host_delegate.h @@ -24,6 +24,10 @@ class CONTENT_EXPORT BrowserChildProcessHostDelegate : public IPC::Listener { // Called when the process has been started. virtual void OnProcessLaunched() {} + // Called if the process failed to launch. In this case the process never + // started so there is no available exit code. + virtual void OnProcessLaunchFailed() {} + // Called if the process crashed. |exit_code| is the status returned when the // process crashed (for posix, as returned from waitpid(), for Windows, as // returned from GetExitCodeProcess()). diff --git a/content/public/browser/utility_process_host.h b/content/public/browser/utility_process_host.h index 1f027a8..c39c76e 100644 --- a/content/public/browser/utility_process_host.h +++ b/content/public/browser/utility_process_host.h @@ -61,6 +61,11 @@ class UtilityProcessHost : public IPC::Sender, // Make the process run without a sandbox. virtual void DisableSandbox() = 0; +#if defined(OS_WIN) + // Make the process run elevated. + virtual void ElevatePrivileges() = 0; +#endif + // Returns information about the utility child process. virtual const ChildProcessData& GetData() = 0; diff --git a/content/public/browser/utility_process_host_client.h b/content/public/browser/utility_process_host_client.h index 73d707b..bd7e89d 100644 --- a/content/public/browser/utility_process_host_client.h +++ b/content/public/browser/utility_process_host_client.h @@ -23,6 +23,9 @@ class UtilityProcessHostClient // Called when the process has crashed. virtual void OnProcessCrashed(int exit_code) {} + // Called when the process fails to launch, i.e. it has no exit code. + virtual void OnProcessLaunchFailed() {} + // Allow the client to filter IPC messages. virtual bool OnMessageReceived(const IPC::Message& message) = 0; diff --git a/content/public/common/child_process_host_delegate.h b/content/public/common/child_process_host_delegate.h index 89cb70a..06d3093 100644 --- a/content/public/common/child_process_host_delegate.h +++ b/content/public/common/child_process_host_delegate.h @@ -7,6 +7,7 @@ #include <string> +#include "base/process/process.h" #include "content/common/content_export.h" #include "ipc/ipc_listener.h" @@ -26,6 +27,10 @@ class ChildProcessHostDelegate : public IPC::Listener { // Called when the child process unexpected closes the IPC channel. Delegates // would normally delete the object in this case. virtual void OnChildDisconnected() {} + + // Returns the handle of the child process. This can be called only after + // OnProcessLaunched is called or it will be invalid and may crash. + virtual base::ProcessHandle GetHandle() const = 0; }; }; // namespace content diff --git a/content/public/common/content_switches.cc b/content/public/common/content_switches.cc index 2d73c2b..977ace3 100644 --- a/content/public/common/content_switches.cc +++ b/content/public/common/content_switches.cc @@ -957,6 +957,8 @@ const char kUtilityProcessAllowedDir[] = "utility-allowed-dir"; // Allows MDns to access network in sandboxed process. const char kUtilityProcessEnableMDns[] = "utility-enable-mdns"; +const char kUtilityProcessRunningElevated[] = "utility-run-elevated"; + // Will add kWaitForDebugger to every child processes. If a value is passed, it // will be used as a filter to determine if the child process should have the // kWaitForDebugger flag passed on or not. diff --git a/content/public/common/content_switches.h b/content/public/common/content_switches.h index 41ddbe7..c902785 100644 --- a/content/public/common/content_switches.h +++ b/content/public/common/content_switches.h @@ -269,6 +269,7 @@ extern const char kUtilityCmdPrefix[]; CONTENT_EXPORT extern const char kUtilityProcess[]; extern const char kUtilityProcessAllowedDir[]; CONTENT_EXPORT extern const char kUtilityProcessEnableMDns[]; +CONTENT_EXPORT extern const char kUtilityProcessRunningElevated[]; CONTENT_EXPORT extern const char kWaitForDebuggerChildren[]; CONTENT_EXPORT extern const char kWebGLCommandBufferSizeKb[]; CONTENT_EXPORT extern const char kWorkerProcess[]; |