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
23namespace nacl {
24
25namespace {
26
27ppapi::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
42ppapi::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
63NaClHostMessageFilter::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
76NaClHostMessageFilter::~NaClHostMessageFilter() {
77}
78
79void NaClHostMessageFilter::OnChannelClosing() {
80  pnacl::PnaclHost::GetInstance()->RendererClosing(render_process_id_);
81}
82
83bool 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
111net::HostResolver* NaClHostMessageFilter::GetHostResolver() {
112  return request_context_->GetURLRequestContext()->host_resolver();
113}
114
115void 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
140void 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
169void 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.
182void 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
195void NaClHostMessageFilter::OnNaClCreateTemporaryFile(
196    IPC::Message* reply_msg) {
197  pnacl::PnaclHost::GetInstance()->CreateTemporaryFile(
198      base::Bind(&NaClHostMessageFilter::SyncReturnTemporaryFile,
199                 this,
200                 reply_msg));
201}
202
203void 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
217void NaClHostMessageFilter::OnNaClGetNumProcessors(int* num_processors) {
218  *num_processors = base::SysInfo::NumberOfProcessors();
219}
220
221void 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
243void NaClHostMessageFilter::OnTranslationFinished(int instance, bool success) {
244  pnacl::PnaclHost::GetInstance()->TranslationFinished(
245      render_process_id_, instance, success);
246}
247
248void NaClHostMessageFilter::OnMissingArchError(int render_view_id) {
249  nacl::NaClBrowser::GetDelegate()->
250      ShowMissingArchInfobar(render_process_id_, render_view_id);
251}
252
253void 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
260void 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