Home | History | Annotate | Download | only in broker
      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