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