diff options
36 files changed, 665 insertions, 77 deletions
diff --git a/chrome/app/chrome_dll_main.cc b/chrome/app/chrome_dll_main.cc index 1e3cb83..1603d32 100644 --- a/chrome/app/chrome_dll_main.cc +++ b/chrome/app/chrome_dll_main.cc @@ -93,7 +93,7 @@ extern int NaClMain(const MainFunctionParams&); extern int UtilityMain(const MainFunctionParams&); extern int ProfileImportMain(const MainFunctionParams&); extern int ZygoteMain(const MainFunctionParams&); -#ifdef NACL_WIN64 +#if defined(_WIN64) extern int NaClBrokerMain(const MainFunctionParams&); #endif @@ -261,7 +261,7 @@ static void AdjustLinuxOOMScore(const std::string& process_type) { } else if (process_type == switches::kProfileImportProcess) { NOTIMPLEMENTED(); #ifndef DISABLE_NACL - } else if (process_type == switches::kNaClProcess) { + } else if (process_type == switches::kNaClLoaderProcess) { score = kPluginScore; #endif } else if (process_type == switches::kZygoteProcess || @@ -686,9 +686,13 @@ int ChromeMain(int argc, char** argv) { } else if (process_type == switches::kWorkerProcess) { rv = WorkerMain(main_params); #ifndef DISABLE_NACL - } else if (process_type == switches::kNaClProcess) { + } else if (process_type == switches::kNaClLoaderProcess) { rv = NaClMain(main_params); #endif +#ifdef _WIN64 // The broker process is used only on Win64. + } else if (process_type == switches::kNaClBrokerProcess) { + rv = NaClBrokerMain(main_params); +#endif } else if (process_type == switches::kZygoteProcess) { #if defined(OS_LINUX) if (ZygoteMain(main_params)) { diff --git a/chrome/app/client_util.cc b/chrome/app/client_util.cc index 993f468..a4bc50b 100644 --- a/chrome/app/client_util.cc +++ b/chrome/app/client_util.cc @@ -7,6 +7,7 @@ #include "chrome/app/breakpad_win.h" #include "chrome/app/client_util.h" +#include "chrome/common/chrome_switches.h" #include "chrome/common/result_codes.h" #include "chrome/installer/util/browser_distribution.h" #include "chrome/installer/util/install_util.h" @@ -83,7 +84,22 @@ bool EnvQueryStr(const wchar_t* key_name, std::wstring* value) { // value not being null to dermine if this path contains a valid dll. HMODULE LoadChromeWithDirectory(std::wstring* dir) { ::SetCurrentDirectoryW(dir->c_str()); +#ifdef _WIN64 + const CommandLine& cmd_line = *CommandLine::ForCurrentProcess(); + if ((cmd_line.GetSwitchValueASCII(switches::kProcessType) == + switches::kNaClBrokerProcess) || + (cmd_line.GetSwitchValueASCII(switches::kProcessType) == + switches::kNaClLoaderProcess)) { + // Load the 64-bit DLL when running in a 64-bit process. + dir->append(installer_util::kChromeNaCl64Dll); + } else { + // Only NaCl broker and loader can be launched as Win64 processes. + NOTREACHED(); + return NULL; + } +#else dir->append(installer_util::kChromeDll); +#endif return ::LoadLibraryExW(dir->c_str(), NULL, LOAD_WITH_ALTERED_SEARCH_PATH); } diff --git a/chrome/app/dummy_main_functions.cc b/chrome/app/dummy_main_functions.cc index 192720e..c8b7c5e 100644 --- a/chrome/app/dummy_main_functions.cc +++ b/chrome/app/dummy_main_functions.cc @@ -35,10 +35,6 @@ int ZygoteMain(const MainFunctionParams& parameters) { return ResultCodes::BAD_PROCESS_TYPE; } -int NaClBrokerMain(const MainFunctionParams& parameters) { - return ResultCodes::BAD_PROCESS_TYPE; -} - int DiagnosticsMain(const CommandLine& command_line) { return 1; } diff --git a/chrome/browser/memory_details.cc b/chrome/browser/memory_details.cc index f212698..4c7e2fb 100644 --- a/chrome/browser/memory_details.cc +++ b/chrome/browser/memory_details.cc @@ -209,7 +209,7 @@ void MemoryDetails::UpdateHistograms() { case ChildProcessInfo::SANDBOX_HELPER_PROCESS: UMA_HISTOGRAM_MEMORY_KB("Memory.SandboxHelper", sample); break; - case ChildProcessInfo::NACL_PROCESS: + case ChildProcessInfo::NACL_LOADER_PROCESS: UMA_HISTOGRAM_MEMORY_KB("Memory.NativeClient", sample); break; default: diff --git a/chrome/browser/nacl_host/nacl_broker_host.cc b/chrome/browser/nacl_host/nacl_broker_host.cc new file mode 100644 index 0000000..8abc228 --- /dev/null +++ b/chrome/browser/nacl_host/nacl_broker_host.cc @@ -0,0 +1,74 @@ +// Copyright (c) 2010 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/browser/nacl_host/nacl_broker_host.h" + +#include "base/command_line.h" +#include "ipc/ipc_switches.h" +#include "chrome/browser/browser_process.h" +#include "chrome/browser/nacl_host/nacl_broker_service.h" +#include "chrome/browser/nacl_process_host.h" +#include "chrome/common/chrome_constants.h" +#include "chrome/common/chrome_switches.h" +#include "chrome/common/nacl_cmd_line.h" +#include "chrome/common/nacl_messages.h" + +NaClBrokerHost::NaClBrokerHost( + ResourceDispatcherHost* resource_dispatcher_host) + : ChildProcessHost(NACL_BROKER_PROCESS, resource_dispatcher_host) { +} + +NaClBrokerHost::~NaClBrokerHost() { +} + +URLRequestContext* NaClBrokerHost::GetRequestContext( + uint32 request_id, + const ViewHostMsg_Resource_Request& request_data) { + return NULL; +} + +bool NaClBrokerHost::Init() { + // Create the channel that will be used for communicating with the broker. + if (!CreateChannel()) + return false; + + // Create the path to the nacl broker/loader executable. + FilePath exe_path = GetChildPath(false); + if (exe_path.empty()) + return false; + + FilePath nacl_path = exe_path.DirName().Append(chrome::kNaClAppName); + CommandLine* cmd_line = new CommandLine(nacl_path); + nacl::CopyNaClCommandLineArguments(cmd_line); + + cmd_line->AppendSwitchWithValue(switches::kProcessType, + switches::kNaClBrokerProcess); + + cmd_line->AppendSwitchWithValue(switches::kProcessChannelID, + ASCIIToWide(channel_id())); + + ChildProcessHost::Launch(FilePath(), cmd_line); + return true; +} + +void NaClBrokerHost::OnMessageReceived(const IPC::Message& msg) { + IPC_BEGIN_MESSAGE_MAP(NaClBrokerHost, msg) + IPC_MESSAGE_HANDLER(NaClProcessMsg_BrokerReady, OnBrokerReady) + IPC_MESSAGE_HANDLER(NaClProcessMsg_LoaderLaunched, OnLoaderLaunched) + IPC_END_MESSAGE_MAP() +} + +void NaClBrokerHost::OnBrokerReady() { + NaClBrokerService::GetInstance()->OnBrokerStarted(); +} + +bool NaClBrokerHost::LaunchLoader( + const std::wstring& loader_channel_id) { + return Send(new NaClProcessMsg_LaunchLoaderThroughBroker(loader_channel_id)); +} + +void NaClBrokerHost::OnLoaderLaunched(const std::wstring& loader_channel_id, + base::ProcessHandle handle) { + NaClBrokerService::GetInstance()->OnLoaderLaunched(loader_channel_id, handle); +} diff --git a/chrome/browser/nacl_host/nacl_broker_host.h b/chrome/browser/nacl_host/nacl_broker_host.h new file mode 100644 index 0000000..f526aa1 --- /dev/null +++ b/chrome/browser/nacl_host/nacl_broker_host.h @@ -0,0 +1,46 @@ +// Copyright (c) 2010 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_BROWSER_NACL_HOST_NACL_BROKER_HOST_H_ +#define CHROME_BROWSER_NACL_HOST_NACL_BROKER_HOST_H_ + +#include "base/basictypes.h" +#include "base/process.h" +#include "chrome/common/child_process_host.h" +#include "ipc/ipc_message.h" + +class NaClBrokerHost : public ChildProcessHost { + public: + explicit NaClBrokerHost(ResourceDispatcherHost* resource_dispatcher_host); + ~NaClBrokerHost(); + + // This function starts the broker process. It needs to be called + // before loaders can be launched. + bool Init(); + + // Send a message to the broker process, causing it to launch + // a Native Client loader process. + bool LaunchLoader(const std::wstring& loader_channel_id); + + private: + // ResourceDispatcherHost::Receiver implementation: + virtual URLRequestContext* GetRequestContext( + uint32 request_id, + const ViewHostMsg_Resource_Request& request_data); + + virtual bool CanShutdown() { return true; } + + // Handler for NaClProcessMsg_BrokerReady message (sent by the broker process) + void OnBrokerReady(); + // Handler for NaClProcessMsg_LoaderLaunched message + void OnLoaderLaunched(const std::wstring& loader_channel_id, + base::ProcessHandle handle); + + // IPC::Channel::Listener + virtual void OnMessageReceived(const IPC::Message& msg); + + DISALLOW_COPY_AND_ASSIGN(NaClBrokerHost); +}; + +#endif // CHROME_BROWSER_NACL_HOST_NACL_BROKER_HOST_H_ diff --git a/chrome/browser/nacl_host/nacl_broker_service.cc b/chrome/browser/nacl_host/nacl_broker_service.cc new file mode 100644 index 0000000..ef659cd --- /dev/null +++ b/chrome/browser/nacl_host/nacl_broker_service.cc @@ -0,0 +1,69 @@ +// Copyright (c) 2010 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/browser/nacl_host/nacl_broker_service.h" + +#include "chrome/browser/browser_process.h" +#include "chrome/browser/nacl_process_host.h" +#include "chrome/common/chrome_switches.h" + +NaClBrokerService* NaClBrokerService::GetInstance() { + return Singleton<NaClBrokerService>::get(); +} + +NaClBrokerService::NaClBrokerService() + : broker_started_(false), + broker_host_(NULL), + resource_dispatcher_host_(NULL), + initialized_(false) { +} + +void NaClBrokerService::Init(ResourceDispatcherHost* resource_dispatcher_host) { + if (initialized_) { + return; + } + resource_dispatcher_host_ = resource_dispatcher_host; + StartBroker(); + initialized_ = true; +} + +bool NaClBrokerService::StartBroker() { + broker_host_.reset(new NaClBrokerHost(resource_dispatcher_host_)); + if (!broker_host_->Init()) { + // Initialization failed, we will not retry in the future + broker_host_.reset(NULL); + } + return (broker_host_ != NULL); +} + +bool NaClBrokerService::LaunchLoader(NaClProcessHost* nacl_process_host, + const std::wstring& loader_channel_id) { + if (broker_started_) { + broker_host_->LaunchLoader(loader_channel_id); + } else { + // Add task to the list + pending_launches_[loader_channel_id] = nacl_process_host; + } + return true; +} + +void NaClBrokerService::OnBrokerStarted() { + PendingLaunchesMap::iterator it; + for (it = pending_launches_.begin(); it != pending_launches_.end(); it++) { + broker_host_->LaunchLoader(it->first); + } + broker_started_ = true; +} + +void NaClBrokerService::OnLoaderLaunched(const std::wstring& channel_id, + base::ProcessHandle handle) { + NaClProcessHost* client; + PendingLaunchesMap::iterator it = pending_launches_.find(channel_id); + if (pending_launches_.end() == it) { + NOTREACHED(); + } + client = it->second; + client->OnProcessLaunchedByBroker(handle); + pending_launches_.erase(it); +} diff --git a/chrome/browser/nacl_host/nacl_broker_service.h b/chrome/browser/nacl_host/nacl_broker_service.h new file mode 100644 index 0000000..75e089d --- /dev/null +++ b/chrome/browser/nacl_host/nacl_broker_service.h @@ -0,0 +1,57 @@ +// Copyright (c) 2010 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_BROWSER_NACL_HOST_NACL_BROKER_SERVICE_H_ +#define CHROME_BROWSER_NACL_HOST_NACL_BROKER_SERVICE_H_ + +#include <map> + +#include "base/basictypes.h" +#include "base/singleton.h" +#include "chrome/browser/nacl_host/nacl_broker_host.h" + +class NaClProcessHost; + +class NaClBrokerService { + public: + // Returns the NaClBrokerService singleton. + static NaClBrokerService* GetInstance(); + + void Init(ResourceDispatcherHost* resource_dispatcher_host); + + // Can be called several times, must be called before LaunchLoader. + bool StartBroker(); + + // Send a message to the broker process, causing it to launch + // a Native Client loader process. + bool LaunchLoader(NaClProcessHost* client, + const std::wstring& loader_channel_id); + + // Called by NaClBrokerHost to notify the service + // that the broker was launched. + void OnBrokerStarted(); + + // Called by NaClBrokerHost to notify the service that a loader was launched. + void OnLoaderLaunched(const std::wstring& channel_id, + base::ProcessHandle handle); + + private: + typedef std::map<std::wstring, NaClProcessHost*> + PendingLaunchesMap; + + friend struct DefaultSingletonTraits<NaClBrokerService>; + + NaClBrokerService(); + ~NaClBrokerService() {} + + bool broker_started_; + scoped_ptr<NaClBrokerHost> broker_host_; + bool initialized_; + ResourceDispatcherHost* resource_dispatcher_host_; + PendingLaunchesMap pending_launches_; + + DISALLOW_COPY_AND_ASSIGN(NaClBrokerService); +}; + +#endif // CHROME_BROWSER_NACL_HOST_NACL_BROKER_SERVICE_H_ diff --git a/chrome/browser/nacl_process_host.cc b/chrome/browser/nacl_process_host.cc index f736ab7..9f57620 100644 --- a/chrome/browser/nacl_process_host.cc +++ b/chrome/browser/nacl_process_host.cc @@ -10,9 +10,12 @@ #include <fcntl.h> #endif +#include "base/command_line.h" +#include "chrome/browser/nacl_host/nacl_broker_service.h" #include "chrome/browser/renderer_host/resource_message_filter.h" #include "chrome/common/chrome_switches.h" #include "chrome/common/logging_chrome.h" +#include "chrome/common/nacl_cmd_line.h" #include "chrome/common/nacl_messages.h" #include "chrome/common/render_messages.h" #include "ipc/ipc_switches.h" @@ -24,11 +27,15 @@ NaClProcessHost::NaClProcessHost( ResourceDispatcherHost *resource_dispatcher_host, const std::wstring& url) - : ChildProcessHost(NACL_PROCESS, resource_dispatcher_host), + : ChildProcessHost(NACL_LOADER_PROCESS, resource_dispatcher_host), resource_dispatcher_host_(resource_dispatcher_host), reply_msg_(NULL), - descriptor_(0) { + descriptor_(0), + running_on_wow64_(false) { set_name(url); +#if defined(OS_WIN) + CheckIsWow64(); +#endif } NaClProcessHost::~NaClProcessHost() { @@ -77,73 +84,67 @@ bool NaClProcessHost::LaunchSelLdr() { return false; CommandLine* cmd_line = new CommandLine(exe_path); - if (logging::DialogsAreSuppressed()) - cmd_line->AppendSwitch(switches::kNoErrorDialogs); - - // Propagate the following switches to the plugin command line (along with - // any associated values) if present in the browser command line. - // TODO(gregoryd): check which flags of those below can be supported. - static const char* const switch_names[] = { - switches::kNoSandbox, - switches::kTestSandbox, - switches::kDisableBreakpad, - switches::kFullMemoryCrashReport, - switches::kEnableLogging, - switches::kDisableLogging, - switches::kLoggingLevel, - switches::kEnableDCHECK, - switches::kSilentDumpOnDCHECK, - switches::kMemoryProfiling, -#if defined(OS_MACOSX) - // TODO(dspringer): remove this when NaCl x86-32 security issues are fixed - switches::kEnableNaClOnMac, -#endif - }; - - const CommandLine& browser_command_line = *CommandLine::ForCurrentProcess(); + nacl::CopyNaClCommandLineArguments(cmd_line); #if defined(OS_MACOSX) -// TODO(dspringer): NaCl is temporalrily disabled on the Mac by default, but it -// can be enabled with the --enable-nacl cmd-line switch. Remove this check -// when the security issues in the Mac PIC code are resolved. - if (!browser_command_line.HasSwitch(switches::kEnableNaClOnMac)) + // TODO(dspringer): NaCl is temporalrily disabled on the Mac by default, but + // it can be enabled with the --enable-nacl cmd-line switch. Remove this check + // when the security issues in the Mac PIC code are resolved. + if (!cmd_line->HasSwitch(switches::kEnableNaCl)) return false; #endif - for (size_t i = 0; i < arraysize(switch_names); ++i) { - if (browser_command_line.HasSwitch(switch_names[i])) { - cmd_line->AppendSwitchWithValue(switch_names[i], - browser_command_line.GetSwitchValueASCII(switch_names[i])); - } - } - cmd_line->AppendSwitchWithValue(switches::kProcessType, - switches::kNaClProcess); + switches::kNaClLoaderProcess); cmd_line->AppendSwitchWithValue(switches::kProcessChannelID, ASCIIToWide(channel_id())); - ChildProcessHost::Launch( + // On Windows we might need to start the broker process to launch a new loader #if defined(OS_WIN) - FilePath(), + if (running_on_wow64_) { + NaClBrokerService::GetInstance()->Init(resource_dispatcher_host_); + NaClBrokerService::GetInstance()->LaunchLoader(this, + ASCIIToWide(channel_id())); + } else +#endif + ChildProcessHost::Launch( +#if defined(OS_WIN) + FilePath(), #elif defined(OS_POSIX) - false, - base::environment_vector(), + false, + base::environment_vector(), #endif - cmd_line); + cmd_line); return true; } +void NaClProcessHost::OnProcessLaunchedByBroker(base::ProcessHandle handle) { + set_handle(handle); + OnProcessLaunched(); +} + +bool NaClProcessHost::DidChildCrash() { + if (running_on_wow64_) { + bool child_exited; + return base::DidProcessCrash(&child_exited, handle()); + } + return ChildProcessHost::DidChildCrash(); +} + void NaClProcessHost::OnProcessLaunched() { nacl::FileDescriptor imc_handle; base::ProcessHandle nacl_process_handle; #if NACL_WINDOWS // Duplicate the IMC handle + // We assume the size of imc_handle has the same size as HANDLE, so the cast + // below is safe. + DCHECK(sizeof(HANDLE) == sizeof(imc_handle)); DuplicateHandle(base::GetCurrentProcessHandle(), reinterpret_cast<HANDLE>(pair_[0]), resource_message_filter_->handle(), - &imc_handle, + reinterpret_cast<HANDLE*>(&imc_handle), GENERIC_READ | GENERIC_WRITE, FALSE, DUPLICATE_CLOSE_SOURCE); @@ -212,3 +213,24 @@ URLRequestContext* NaClProcessHost::GetRequestContext( const ViewHostMsg_Resource_Request& request_data) { return NULL; } + +#if defined(OS_WIN) +// TODO(gregoryd): invoke CheckIsWow64 only once, not for each NaClProcessHost +typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL); +void NaClProcessHost::CheckIsWow64() { + LPFN_ISWOW64PROCESS fnIsWow64Process; + + fnIsWow64Process = (LPFN_ISWOW64PROCESS) GetProcAddress( + GetModuleHandle(TEXT("kernel32")), + "IsWow64Process"); + + if (fnIsWow64Process != NULL) { + BOOL bIsWow64 = FALSE; + if (fnIsWow64Process(GetCurrentProcess(),&bIsWow64)) { + if (bIsWow64) { + running_on_wow64_ = true; + } + } + } +} +#endif diff --git a/chrome/browser/nacl_process_host.h b/chrome/browser/nacl_process_host.h index 8159836..ca416f6 100644 --- a/chrome/browser/nacl_process_host.h +++ b/chrome/browser/nacl_process_host.h @@ -33,6 +33,11 @@ class NaClProcessHost : public ChildProcessHost { virtual void OnMessageReceived(const IPC::Message& msg); + void OnProcessLaunchedByBroker(base::ProcessHandle handle); + + protected: + virtual bool DidChildCrash(); + private: bool LaunchSelLdr(); @@ -47,6 +52,11 @@ class NaClProcessHost : public ChildProcessHost { virtual bool CanShutdown() { return true; } +#if defined(OS_WIN) + // Check whether the browser process is running on WOW64 - Windows only + void CheckIsWow64(); +#endif + private: ResourceDispatcherHost* resource_dispatcher_host_; @@ -63,6 +73,9 @@ class NaClProcessHost : public ChildProcessHost { // The NaCl specific descriptor for this process. int descriptor_; + // Windows platform flag + bool running_on_wow64_; + DISALLOW_COPY_AND_ASSIGN(NaClProcessHost); }; diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index 6adda93..b9a7475 100755 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi @@ -2205,6 +2205,11 @@ '../views/views.gyp:views', ], 'sources': [ + # NaCl broker is used on Windows only + 'browser/nacl_host/nacl_broker_host.cc', + 'browser/nacl_host/nacl_broker_host.h', + 'browser/nacl_host/nacl_broker_service.cc', + 'browser/nacl_host/nacl_broker_service.h', 'browser/net/ssl_config_service_manager_system.cc', # Using built-in rule in vstudio for midl. 'browser/history/history_indexer.idl', diff --git a/chrome/chrome_common.gypi b/chrome/chrome_common.gypi index ffb4bb3..c0205b2 100644 --- a/chrome/chrome_common.gypi +++ b/chrome/chrome_common.gypi @@ -60,7 +60,10 @@ 'common/main_function_params.h', 'common/message_router.cc', 'common/message_router.h', + 'common/nacl_cmd_line.cc', + 'common/nacl_cmd_line.h', 'common/nacl_messages.h', + 'common/nacl_types.h', 'common/nacl_messages_internal.h', 'common/notification_details.h', 'common/notification_observer.h', diff --git a/chrome/common/child_process_host.cc b/chrome/common/child_process_host.cc index 9fb6b52..51c6de4 100644 --- a/chrome/common/child_process_host.cc +++ b/chrome/common/child_process_host.cc @@ -177,9 +177,13 @@ void ChildProcessHost::Notify(NotificationType type) { ChromeThread::UI, FROM_HERE, new ChildNotificationTask(type, this)); } +bool ChildProcessHost::DidChildCrash() { + return child_process_->DidProcessCrash(); +} + void ChildProcessHost::OnChildDied() { - if (child_process_->GetHandle()) { - bool did_crash = child_process_->DidProcessCrash(); + if (handle() != base::kNullProcessHandle) { + bool did_crash = DidChildCrash(); if (did_crash) { OnProcessCrashed(); // Report that this child process crashed. diff --git a/chrome/common/child_process_host.h b/chrome/common/child_process_host.h index ec6e86d..22d5cc3 100644 --- a/chrome/common/child_process_host.h +++ b/chrome/common/child_process_host.h @@ -116,6 +116,8 @@ class ChildProcessHost : public ResourceDispatcherHost::Receiver, bool opening_channel() { return opening_channel_; } const std::string& channel_id() { return channel_id_; } + virtual bool DidChildCrash(); + private: // Sends the given notification to the notification service on the UI thread. void Notify(NotificationType type); diff --git a/chrome/common/child_process_info.cc b/chrome/common/child_process_info.cc index c915e80..473512f 100644 --- a/chrome/common/child_process_info.cc +++ b/chrome/common/child_process_info.cc @@ -54,7 +54,7 @@ std::wstring ChildProcessInfo::GetTypeNameInEnglish( return L"Zygote"; case SANDBOX_HELPER_PROCESS: return L"Sandbox helper"; - case NACL_PROCESS: + case NACL_LOADER_PROCESS: return L"Native Client module"; case UNKNOWN_PROCESS: default: @@ -77,7 +77,7 @@ std::wstring ChildProcessInfo::GetLocalizedTitle() const { message_id = IDS_TASK_MANAGER_UTILITY_PREFIX; } else if (type_ == ChildProcessInfo::PROFILE_IMPORT_PROCESS) { message_id = IDS_TASK_MANAGER_PROFILE_IMPORT_PREFIX; - } else if (type_ == ChildProcessInfo::NACL_PROCESS) { + } else if (type_ == ChildProcessInfo::NACL_LOADER_PROCESS) { message_id = IDS_TASK_MANAGER_NACL_PREFIX; } else { DCHECK(false) << "Need localized name for child process type."; diff --git a/chrome/common/child_process_info.h b/chrome/common/child_process_info.h index 5726675..1607417 100644 --- a/chrome/common/child_process_info.h +++ b/chrome/common/child_process_info.h @@ -20,11 +20,12 @@ class ChildProcessInfo { RENDER_PROCESS, PLUGIN_PROCESS, WORKER_PROCESS, - NACL_PROCESS, + NACL_LOADER_PROCESS, UTILITY_PROCESS, PROFILE_IMPORT_PROCESS, ZYGOTE_PROCESS, SANDBOX_HELPER_PROCESS, + NACL_BROKER_PROCESS, GPU_PROCESS }; diff --git a/chrome/common/chrome_constants.cc b/chrome/common/chrome_constants.cc index c75ab65..8226cd8 100644 --- a/chrome/common/chrome_constants.cc +++ b/chrome/common/chrome_constants.cc @@ -52,6 +52,7 @@ const FilePath::CharType kHelperProcessExecutablePath[] = const FilePath::CharType kFrameworkName[] = FPL(PRODUCT_STRING " Framework.framework"); #endif // OS_MACOSX +const wchar_t kNaClAppName[] = L"nacl"; #if defined(GOOGLE_CHROME_BUILD) const wchar_t kBrowserAppName[] = L"Chrome"; const char kStatsFilename[] = "ChromeStats2"; diff --git a/chrome/common/chrome_constants.h b/chrome/common/chrome_constants.h index c8121d0..fc271e0 100644 --- a/chrome/common/chrome_constants.h +++ b/chrome/common/chrome_constants.h @@ -31,6 +31,7 @@ extern const wchar_t kNotSignedInProfile[]; extern const wchar_t kNotSignedInID[]; extern const char kStatsFilename[]; extern const wchar_t kBrowserResourcesDll[]; +extern const wchar_t kNaClAppName[]; extern const FilePath::CharType kExtensionFileExtension[]; // filenames diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc index 574752a..c9bc494 100644 --- a/chrome/common/chrome_switches.cc +++ b/chrome/common/chrome_switches.cc @@ -384,8 +384,12 @@ const char kMessageLoopHistogrammer[] = "message-loop-histogrammer"; // and performance tests. const char kMetricsRecordingOnly[] = "metrics-recording-only"; -// Causes the process to run as a NativeClient's sel_ldr subprocess. -const char kNaClProcess[] = "nacl"; +// Causes the process to run as a NativeClient broker +// (used for launching NaCl loader processes on 64-bit Windows). +const char kNaClBrokerProcess[] = "nacl-broker"; + +// Causes the process to run as a NativeClient loader. +const char kNaClLoaderProcess[] = "nacl-loader"; // Causes the Native Client process to display a dialog on launch. const char kNaClStartupDialog[] = "nacl-startup-dialog"; diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h index 4f8d4d6..856df24 100644 --- a/chrome/common/chrome_switches.h +++ b/chrome/common/chrome_switches.h @@ -121,7 +121,8 @@ extern const char kMediaCacheSize[]; extern const char kMemoryProfiling[]; extern const char kMessageLoopHistogrammer[]; extern const char kMetricsRecordingOnly[]; -extern const char kNaClProcess[]; +extern const char kNaClBrokerProcess[]; +extern const char kNaClLoaderProcess[]; extern const char kNaClStartupDialog[]; extern const char kNewTabPage[]; extern const char kNoDefaultBrowserCheck[]; diff --git a/chrome/common/nacl_cmd_line.cc b/chrome/common/nacl_cmd_line.cc new file mode 100644 index 0000000..2212c68 --- /dev/null +++ b/chrome/common/nacl_cmd_line.cc @@ -0,0 +1,44 @@ +// Copyright (c) 2010 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/command_line.h" +#include "chrome/common/chrome_constants.h" +#include "chrome/common/chrome_switches.h" +#include "chrome/common/logging_chrome.h" + +namespace nacl { + void CopyNaClCommandLineArguments(CommandLine* cmd_line) { + const CommandLine& browser_command_line = *CommandLine::ForCurrentProcess(); + if (logging::DialogsAreSuppressed()) + cmd_line->AppendSwitch(switches::kNoErrorDialogs); + + // Propagate the following switches to the NaCl loader command line (along + // with any associated values) if present in the browser command line. + // TODO(gregoryd): check which flags of those below can be supported. + static const char* const switch_names[] = { + switches::kNoSandbox, + switches::kTestSandbox, + switches::kDisableBreakpad, + switches::kFullMemoryCrashReport, + switches::kEnableLogging, + switches::kDisableLogging, + switches::kLoggingLevel, + switches::kEnableDCHECK, + switches::kSilentDumpOnDCHECK, + switches::kMemoryProfiling, +#if defined(OS_MACOSX) + // TODO(dspringer): remove this when NaCl x86-32 security issues are fixed + switches::kEnableNaClOnMac, +#endif + }; + + for (size_t i = 0; i < arraysize(switch_names); ++i) { + if (browser_command_line.HasSwitch(switch_names[i])) { + cmd_line->AppendSwitchWithValue( + switch_names[i], + browser_command_line.GetSwitchValueASCII(switch_names[i])); + } + } + } +} diff --git a/chrome/common/nacl_cmd_line.h b/chrome/common/nacl_cmd_line.h new file mode 100644 index 0000000..1091e11 --- /dev/null +++ b/chrome/common/nacl_cmd_line.h @@ -0,0 +1,16 @@ +// Copyright (c) 2010 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_COMMON_NACL_CMD_LINE_H_ +#define CHROME_COMMON_NACL_CMD_LINE_H_ + +#include "base/command_line.h" + +namespace nacl { + // Copy all the relevant arguments from the command line of the current + // process to cmd_line that will be used for launching the NaCl loader/broker. + void CopyNaClCommandLineArguments(CommandLine* cmd_line); +} + +#endif // CHROME_COMMON_NACL_CMD_LINE_H_ diff --git a/chrome/common/nacl_messages_internal.h b/chrome/common/nacl_messages_internal.h index 3794255..11dfba7 100644 --- a/chrome/common/nacl_messages_internal.h +++ b/chrome/common/nacl_messages_internal.h @@ -14,5 +14,16 @@ IPC_BEGIN_MESSAGES(NaClProcess) int /* descriptor id */, nacl::FileDescriptor /* handle value */) + // Tells the NaCl broker to launch a NaCl loader process. + IPC_MESSAGE_CONTROL1(NaClProcessMsg_LaunchLoaderThroughBroker, + std::wstring /* channel ID for the loader */) + + // Notify the browser process that the loader was launched successfully. + IPC_MESSAGE_CONTROL2(NaClProcessMsg_LoaderLaunched, + std::wstring, /* channel ID for the loader */ + base::ProcessHandle /* loader process handle */) + + // Notify the browser process that the broker is ready (sent by the broker) + IPC_MESSAGE_CONTROL0(NaClProcessMsg_BrokerReady) IPC_END_MESSAGES(NaClProcess) diff --git a/chrome/common/nacl_types.h b/chrome/common/nacl_types.h index 394edd3..5c5f5dc 100644 --- a/chrome/common/nacl_types.h +++ b/chrome/common/nacl_types.h @@ -6,15 +6,23 @@ #ifndef CHROME_COMMON_NACL_TYPES_H_ #define CHROME_COMMON_NACL_TYPES_H_ -// TODO(gregoryd): add a Windows definition for base::FileDescriptor, -// replace the macros with inline functions. +#if defined(OS_POSIX) +#include "base/file_descriptor_posix.h" +#endif + +// TODO(gregoryd): add a Windows definition for base::FileDescriptor namespace nacl { #if defined(OS_WIN) -typedef HANDLE FileDescriptor; -#define NATIVE_HANDLE(desc) (desc) + // We assume that HANDLE always uses less than 32 bits + typedef int FileDescriptor; + inline HANDLE ToNativeHandle(const FileDescriptor& desc) { + return reinterpret_cast<HANDLE>(desc); + } #elif defined(OS_POSIX) -typedef base::FileDescriptor FileDescriptor; -#define NATIVE_HANDLE(desc) ((desc).fd) + typedef base::FileDescriptor FileDescriptor; + inline int ToNativeHandle(const FileDescriptor& desc) { + return desc.fd; + } #endif } diff --git a/chrome/common/sandbox_init_wrapper_mac.cc b/chrome/common/sandbox_init_wrapper_mac.cc index 3341b08..a47240d 100644 --- a/chrome/common/sandbox_init_wrapper_mac.cc +++ b/chrome/common/sandbox_init_wrapper_mac.cc @@ -39,7 +39,7 @@ bool SandboxInitWrapper::InitializeSandbox(const CommandLine& command_line, } else if (process_type == switches::kWorkerProcess) { // Worker process sandbox. sandbox_process_type = sandbox::SANDBOX_TYPE_WORKER; - } else if ((process_type == switches::kNaClProcess) || + } else if ((process_type == switches::kNaClLoaderProcess) || (process_type == switches::kPluginProcess) || (process_type == switches::kProfileImportProcess)) { return true; diff --git a/chrome/common/sandbox_init_wrapper_win.cc b/chrome/common/sandbox_init_wrapper_win.cc index 0bfba24..5d4399a 100644 --- a/chrome/common/sandbox_init_wrapper_win.cc +++ b/chrome/common/sandbox_init_wrapper_win.cc @@ -21,7 +21,7 @@ bool SandboxInitWrapper::InitializeSandbox(const CommandLine& command_line, if ((process_type == switches::kRendererProcess) || (process_type == switches::kExtensionProcess) || (process_type == switches::kWorkerProcess) || - (process_type == switches::kNaClProcess) || + (process_type == switches::kNaClLoaderProcess) || (process_type == switches::kUtilityProcess) || (process_type == switches::kPluginProcess && command_line.HasSwitch(switches::kSafePlugins))) { diff --git a/chrome/common/sandbox_policy.cc b/chrome/common/sandbox_policy.cc index 9e70b08..a79a962 100644 --- a/chrome/common/sandbox_policy.cc +++ b/chrome/common/sandbox_policy.cc @@ -23,6 +23,13 @@ #include "sandbox/src/sandbox.h" #include "webkit/glue/plugins/plugin_list.h" +#ifdef NACL_WIN64 + // The sandbox can be used also by the NaCl broker process. In this case we + // define a global variable g_broker_services instead of g_browser_process. + // This can be changed if we discover that the broker process needs to be more + // similar to the browser process. + extern sandbox::BrokerServices* g_broker_services; +#endif namespace { // The DLLs listed here are known (or under strong suspicion) of causing crashes @@ -342,10 +349,12 @@ base::ProcessHandle StartProcessWithAccess(CommandLine* cmd_line, type = ChildProcessInfo::PLUGIN_PROCESS; } else if (type_str == switches::kWorkerProcess) { type = ChildProcessInfo::WORKER_PROCESS; - } else if (type_str == switches::kNaClProcess) { - type = ChildProcessInfo::NACL_PROCESS; + } else if (type_str == switches::kNaClLoaderProcess) { + type = ChildProcessInfo::NACL_LOADER_PROCESS; } else if (type_str == switches::kUtilityProcess) { type = ChildProcessInfo::UTILITY_PROCESS; + } else if (type_str == switches::kNaClBrokerProcess) { + type = ChildProcessInfo::NACL_BROKER_PROCESS; } else if (type_str == switches::kGpuProcess) { type = ChildProcessInfo::GPU_PROCESS; } else { @@ -379,10 +388,15 @@ base::ProcessHandle StartProcessWithAccess(CommandLine* cmd_line, return process; } +#ifdef NACL_WIN64 + // When running in the broker we get the BrokerServices pointer from a global + // variable. It is initialized in NaClBrokerMain. + sandbox::BrokerServices* broker_service = g_broker_services; +#else // spawn the child process in the sandbox sandbox::BrokerServices* broker_service = g_browser_process->broker_services(); - +#endif sandbox::ResultCode result; PROCESS_INFORMATION target = {0}; sandbox::TargetPolicy* policy = broker_service->CreatePolicy(); diff --git a/chrome/installer/util/util_constants.cc b/chrome/installer/util/util_constants.cc index 5505685..6b89abf 100644 --- a/chrome/installer/util/util_constants.cc +++ b/chrome/installer/util/util_constants.cc @@ -113,6 +113,7 @@ const wchar_t kChromeExe[] = L"chrome.exe"; const wchar_t kChromeOldExe[] = L"old_chrome.exe"; const wchar_t kChromeNewExe[] = L"new_chrome.exe"; const wchar_t kChromeDll[] = L"chrome.dll"; +const wchar_t kChromeNaCl64Dll[] = L"chrome_nacl_win64.dll"; const wchar_t kChromeFrameDll[] = L"npchrome_frame.dll"; const wchar_t kSetupExe[] = L"setup.exe"; const wchar_t kInstallerDir[] = L"Installer"; diff --git a/chrome/installer/util/util_constants.h b/chrome/installer/util/util_constants.h index f510cdc..b3a4eed 100644 --- a/chrome/installer/util/util_constants.h +++ b/chrome/installer/util/util_constants.h @@ -81,6 +81,7 @@ extern const wchar_t kChromeExe[]; extern const wchar_t kChromeOldExe[]; extern const wchar_t kChromeNewExe[]; extern const wchar_t kChromeDll[]; +extern const wchar_t kChromeNaCl64Dll[]; extern const wchar_t kChromeFrameDll[]; extern const wchar_t kSetupExe[]; extern const wchar_t kInstallerDir[]; diff --git a/chrome/nacl.gypi b/chrome/nacl.gypi index 696b60d..d142af7 100644 --- a/chrome/nacl.gypi +++ b/chrome/nacl.gypi @@ -86,6 +86,10 @@ 'chrome_strings', 'common_nacl_win64', ], + 'sources': [ + 'nacl/broker_thread.cc', + 'nacl/broker_thread.h', + ], 'defines': [ '<@(nacl_win64_defines)', ], diff --git a/chrome/nacl/broker_thread.cc b/chrome/nacl/broker_thread.cc new file mode 100644 index 0000000..0b4bbd2 --- /dev/null +++ b/chrome/nacl/broker_thread.cc @@ -0,0 +1,72 @@ +// Copyright (c) 2010 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/nacl/broker_thread.h" + +#include "base/base_switches.h" +#include "base/command_line.h" +#include "base/path_service.h" +#include "base/process_util.h" +#include "chrome/common/sandbox_policy.h" +#include "chrome/common/chrome_switches.h" +#include "chrome/common/nacl_cmd_line.h" +#include "chrome/common/nacl_messages.h" +#include "ipc/ipc_switches.h" + +NaClBrokerThread::NaClBrokerThread() + : browser_handle_(0), + broker_services_(NULL) { +} + +NaClBrokerThread::~NaClBrokerThread() { + base::CloseProcessHandle(browser_handle_); +} + +NaClBrokerThread* NaClBrokerThread::current() { + return static_cast<NaClBrokerThread*>(ChildThread::current()); +} + +void NaClBrokerThread::OnControlMessageReceived(const IPC::Message& msg) { + IPC_BEGIN_MESSAGE_MAP(NaClBrokerThread, msg) + IPC_MESSAGE_HANDLER(NaClProcessMsg_LaunchLoaderThroughBroker, + OnLaunchLoaderThroughBroker) + IPC_END_MESSAGE_MAP() +} + +void NaClBrokerThread::OnLaunchLoaderThroughBroker( + const std::wstring& loader_channel_id) { + base::ProcessHandle loader_process = 0; + base::ProcessHandle loader_handle_in_browser = 0; + + // Create the path to the nacl broker/loader executable - it's the executable + // this code is running in. + FilePath exe_path; + PathService::Get(base::FILE_EXE, &exe_path); + if (!exe_path.empty()) { + CommandLine* cmd_line = new CommandLine(exe_path); + nacl::CopyNaClCommandLineArguments(cmd_line); + + cmd_line->AppendSwitchWithValue(switches::kProcessType, + switches::kNaClLoaderProcess); + + cmd_line->AppendSwitchWithValue(switches::kProcessChannelID, + loader_channel_id); + + loader_process = sandbox::StartProcessWithAccess(cmd_line, FilePath()); + if (loader_process) { + DuplicateHandle(::GetCurrentProcess(), loader_process, + browser_handle_, &loader_handle_in_browser, + PROCESS_DUP_HANDLE, FALSE, 0); + } + } + Send(new NaClProcessMsg_LoaderLaunched(loader_channel_id, + loader_handle_in_browser)); +} + +void NaClBrokerThread::OnChannelConnected(int32 peer_pid) { + bool res = base::OpenProcessHandle(peer_pid, &browser_handle_); + DCHECK(res); + Send(new NaClProcessMsg_BrokerReady()); +} + diff --git a/chrome/nacl/broker_thread.h b/chrome/nacl/broker_thread.h new file mode 100644 index 0000000..d88919f --- /dev/null +++ b/chrome/nacl/broker_thread.h @@ -0,0 +1,37 @@ +// Copyright (c) 2010 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_NACL_BROKER_THREAD_H_ +#define CHROME_NACL_BROKER_THREAD_H_ + +#include "chrome/common/child_thread.h" +#include "chrome/common/nacl_types.h" + +#if defined(OS_WIN) +#include "sandbox/src/sandbox.h" +#endif + +// The BrokerThread class represents the thread that handles the messages from +// the browser process and starts NaCl loader processes. +class NaClBrokerThread : public ChildThread { + public: + NaClBrokerThread(); + ~NaClBrokerThread(); + // Returns the one NaCl thread. + static NaClBrokerThread* current(); + + virtual void OnChannelConnected(int32 peer_pid); + + private: + virtual void OnControlMessageReceived(const IPC::Message& msg); + void OnLaunchLoaderThroughBroker(const std::wstring& loader_channel_id); + void OnShareBrowserHandle(int browser_handle); + + base::ProcessHandle browser_handle_; + sandbox::BrokerServices* broker_services_; + + DISALLOW_COPY_AND_ASSIGN(NaClBrokerThread); +}; + +#endif // CHROME_NACL_BROKER_THREAD_H_ diff --git a/chrome/nacl/nacl_main.cc b/chrome/nacl/nacl_main.cc index 72bc8a2..ffda8ab 100644 --- a/chrome/nacl/nacl_main.cc +++ b/chrome/nacl/nacl_main.cc @@ -20,8 +20,66 @@ #include "chrome/common/chrome_switches.h" #include "chrome/common/logging_chrome.h" #include "chrome/common/main_function_params.h" +#include "chrome/common/result_codes.h" +#if defined(OS_WIN) +#include "chrome/nacl/broker_thread.h" +#endif #include "chrome/nacl/nacl_thread.h" +#ifdef _WIN64 + +sandbox::BrokerServices* g_broker_services = NULL; + +// main() routine for the NaCl broker process. +// This is necessary for supporting NaCl in Chrome on Win64. +int NaClBrokerMain(const MainFunctionParams& parameters) { + // The main thread of the broker. + MessageLoopForIO main_message_loop; + std::wstring app_name = chrome::kNaClAppName; + PlatformThread::SetName(WideToASCII(app_name + L"_NaClBrokerMain").c_str()); + + SystemMonitor system_monitor; + HighResolutionTimerManager hi_res_timer_manager; + + const CommandLine& parsed_command_line = parameters.command_line_; + + DLOG(INFO) << "Started NaCL broker with " << + parsed_command_line.command_line_string(); + + // NOTE: this code is duplicated from browser_main.cc + // IMPORTANT: This piece of code needs to run as early as possible in the + // process because it will initialize the sandbox broker, which requires the + // process to swap its window station. During this time all the UI will be + // broken. This has to run before threads and windows are created. + sandbox::BrokerServices* broker_services = + parameters.sandbox_info_.BrokerServices(); + if (broker_services) { + g_broker_services = broker_services; + if (!parsed_command_line.HasSwitch(switches::kNoSandbox)) { + bool use_winsta = !parsed_command_line.HasSwitch( + switches::kDisableAltWinstation); + // Precreate the desktop and window station used by the renderers. + sandbox::TargetPolicy* policy = broker_services->CreatePolicy(); + sandbox::ResultCode result = policy->CreateAlternateDesktop(use_winsta); + CHECK(sandbox::SBOX_ERROR_FAILED_TO_SWITCH_BACK_WINSTATION != result); + policy->Release(); + } + } + + { + ChildProcess broker_process; + broker_process.set_main_thread(new NaClBrokerThread()); + MessageLoop::current()->Run(); + } + + return 0; +} +#else +int NaClBrokerMain(const MainFunctionParams& parameters) { + return ResultCodes::BAD_PROCESS_TYPE; +} +#endif // _WIN64 + // This function provides some ways to test crash and assertion handling // behavior of the renderer. static void HandleNaClTestParameters(const CommandLine& command_line) { @@ -48,7 +106,7 @@ static void LaunchNaClChildProcess() { } #endif -// main() routine for running as the sel_ldr process. +// main() routine for the NaCl loader process. int NaClMain(const MainFunctionParams& parameters) { const CommandLine& parsed_command_line = parameters.command_line_; @@ -60,7 +118,12 @@ int NaClMain(const MainFunctionParams& parameters) { // The main thread of the plugin services IO. MessageLoopForIO main_message_loop; + // NaCl code runs in a different binary on Win64. +#ifdef _WIN64 + std::wstring app_name = chrome::kNaClAppName; +#else std::wstring app_name = chrome::kBrowserAppName; +#endif PlatformThread::SetName(WideToASCII(app_name + L"_NaClMain").c_str()); SystemMonitor system_monitor; @@ -70,7 +133,7 @@ int NaClMain(const MainFunctionParams& parameters) { sandbox::TargetServices* target_services = parameters.sandbox_info_.TargetServices(); - DLOG(INFO) << "Started plugin with " << + DLOG(INFO) << "Started NaCl loader with " << parsed_command_line.command_line_string(); HMODULE sandbox_test_module = NULL; diff --git a/chrome/nacl/nacl_thread.cc b/chrome/nacl/nacl_thread.cc index 4c9dd5f05..0f05f06 100644 --- a/chrome/nacl/nacl_thread.cc +++ b/chrome/nacl/nacl_thread.cc @@ -36,5 +36,5 @@ void NaClThread::OnControlMessageReceived(const IPC::Message& msg) { void NaClThread::OnStartSelLdr(int channel_descriptor, nacl::FileDescriptor handle) { - SelMain(channel_descriptor, NATIVE_HANDLE(handle)); + SelMain(channel_descriptor, nacl::ToNativeHandle(handle)); } diff --git a/chrome/nacl/nacl_thread.h b/chrome/nacl/nacl_thread.h index fd8fe76..8893819 100644 --- a/chrome/nacl/nacl_thread.h +++ b/chrome/nacl/nacl_thread.h @@ -10,8 +10,6 @@ #include "chrome/common/child_thread.h" #include "chrome/common/nacl_types.h" -class NotificationService; - // The NaClThread class represents a background thread where NaCl app gets // started. class NaClThread : public ChildThread { diff --git a/chrome/renderer/render_process.cc b/chrome/renderer/render_process.cc index ac372ed..5a5bfe7 100644 --- a/chrome/renderer/render_process.cc +++ b/chrome/renderer/render_process.cc @@ -150,7 +150,7 @@ bool RenderProcess::LaunchNaClProcess(const char* url, reinterpret_cast<base::ProcessId*>(nacl_process_id)))) { return false; } - *imc_handle = NATIVE_HANDLE(imc_descriptor); + *imc_handle = nacl::ToNativeHandle(imc_descriptor); *nacl_process_handle = nacl_process; return true; } |