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