1 // Copyright 2013 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "components/nacl/broker/nacl_broker_listener.h" 6 7 #include "base/base_switches.h" 8 #include "base/bind.h" 9 #include "base/command_line.h" 10 #include "base/message_loop/message_loop.h" 11 #include "base/message_loop/message_loop_proxy.h" 12 #include "base/path_service.h" 13 #include "components/nacl/common/nacl_cmd_line.h" 14 #include "components/nacl/common/nacl_debug_exception_handler_win.h" 15 #include "components/nacl/common/nacl_messages.h" 16 #include "components/nacl/common/nacl_switches.h" 17 #include "content/public/common/content_switches.h" 18 #include "content/public/common/sandbox_init.h" 19 #include "ipc/ipc_channel.h" 20 #include "ipc/ipc_switches.h" 21 #include "sandbox/win/src/sandbox_policy.h" 22 23 namespace { 24 25 void SendReply(IPC::Channel* channel, int32 pid, bool result) { 26 channel->Send(new NaClProcessMsg_DebugExceptionHandlerLaunched(pid, result)); 27 } 28 29 } // namespace 30 31 NaClBrokerListener::NaClBrokerListener() 32 : browser_handle_(base::kNullProcessHandle) { 33 } 34 35 NaClBrokerListener::~NaClBrokerListener() { 36 base::CloseProcessHandle(browser_handle_); 37 } 38 39 void NaClBrokerListener::Listen() { 40 std::string channel_name = 41 CommandLine::ForCurrentProcess()->GetSwitchValueASCII( 42 switches::kProcessChannelID); 43 channel_ = IPC::Channel::CreateClient(channel_name, this); 44 CHECK(channel_->Connect()); 45 base::MessageLoop::current()->Run(); 46 } 47 48 // NOTE: changes to this method need to be reviewed by the security team. 49 void NaClBrokerListener::PreSpawnTarget(sandbox::TargetPolicy* policy, 50 bool* success) { 51 // This code is duplicated in chrome_content_browser_client.cc. 52 53 // Allow the server side of a pipe restricted to the "chrome.nacl." 54 // namespace so that it cannot impersonate other system or other chrome 55 // service pipes. 56 sandbox::ResultCode result = policy->AddRule( 57 sandbox::TargetPolicy::SUBSYS_NAMED_PIPES, 58 sandbox::TargetPolicy::NAMEDPIPES_ALLOW_ANY, 59 L"\\\\.\\pipe\\chrome.nacl.*"); 60 *success = (result == sandbox::SBOX_ALL_OK); 61 } 62 63 void NaClBrokerListener::OnChannelConnected(int32 peer_pid) { 64 bool res = base::OpenPrivilegedProcessHandle(peer_pid, &browser_handle_); 65 CHECK(res); 66 } 67 68 bool NaClBrokerListener::OnMessageReceived(const IPC::Message& msg) { 69 bool handled = true; 70 IPC_BEGIN_MESSAGE_MAP(NaClBrokerListener, msg) 71 IPC_MESSAGE_HANDLER(NaClProcessMsg_LaunchLoaderThroughBroker, 72 OnLaunchLoaderThroughBroker) 73 IPC_MESSAGE_HANDLER(NaClProcessMsg_LaunchDebugExceptionHandler, 74 OnLaunchDebugExceptionHandler) 75 IPC_MESSAGE_HANDLER(NaClProcessMsg_StopBroker, OnStopBroker) 76 IPC_MESSAGE_UNHANDLED(handled = false) 77 IPC_END_MESSAGE_MAP() 78 return handled; 79 } 80 81 void NaClBrokerListener::OnChannelError() { 82 // The browser died unexpectedly, quit to avoid a zombie process. 83 base::MessageLoop::current()->Quit(); 84 } 85 86 void NaClBrokerListener::OnLaunchLoaderThroughBroker( 87 const std::string& loader_channel_id) { 88 base::ProcessHandle loader_process = 0; 89 base::ProcessHandle loader_handle_in_browser = 0; 90 91 // Create the path to the nacl broker/loader executable - it's the executable 92 // this code is running in. 93 base::FilePath exe_path; 94 PathService::Get(base::FILE_EXE, &exe_path); 95 if (!exe_path.empty()) { 96 CommandLine* cmd_line = new CommandLine(exe_path); 97 nacl::CopyNaClCommandLineArguments(cmd_line); 98 99 cmd_line->AppendSwitchASCII(switches::kProcessType, 100 switches::kNaClLoaderProcess); 101 102 cmd_line->AppendSwitchASCII(switches::kProcessChannelID, 103 loader_channel_id); 104 105 loader_process = content::StartSandboxedProcess(this, cmd_line); 106 if (loader_process) { 107 // Note: PROCESS_DUP_HANDLE is necessary here, because: 108 // 1) The current process is the broker, which is the loader's parent. 109 // 2) The browser is not the loader's parent, and so only gets the 110 // access rights we confer here. 111 // 3) The browser calls DuplicateHandle to set up communications with 112 // the loader. 113 // 4) The target process handle to DuplicateHandle needs to have 114 // PROCESS_DUP_HANDLE access rights. 115 DuplicateHandle(::GetCurrentProcess(), loader_process, 116 browser_handle_, &loader_handle_in_browser, 117 PROCESS_DUP_HANDLE | PROCESS_QUERY_INFORMATION | PROCESS_TERMINATE, 118 FALSE, 0); 119 base::CloseProcessHandle(loader_process); 120 } 121 } 122 channel_->Send(new NaClProcessMsg_LoaderLaunched(loader_channel_id, 123 loader_handle_in_browser)); 124 } 125 126 void NaClBrokerListener::OnLaunchDebugExceptionHandler( 127 int32 pid, base::ProcessHandle process_handle, 128 const std::string& startup_info) { 129 NaClStartDebugExceptionHandlerThread( 130 process_handle, startup_info, 131 base::MessageLoopProxy::current(), 132 base::Bind(SendReply, channel_.get(), pid)); 133 } 134 135 void NaClBrokerListener::OnStopBroker() { 136 base::MessageLoop::current()->Quit(); 137 } 138