1558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch// Copyright 2013 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch#include "components/nacl/broker/nacl_broker_listener.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/base_switches.h" 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h" 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/command_line.h" 109ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch#include "base/message_loop/message_loop.h" 11b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)#include "base/message_loop/message_loop_proxy.h" 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/path_service.h" 13ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#include "components/nacl/common/nacl_cmd_line.h" 14a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch#include "components/nacl/common/nacl_debug_exception_handler_win.h" 15a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch#include "components/nacl/common/nacl_messages.h" 16eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "components/nacl/common/nacl_switches.h" 17eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "content/public/common/content_switches.h" 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/common/sandbox_init.h" 192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ipc/ipc_channel.h" 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ipc/ipc_switches.h" 212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "sandbox/win/src/sandbox_policy.h" 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace { 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SendReply(IPC::Channel* channel, int32 pid, bool result) { 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) channel->Send(new NaClProcessMsg_DebugExceptionHandlerLaunched(pid, result)); 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)NaClBrokerListener::NaClBrokerListener() 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : browser_handle_(base::kNullProcessHandle) { 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)NaClBrokerListener::~NaClBrokerListener() { 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::CloseProcessHandle(browser_handle_); 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void NaClBrokerListener::Listen() { 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string channel_name = 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CommandLine::ForCurrentProcess()->GetSwitchValueASCII( 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switches::kProcessChannelID); 43cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) channel_ = IPC::Channel::CreateClient(channel_name, this); 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK(channel_->Connect()); 45a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) base::MessageLoop::current()->Run(); 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// NOTE: changes to this method need to be reviewed by the security team. 492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void NaClBrokerListener::PreSpawnTarget(sandbox::TargetPolicy* policy, 502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bool* success) { 512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // This code is duplicated in chrome_content_browser_client.cc. 522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Allow the server side of a pipe restricted to the "chrome.nacl." 542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // namespace so that it cannot impersonate other system or other chrome 552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // service pipes. 562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) sandbox::ResultCode result = policy->AddRule( 572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) sandbox::TargetPolicy::SUBSYS_NAMED_PIPES, 582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) sandbox::TargetPolicy::NAMEDPIPES_ALLOW_ANY, 592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) L"\\\\.\\pipe\\chrome.nacl.*"); 602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *success = (result == sandbox::SBOX_ALL_OK); 612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void NaClBrokerListener::OnChannelConnected(int32 peer_pid) { 64c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) bool res = base::OpenPrivilegedProcessHandle(peer_pid, &browser_handle_); 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK(res); 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool NaClBrokerListener::OnMessageReceived(const IPC::Message& msg) { 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool handled = true; 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IPC_BEGIN_MESSAGE_MAP(NaClBrokerListener, msg) 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IPC_MESSAGE_HANDLER(NaClProcessMsg_LaunchLoaderThroughBroker, 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) OnLaunchLoaderThroughBroker) 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IPC_MESSAGE_HANDLER(NaClProcessMsg_LaunchDebugExceptionHandler, 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) OnLaunchDebugExceptionHandler) 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IPC_MESSAGE_HANDLER(NaClProcessMsg_StopBroker, OnStopBroker) 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IPC_MESSAGE_UNHANDLED(handled = false) 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IPC_END_MESSAGE_MAP() 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return handled; 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void NaClBrokerListener::OnChannelError() { 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The browser died unexpectedly, quit to avoid a zombie process. 83a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) base::MessageLoop::current()->Quit(); 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void NaClBrokerListener::OnLaunchLoaderThroughBroker( 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& loader_channel_id) { 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::ProcessHandle loader_process = 0; 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::ProcessHandle loader_handle_in_browser = 0; 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Create the path to the nacl broker/loader executable - it's the executable 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // this code is running in. 932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::FilePath exe_path; 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PathService::Get(base::FILE_EXE, &exe_path); 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!exe_path.empty()) { 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CommandLine* cmd_line = new CommandLine(exe_path); 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) nacl::CopyNaClCommandLineArguments(cmd_line); 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cmd_line->AppendSwitchASCII(switches::kProcessType, 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switches::kNaClLoaderProcess); 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cmd_line->AppendSwitchASCII(switches::kProcessChannelID, 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) loader_channel_id); 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) loader_process = content::StartSandboxedProcess(this, cmd_line); 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (loader_process) { 107424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) // Note: PROCESS_DUP_HANDLE is necessary here, because: 108424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) // 1) The current process is the broker, which is the loader's parent. 109424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) // 2) The browser is not the loader's parent, and so only gets the 110424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) // access rights we confer here. 111424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) // 3) The browser calls DuplicateHandle to set up communications with 112424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) // the loader. 113424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) // 4) The target process handle to DuplicateHandle needs to have 114424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) // PROCESS_DUP_HANDLE access rights. 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DuplicateHandle(::GetCurrentProcess(), loader_process, 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) browser_handle_, &loader_handle_in_browser, 117424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) PROCESS_DUP_HANDLE | PROCESS_QUERY_INFORMATION | PROCESS_TERMINATE, 118424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) FALSE, 0); 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::CloseProcessHandle(loader_process); 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) channel_->Send(new NaClProcessMsg_LoaderLaunched(loader_channel_id, 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) loader_handle_in_browser)); 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void NaClBrokerListener::OnLaunchDebugExceptionHandler( 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int32 pid, base::ProcessHandle process_handle, 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& startup_info) { 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NaClStartDebugExceptionHandlerThread( 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) process_handle, startup_info, 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::MessageLoopProxy::current(), 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Bind(SendReply, channel_.get(), pid)); 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void NaClBrokerListener::OnStopBroker() { 136a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) base::MessageLoop::current()->Quit(); 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 138