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_.reset(new IPC::Channel( 44 channel_name, IPC::Channel::MODE_CLIENT, this)); 45 CHECK(channel_->Connect()); 46 base::MessageLoop::current()->Run(); 47 } 48 49 // NOTE: changes to this method need to be reviewed by the security team. 50 void NaClBrokerListener::PreSpawnTarget(sandbox::TargetPolicy* policy, 51 bool* success) { 52 // This code is duplicated in chrome_content_browser_client.cc. 53 54 // Allow the server side of a pipe restricted to the "chrome.nacl." 55 // namespace so that it cannot impersonate other system or other chrome 56 // service pipes. 57 sandbox::ResultCode result = policy->AddRule( 58 sandbox::TargetPolicy::SUBSYS_NAMED_PIPES, 59 sandbox::TargetPolicy::NAMEDPIPES_ALLOW_ANY, 60 L"\\\\.\\pipe\\chrome.nacl.*"); 61 *success = (result == sandbox::SBOX_ALL_OK); 62 } 63 64 void NaClBrokerListener::OnChannelConnected(int32 peer_pid) { 65 bool res = base::OpenPrivilegedProcessHandle(peer_pid, &browser_handle_); 66 CHECK(res); 67 } 68 69 bool NaClBrokerListener::OnMessageReceived(const IPC::Message& msg) { 70 bool handled = true; 71 IPC_BEGIN_MESSAGE_MAP(NaClBrokerListener, msg) 72 IPC_MESSAGE_HANDLER(NaClProcessMsg_LaunchLoaderThroughBroker, 73 OnLaunchLoaderThroughBroker) 74 IPC_MESSAGE_HANDLER(NaClProcessMsg_LaunchDebugExceptionHandler, 75 OnLaunchDebugExceptionHandler) 76 IPC_MESSAGE_HANDLER(NaClProcessMsg_StopBroker, OnStopBroker) 77 IPC_MESSAGE_UNHANDLED(handled = false) 78 IPC_END_MESSAGE_MAP() 79 return handled; 80 } 81 82 void NaClBrokerListener::OnChannelError() { 83 // The browser died unexpectedly, quit to avoid a zombie process. 84 base::MessageLoop::current()->Quit(); 85 } 86 87 void NaClBrokerListener::OnLaunchLoaderThroughBroker( 88 const std::string& loader_channel_id) { 89 base::ProcessHandle loader_process = 0; 90 base::ProcessHandle loader_handle_in_browser = 0; 91 92 // Create the path to the nacl broker/loader executable - it's the executable 93 // this code is running in. 94 base::FilePath exe_path; 95 PathService::Get(base::FILE_EXE, &exe_path); 96 if (!exe_path.empty()) { 97 CommandLine* cmd_line = new CommandLine(exe_path); 98 nacl::CopyNaClCommandLineArguments(cmd_line); 99 100 cmd_line->AppendSwitchASCII(switches::kProcessType, 101 switches::kNaClLoaderProcess); 102 103 cmd_line->AppendSwitchASCII(switches::kProcessChannelID, 104 loader_channel_id); 105 106 loader_process = content::StartSandboxedProcess(this, cmd_line); 107 if (loader_process) { 108 DuplicateHandle(::GetCurrentProcess(), loader_process, 109 browser_handle_, &loader_handle_in_browser, 110 PROCESS_DUP_HANDLE | PROCESS_QUERY_INFORMATION , FALSE, 0); 111 base::CloseProcessHandle(loader_process); 112 } 113 } 114 channel_->Send(new NaClProcessMsg_LoaderLaunched(loader_channel_id, 115 loader_handle_in_browser)); 116 } 117 118 void NaClBrokerListener::OnLaunchDebugExceptionHandler( 119 int32 pid, base::ProcessHandle process_handle, 120 const std::string& startup_info) { 121 NaClStartDebugExceptionHandlerThread( 122 process_handle, startup_info, 123 base::MessageLoopProxy::current(), 124 base::Bind(SendReply, channel_.get(), pid)); 125 } 126 127 void NaClBrokerListener::OnStopBroker() { 128 base::MessageLoop::current()->Quit(); 129 } 130