Home | History | Annotate | Download | only in browser
      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/browser/nacl_host_message_filter.h"
      6 
      7 #include "base/sys_info.h"
      8 #include "components/nacl/browser/nacl_browser.h"
      9 #include "components/nacl/browser/nacl_file_host.h"
     10 #include "components/nacl/browser/nacl_process_host.h"
     11 #include "components/nacl/browser/pnacl_host.h"
     12 #include "components/nacl/common/nacl_host_messages.h"
     13 #include "content/public/browser/browser_thread.h"
     14 #include "content/public/browser/plugin_service.h"
     15 #include "content/public/browser/render_process_host.h"
     16 #include "content/public/browser/web_contents.h"
     17 #include "ipc/ipc_platform_file.h"
     18 #include "net/url_request/url_request_context.h"
     19 #include "net/url_request/url_request_context_getter.h"
     20 #include "ppapi/shared_impl/ppapi_permissions.h"
     21 #include "url/gurl.h"
     22 
     23 namespace nacl {
     24 
     25 namespace {
     26 
     27 ppapi::PpapiPermissions GetNaClPermissions(
     28     uint32 permission_bits,
     29     content::BrowserContext* browser_context,
     30     const GURL& document_url) {
     31   // Only allow NaCl plugins to request certain permissions. We don't want
     32   // a compromised renderer to be able to start a nacl plugin with e.g. Flash
     33   // permissions which may expand the surface area of the sandbox.
     34   uint32 masked_bits = permission_bits & ppapi::PERMISSION_DEV;
     35   if (content::PluginService::GetInstance()->PpapiDevChannelSupported(
     36           browser_context, document_url))
     37     masked_bits |= ppapi::PERMISSION_DEV_CHANNEL;
     38   return ppapi::PpapiPermissions::GetForCommandLine(masked_bits);
     39 }
     40 
     41 
     42 ppapi::PpapiPermissions GetPpapiPermissions(uint32 permission_bits,
     43                                             int render_process_id,
     44                                             int render_view_id) {
     45   // We get the URL from WebContents from the RenderViewHost, since we don't
     46   // have a BrowserPpapiHost yet.
     47   content::RenderProcessHost* host =
     48       content::RenderProcessHost::FromID(render_process_id);
     49   content::RenderViewHost* view_host =
     50       content::RenderViewHost::FromID(render_process_id, render_view_id);
     51   GURL document_url;
     52   content::WebContents* contents =
     53       content::WebContents::FromRenderViewHost(view_host);
     54   if (contents)
     55     document_url = contents->GetLastCommittedURL();
     56   return GetNaClPermissions(permission_bits,
     57                             host->GetBrowserContext(),
     58                             document_url);
     59 }
     60 
     61 }  // namespace
     62 
     63 NaClHostMessageFilter::NaClHostMessageFilter(
     64     int render_process_id,
     65     bool is_off_the_record,
     66     const base::FilePath& profile_directory,
     67     net::URLRequestContextGetter* request_context)
     68     : BrowserMessageFilter(NaClHostMsgStart),
     69       render_process_id_(render_process_id),
     70       off_the_record_(is_off_the_record),
     71       profile_directory_(profile_directory),
     72       request_context_(request_context),
     73       weak_ptr_factory_(this) {
     74 }
     75 
     76 NaClHostMessageFilter::~NaClHostMessageFilter() {
     77 }
     78 
     79 void NaClHostMessageFilter::OnChannelClosing() {
     80   pnacl::PnaclHost::GetInstance()->RendererClosing(render_process_id_);
     81 }
     82 
     83 bool NaClHostMessageFilter::OnMessageReceived(const IPC::Message& message) {
     84   bool handled = true;
     85   IPC_BEGIN_MESSAGE_MAP(NaClHostMessageFilter, message)
     86 #if !defined(DISABLE_NACL)
     87     IPC_MESSAGE_HANDLER_DELAY_REPLY(NaClHostMsg_LaunchNaCl, OnLaunchNaCl)
     88     IPC_MESSAGE_HANDLER_DELAY_REPLY(NaClHostMsg_GetReadonlyPnaclFD,
     89                                     OnGetReadonlyPnaclFd)
     90     IPC_MESSAGE_HANDLER_DELAY_REPLY(NaClHostMsg_NaClCreateTemporaryFile,
     91                                     OnNaClCreateTemporaryFile)
     92     IPC_MESSAGE_HANDLER(NaClHostMsg_NexeTempFileRequest,
     93                         OnGetNexeFd)
     94     IPC_MESSAGE_HANDLER(NaClHostMsg_ReportTranslationFinished,
     95                         OnTranslationFinished)
     96     IPC_MESSAGE_HANDLER(NaClHostMsg_MissingArchError,
     97                         OnMissingArchError)
     98     IPC_MESSAGE_HANDLER_DELAY_REPLY(NaClHostMsg_OpenNaClExecutable,
     99                                     OnOpenNaClExecutable)
    100     IPC_MESSAGE_HANDLER(NaClHostMsg_NaClGetNumProcessors,
    101                         OnNaClGetNumProcessors)
    102     IPC_MESSAGE_HANDLER(NaClHostMsg_NaClDebugEnabledForURL,
    103                         OnNaClDebugEnabledForURL)
    104 #endif
    105     IPC_MESSAGE_UNHANDLED(handled = false)
    106   IPC_END_MESSAGE_MAP()
    107 
    108   return handled;
    109 }
    110 
    111 net::HostResolver* NaClHostMessageFilter::GetHostResolver() {
    112   return request_context_->GetURLRequestContext()->host_resolver();
    113 }
    114 
    115 void NaClHostMessageFilter::OnLaunchNaCl(
    116     const nacl::NaClLaunchParams& launch_params,
    117     IPC::Message* reply_msg) {
    118   // PNaCl hack
    119   if (!launch_params.enable_dyncode_syscalls) {
    120     uint32 perms = launch_params.permission_bits & ppapi::PERMISSION_DEV;
    121     LaunchNaClContinuation(
    122         launch_params,
    123         reply_msg,
    124         ppapi::PpapiPermissions(perms));
    125     return;
    126   }
    127   content::BrowserThread::PostTaskAndReplyWithResult(
    128       content::BrowserThread::UI,
    129       FROM_HERE,
    130       base::Bind(&GetPpapiPermissions,
    131                  launch_params.permission_bits,
    132                  render_process_id_,
    133                  launch_params.render_view_id),
    134       base::Bind(&NaClHostMessageFilter::LaunchNaClContinuation,
    135                  this,
    136                  launch_params,
    137                  reply_msg));
    138 }
    139 
    140 void NaClHostMessageFilter::LaunchNaClContinuation(
    141     const nacl::NaClLaunchParams& launch_params,
    142     IPC::Message* reply_msg,
    143     ppapi::PpapiPermissions permissions) {
    144   NaClProcessHost* host = new NaClProcessHost(
    145       GURL(launch_params.manifest_url),
    146       permissions,
    147       launch_params.render_view_id,
    148       launch_params.permission_bits,
    149       launch_params.uses_irt,
    150       launch_params.uses_nonsfi_mode,
    151       launch_params.enable_dyncode_syscalls,
    152       launch_params.enable_exception_handling,
    153       launch_params.enable_crash_throttling,
    154       off_the_record_,
    155       profile_directory_);
    156   GURL manifest_url(launch_params.manifest_url);
    157   base::FilePath manifest_path;
    158   // We're calling MapUrlToLocalFilePath with the non-blocking API
    159   // because we're running in the I/O thread. Ideally we'd use the other path,
    160   // which would cover more cases.
    161   nacl::NaClBrowser::GetDelegate()->MapUrlToLocalFilePath(
    162       manifest_url,
    163       false /* use_blocking_api */,
    164       profile_directory_,
    165       &manifest_path);
    166   host->Launch(this, reply_msg, manifest_path);
    167 }
    168 
    169 void NaClHostMessageFilter::OnGetReadonlyPnaclFd(
    170     const std::string& filename, IPC::Message* reply_msg) {
    171   // This posts a task to another thread, but the renderer will
    172   // block until the reply is sent.
    173   nacl_file_host::GetReadonlyPnaclFd(this, filename, reply_msg);
    174 
    175   // This is the first message we receive from the renderer once it knows we
    176   // want to use PNaCl, so start the translation cache initialization here.
    177   pnacl::PnaclHost::GetInstance()->Init();
    178 }
    179 
    180 // Return the temporary file via a reply to the
    181 // NaClHostMsg_NaClCreateTemporaryFile sync message.
    182 void NaClHostMessageFilter::SyncReturnTemporaryFile(
    183     IPC::Message* reply_msg,
    184     base::File file) {
    185   if (file.IsValid()) {
    186     NaClHostMsg_NaClCreateTemporaryFile::WriteReplyParams(
    187         reply_msg,
    188         IPC::TakeFileHandleForProcess(file.Pass(), PeerHandle()));
    189   } else {
    190     reply_msg->set_reply_error();
    191   }
    192   Send(reply_msg);
    193 }
    194 
    195 void NaClHostMessageFilter::OnNaClCreateTemporaryFile(
    196     IPC::Message* reply_msg) {
    197   pnacl::PnaclHost::GetInstance()->CreateTemporaryFile(
    198       base::Bind(&NaClHostMessageFilter::SyncReturnTemporaryFile,
    199                  this,
    200                  reply_msg));
    201 }
    202 
    203 void NaClHostMessageFilter::AsyncReturnTemporaryFile(
    204     int pp_instance,
    205     const base::File& file,
    206     bool is_hit) {
    207   IPC::PlatformFileForTransit fd = IPC::InvalidPlatformFileForTransit();
    208   if (file.IsValid()) {
    209     // Don't close our copy of the handle, because PnaclHost will use it
    210     // when the translation finishes.
    211     fd = IPC::GetFileHandleForProcess(file.GetPlatformFile(), PeerHandle(),
    212                                       false);
    213   }
    214   Send(new NaClViewMsg_NexeTempFileReply(pp_instance, is_hit, fd));
    215 }
    216 
    217 void NaClHostMessageFilter::OnNaClGetNumProcessors(int* num_processors) {
    218   *num_processors = base::SysInfo::NumberOfProcessors();
    219 }
    220 
    221 void NaClHostMessageFilter::OnGetNexeFd(
    222     int render_view_id,
    223     int pp_instance,
    224     const nacl::PnaclCacheInfo& cache_info) {
    225   if (!cache_info.pexe_url.is_valid()) {
    226     LOG(ERROR) << "Bad URL received from GetNexeFd: " <<
    227         cache_info.pexe_url.possibly_invalid_spec();
    228     BadMessageReceived();
    229     return;
    230   }
    231 
    232   pnacl::PnaclHost::GetInstance()->GetNexeFd(
    233       render_process_id_,
    234       render_view_id,
    235       pp_instance,
    236       off_the_record_,
    237       cache_info,
    238       base::Bind(&NaClHostMessageFilter::AsyncReturnTemporaryFile,
    239                  this,
    240                  pp_instance));
    241 }
    242 
    243 void NaClHostMessageFilter::OnTranslationFinished(int instance, bool success) {
    244   pnacl::PnaclHost::GetInstance()->TranslationFinished(
    245       render_process_id_, instance, success);
    246 }
    247 
    248 void NaClHostMessageFilter::OnMissingArchError(int render_view_id) {
    249   nacl::NaClBrowser::GetDelegate()->
    250       ShowMissingArchInfobar(render_process_id_, render_view_id);
    251 }
    252 
    253 void NaClHostMessageFilter::OnOpenNaClExecutable(int render_view_id,
    254                                                  const GURL& file_url,
    255                                                  IPC::Message* reply_msg) {
    256   nacl_file_host::OpenNaClExecutable(this, render_view_id, file_url,
    257                                      reply_msg);
    258 }
    259 
    260 void NaClHostMessageFilter::OnNaClDebugEnabledForURL(const GURL& nmf_url,
    261                                                      bool* should_debug) {
    262   *should_debug =
    263       nacl::NaClBrowser::GetDelegate()->URLMatchesDebugPatterns(nmf_url);
    264 }
    265 
    266 }  // namespace nacl
    267