blob: ce95b628647439531600a98a35969db8426fa5f4 [file] [log] [blame]
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001// Copyright (c) 2012 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 "chrome/renderer/pepper/ppb_nacl_private_impl.h"
6
7#ifndef DISABLE_NACL
8
9#include "base/command_line.h"
10#include "base/lazy_instance.h"
11#include "base/logging.h"
12#include "base/rand_util.h"
13#include "chrome/common/chrome_switches.h"
Torne (Richard Coles)58218062012-11-14 11:43:16 +000014#include "chrome/renderer/chrome_render_process_observer.h"
Ben Murdoch7dbb3d52013-07-17 14:55:54 +010015#include "chrome/renderer/pepper/pnacl_translation_resource_host.h"
Ben Murdocha3f7b4e2013-07-24 10:36:34 +010016#include "components/nacl/common/nacl_host_messages.h"
17#include "components/nacl/common/nacl_types.h"
Torne (Richard Coles)58218062012-11-14 11:43:16 +000018#include "content/public/common/content_client.h"
19#include "content/public/common/content_switches.h"
20#include "content/public/common/sandbox_init.h"
Ben Murdoch58e6fbe2013-07-26 10:20:38 +010021#include "content/public/renderer/pepper_plugin_instance.h"
Torne (Richard Coles)58218062012-11-14 11:43:16 +000022#include "content/public/renderer/renderer_ppapi_host.h"
23#include "content/public/renderer/render_thread.h"
24#include "content/public/renderer/render_view.h"
Torne (Richard Coles)58218062012-11-14 11:43:16 +000025#include "ppapi/c/pp_bool.h"
26#include "ppapi/c/private/pp_file_handle.h"
Torne (Richard Coles)58218062012-11-14 11:43:16 +000027#include "ppapi/native_client/src/trusted/plugin/nacl_entry_points.h"
Ben Murdocha3f7b4e2013-07-24 10:36:34 +010028#include "ppapi/shared_impl/ppapi_permissions.h"
Torne (Richard Coles)58218062012-11-14 11:43:16 +000029#include "ppapi/shared_impl/ppapi_preferences.h"
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010030#include "ppapi/shared_impl/var.h"
Ben Murdocheb525c52013-07-10 11:40:50 +010031#include "ppapi/thunk/enter.h"
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +010032#include "third_party/WebKit/public/web/WebDocument.h"
33#include "third_party/WebKit/public/web/WebElement.h"
34#include "third_party/WebKit/public/web/WebFrame.h"
35#include "third_party/WebKit/public/web/WebPluginContainer.h"
36#include "third_party/WebKit/public/web/WebView.h"
Torne (Richard Coles)58218062012-11-14 11:43:16 +000037
38namespace {
39
Ben Murdoch7dbb3d52013-07-17 14:55:54 +010040base::LazyInstance<scoped_refptr<PnaclTranslationResourceHost> >
41 g_pnacl_resource_host = LAZY_INSTANCE_INITIALIZER;
42
43static bool InitializePnaclResourceHost() {
Ben Murdoch2385ea32013-08-06 11:01:04 +010044 // Must run on the main thread.
45 content::RenderThread* render_thread = content::RenderThread::Get();
46 if (!render_thread)
47 return false;
Ben Murdoch7dbb3d52013-07-17 14:55:54 +010048 if (!g_pnacl_resource_host.Get()) {
Ben Murdoch7dbb3d52013-07-17 14:55:54 +010049 g_pnacl_resource_host.Get() = new PnaclTranslationResourceHost(
50 render_thread->GetIOMessageLoopProxy());
51 render_thread->AddFilter(g_pnacl_resource_host.Get());
52 }
53 return true;
54}
Torne (Richard Coles)58218062012-11-14 11:43:16 +000055
56struct InstanceInfo {
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000057 InstanceInfo() : plugin_pid(base::kNullProcessId), plugin_child_id(0) {}
Torne (Richard Coles)58218062012-11-14 11:43:16 +000058 GURL url;
59 ppapi::PpapiPermissions permissions;
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000060 base::ProcessId plugin_pid;
Torne (Richard Coles)58218062012-11-14 11:43:16 +000061 int plugin_child_id;
62 IPC::ChannelHandle channel_handle;
63};
64
65typedef std::map<PP_Instance, InstanceInfo> InstanceInfoMap;
66
67base::LazyInstance<InstanceInfoMap> g_instance_info =
68 LAZY_INSTANCE_INITIALIZER;
69
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000070static int GetRoutingID(PP_Instance instance) {
71 // Check that we are on the main renderer thread.
72 DCHECK(content::RenderThread::Get());
73 content::RendererPpapiHost *host =
74 content::RendererPpapiHost::GetForPPInstance(instance);
75 if (!host)
76 return 0;
77 return host->GetRoutingIDForWidget(instance);
78}
79
Torne (Richard Coles)58218062012-11-14 11:43:16 +000080// Launch NaCl's sel_ldr process.
Ben Murdocha3f7b4e2013-07-24 10:36:34 +010081PP_ExternalPluginResult LaunchSelLdr(PP_Instance instance,
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000082 const char* alleged_url,
83 PP_Bool uses_irt,
84 PP_Bool uses_ppapi,
85 PP_Bool enable_ppapi_dev,
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010086 PP_Bool enable_dyncode_syscalls,
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +010087 PP_Bool enable_exception_handling,
Ben Murdochca12bfa2013-07-23 11:17:05 +010088 void* imc_handle,
89 struct PP_Var* error_message) {
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000090 nacl::FileDescriptor result_socket;
Torne (Richard Coles)58218062012-11-14 11:43:16 +000091 IPC::Sender* sender = content::RenderThread::Get();
Ben Murdoch7dbb3d52013-07-17 14:55:54 +010092 DCHECK(sender);
Ben Murdochca12bfa2013-07-23 11:17:05 +010093 *error_message = PP_MakeUndefined();
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000094 int routing_id = 0;
95 // If the nexe uses ppapi APIs, we need a routing ID.
96 // To get the routing ID, we must be on the main thread.
97 // Some nexes do not use ppapi and launch from the background thread,
98 // so those nexes can skip finding a routing_id.
99 if (uses_ppapi) {
100 routing_id = GetRoutingID(instance);
101 if (!routing_id)
Ben Murdocha3f7b4e2013-07-24 10:36:34 +0100102 return PP_EXTERNAL_PLUGIN_FAILED;
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000103 }
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000104
105 InstanceInfo instance_info;
106 instance_info.url = GURL(alleged_url);
107
108 uint32_t perm_bits = ppapi::PERMISSION_NONE;
109 // Conditionally block 'Dev' interfaces. We do this for the NaCl process, so
110 // it's clearer to developers when they are using 'Dev' inappropriately. We
111 // must also check on the trusted side of the proxy.
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000112 if (enable_ppapi_dev)
113 perm_bits |= ppapi::PERMISSION_DEV;
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000114 instance_info.permissions =
115 ppapi::PpapiPermissions::GetForCommandLine(perm_bits);
Ben Murdochca12bfa2013-07-23 11:17:05 +0100116 std::string error_message_string;
117 nacl::NaClLaunchResult launch_result;
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000118
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100119 if (!sender->Send(new NaClHostMsg_LaunchNaCl(
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000120 nacl::NaClLaunchParams(instance_info.url.spec(),
121 routing_id,
122 perm_bits,
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100123 PP_ToBool(uses_irt),
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100124 PP_ToBool(enable_dyncode_syscalls),
125 PP_ToBool(enable_exception_handling)),
Ben Murdochca12bfa2013-07-23 11:17:05 +0100126 &launch_result,
127 &error_message_string))) {
Ben Murdocha3f7b4e2013-07-24 10:36:34 +0100128 return PP_EXTERNAL_PLUGIN_FAILED;
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000129 }
Ben Murdochca12bfa2013-07-23 11:17:05 +0100130 if (!error_message_string.empty()) {
131 *error_message = ppapi::StringVar::StringToPPVar(error_message_string);
Ben Murdocha3f7b4e2013-07-24 10:36:34 +0100132 return PP_EXTERNAL_PLUGIN_FAILED;
Ben Murdochca12bfa2013-07-23 11:17:05 +0100133 }
134 result_socket = launch_result.imc_channel_handle;
135 instance_info.channel_handle = launch_result.ipc_channel_handle;
136 instance_info.plugin_pid = launch_result.plugin_pid;
137 instance_info.plugin_child_id = launch_result.plugin_child_id;
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000138 // Don't save instance_info if channel handle is invalid.
139 bool invalid_handle = instance_info.channel_handle.name.empty();
140#if defined(OS_POSIX)
141 if (!invalid_handle)
142 invalid_handle = (instance_info.channel_handle.socket.fd == -1);
143#endif
144 if (!invalid_handle)
145 g_instance_info.Get()[instance] = instance_info;
146
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000147 *(static_cast<NaClHandle*>(imc_handle)) =
148 nacl::ToNativeHandle(result_socket);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000149
Ben Murdocha3f7b4e2013-07-24 10:36:34 +0100150 return PP_EXTERNAL_PLUGIN_OK;
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000151}
152
Ben Murdocha3f7b4e2013-07-24 10:36:34 +0100153PP_ExternalPluginResult StartPpapiProxy(PP_Instance instance) {
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000154 InstanceInfoMap& map = g_instance_info.Get();
155 InstanceInfoMap::iterator it = map.find(instance);
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000156 if (it == map.end()) {
157 DLOG(ERROR) << "Could not find instance ID";
Ben Murdocha3f7b4e2013-07-24 10:36:34 +0100158 return PP_EXTERNAL_PLUGIN_FAILED;
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000159 }
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000160 InstanceInfo instance_info = it->second;
161 map.erase(it);
162
Ben Murdoch58e6fbe2013-07-26 10:20:38 +0100163 content::PepperPluginInstance* plugin_instance =
164 content::PepperPluginInstance::Get(instance);
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000165 if (!plugin_instance) {
166 DLOG(ERROR) << "GetInstance() failed";
Ben Murdocha3f7b4e2013-07-24 10:36:34 +0100167 return PP_EXTERNAL_PLUGIN_ERROR_MODULE;
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000168 }
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000169
Ben Murdocha3f7b4e2013-07-24 10:36:34 +0100170 return plugin_instance->SwitchToOutOfProcessProxy(
171 base::FilePath().AppendASCII(instance_info.url.spec()),
172 instance_info.permissions,
173 instance_info.channel_handle,
174 instance_info.plugin_pid,
175 instance_info.plugin_child_id);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000176}
177
178int UrandomFD(void) {
179#if defined(OS_POSIX)
180 return base::GetUrandomFD();
181#else
182 return -1;
183#endif
184}
185
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000186PP_Bool Are3DInterfacesDisabled() {
187 return PP_FromBool(CommandLine::ForCurrentProcess()->HasSwitch(
188 switches::kDisable3DAPIs));
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000189}
190
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000191int32_t BrokerDuplicateHandle(PP_FileHandle source_handle,
192 uint32_t process_id,
193 PP_FileHandle* target_handle,
194 uint32_t desired_access,
195 uint32_t options) {
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000196#if defined(OS_WIN)
197 return content::BrokerDuplicateHandle(source_handle, process_id,
198 target_handle, desired_access,
199 options);
200#else
201 return 0;
202#endif
203}
204
Ben Murdoch2385ea32013-08-06 11:01:04 +0100205int32_t EnsurePnaclInstalled(PP_Instance instance,
206 PP_CompletionCallback callback) {
207 ppapi::thunk::EnterInstance enter(instance, callback);
208 if (enter.failed())
209 return enter.retval();
210 if (!InitializePnaclResourceHost())
211 return enter.SetResult(PP_ERROR_FAILED);
212 g_pnacl_resource_host.Get()->EnsurePnaclInstalled(
213 instance,
214 enter.callback());
215 return enter.SetResult(PP_OK_COMPLETIONPENDING);
216}
217
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000218PP_FileHandle GetReadonlyPnaclFD(const char* filename) {
219 IPC::PlatformFileForTransit out_fd = IPC::InvalidPlatformFileForTransit();
220 IPC::Sender* sender = content::RenderThread::Get();
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100221 DCHECK(sender);
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100222 if (!sender->Send(new NaClHostMsg_GetReadonlyPnaclFD(
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000223 std::string(filename),
224 &out_fd))) {
225 return base::kInvalidPlatformFileValue;
226 }
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000227 if (out_fd == IPC::InvalidPlatformFileForTransit()) {
228 return base::kInvalidPlatformFileValue;
229 }
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000230 base::PlatformFile handle =
231 IPC::PlatformFileForTransitToPlatformFile(out_fd);
232 return handle;
233}
234
235PP_FileHandle CreateTemporaryFile(PP_Instance instance) {
236 IPC::PlatformFileForTransit transit_fd = IPC::InvalidPlatformFileForTransit();
237 IPC::Sender* sender = content::RenderThread::Get();
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100238 DCHECK(sender);
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100239 if (!sender->Send(new NaClHostMsg_NaClCreateTemporaryFile(
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000240 &transit_fd))) {
241 return base::kInvalidPlatformFileValue;
242 }
243
244 if (transit_fd == IPC::InvalidPlatformFileForTransit()) {
245 return base::kInvalidPlatformFileValue;
246 }
247
248 base::PlatformFile handle = IPC::PlatformFileForTransitToPlatformFile(
249 transit_fd);
250 return handle;
251}
252
Ben Murdocheb525c52013-07-10 11:40:50 +0100253int32_t GetNexeFd(PP_Instance instance,
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100254 const char* pexe_url,
255 uint32_t abi_version,
256 uint32_t opt_level,
257 const char* last_modified,
258 const char* etag,
Ben Murdocheb525c52013-07-10 11:40:50 +0100259 PP_Bool* is_hit,
260 PP_FileHandle* handle,
261 struct PP_CompletionCallback callback) {
Ben Murdocheb525c52013-07-10 11:40:50 +0100262 ppapi::thunk::EnterInstance enter(instance, callback);
263 if (enter.failed())
264 return enter.retval();
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100265 if (!pexe_url || !last_modified || !etag || !is_hit || !handle)
266 return enter.SetResult(PP_ERROR_BADARGUMENT);
267 if (!InitializePnaclResourceHost())
268 return enter.SetResult(PP_ERROR_FAILED);
269
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100270 base::Time last_modified_time;
271 // If FromString fails, it doesn't touch last_modified_time and we just send
272 // the default-constructed null value.
273 base::Time::FromString(last_modified, &last_modified_time);
274
275 nacl::PnaclCacheInfo cache_info;
276 cache_info.pexe_url = GURL(pexe_url);
277 cache_info.abi_version = abi_version;
278 cache_info.opt_level = opt_level;
279 cache_info.last_modified = last_modified_time;
280 cache_info.etag = std::string(etag);
281
282 g_pnacl_resource_host.Get()->RequestNexeFd(
283 GetRoutingID(instance),
Ben Murdochca12bfa2013-07-23 11:17:05 +0100284 instance,
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100285 cache_info,
286 is_hit,
287 handle,
288 enter.callback());
289
290 return enter.SetResult(PP_OK_COMPLETIONPENDING);
Ben Murdocheb525c52013-07-10 11:40:50 +0100291}
292
Ben Murdochbb1529c2013-08-08 10:24:53 +0100293void ReportTranslationFinished(PP_Instance instance, PP_Bool success) {
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100294 // If the resource host isn't initialized, don't try to do that here.
295 // Just return because something is already very wrong.
296 if (g_pnacl_resource_host.Get() == NULL)
297 return;
Ben Murdochbb1529c2013-08-08 10:24:53 +0100298 g_pnacl_resource_host.Get()->ReportTranslationFinished(instance, success);
Ben Murdocheb525c52013-07-10 11:40:50 +0100299}
300
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000301PP_Bool IsOffTheRecord() {
302 return PP_FromBool(ChromeRenderProcessObserver::is_incognito_process());
303}
304
305PP_Bool IsPnaclEnabled() {
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000306 return PP_FromBool(
Ben Murdoch558790d2013-07-30 15:19:42 +0100307 !CommandLine::ForCurrentProcess()->HasSwitch(switches::kDisablePnacl));
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000308}
309
Ben Murdocha3f7b4e2013-07-24 10:36:34 +0100310PP_ExternalPluginResult ReportNaClError(PP_Instance instance,
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000311 PP_NaClError error_id) {
312 IPC::Sender* sender = content::RenderThread::Get();
313
314 if (!sender->Send(
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100315 new NaClHostMsg_NaClErrorStatus(
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000316 // TODO(dschuff): does this enum need to be sent as an int,
317 // or is it safe to include the appropriate headers in
318 // render_messages.h?
319 GetRoutingID(instance), static_cast<int>(error_id)))) {
Ben Murdocha3f7b4e2013-07-24 10:36:34 +0100320 return PP_EXTERNAL_PLUGIN_FAILED;
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000321 }
Ben Murdocha3f7b4e2013-07-24 10:36:34 +0100322 return PP_EXTERNAL_PLUGIN_OK;
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000323}
324
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100325PP_FileHandle OpenNaClExecutable(PP_Instance instance,
326 const char* file_url,
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100327 uint64_t* nonce_lo,
328 uint64_t* nonce_hi) {
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100329 IPC::PlatformFileForTransit out_fd = IPC::InvalidPlatformFileForTransit();
330 IPC::Sender* sender = content::RenderThread::Get();
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100331 DCHECK(sender);
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100332 *nonce_lo = 0;
333 *nonce_hi = 0;
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100334 base::FilePath file_path;
335 if (!sender->Send(
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +0100336 new NaClHostMsg_OpenNaClExecutable(GetRoutingID(instance),
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100337 GURL(file_url),
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +0100338 &out_fd,
339 nonce_lo,
340 nonce_hi))) {
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100341 return base::kInvalidPlatformFileValue;
342 }
343
344 if (out_fd == IPC::InvalidPlatformFileForTransit()) {
345 return base::kInvalidPlatformFileValue;
346 }
347
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100348 base::PlatformFile handle =
349 IPC::PlatformFileForTransitToPlatformFile(out_fd);
350 return handle;
351}
352
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000353const PPB_NaCl_Private nacl_interface = {
354 &LaunchSelLdr,
355 &StartPpapiProxy,
356 &UrandomFD,
357 &Are3DInterfacesDisabled,
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000358 &BrokerDuplicateHandle,
Ben Murdoch2385ea32013-08-06 11:01:04 +0100359 &EnsurePnaclInstalled,
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000360 &GetReadonlyPnaclFD,
361 &CreateTemporaryFile,
Ben Murdocheb525c52013-07-10 11:40:50 +0100362 &GetNexeFd,
363 &ReportTranslationFinished,
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000364 &IsOffTheRecord,
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000365 &IsPnaclEnabled,
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100366 &ReportNaClError,
367 &OpenNaClExecutable
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000368};
369
370} // namespace
371
372const PPB_NaCl_Private* PPB_NaCl_Private_Impl::GetInterface() {
373 return &nacl_interface;
374}
375
376#endif // DISABLE_NACL