Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / components / nacl / renderer / ppb_nacl_private_impl.cc
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/renderer/ppb_nacl_private_impl.h"
6
7 #include <numeric>
8 #include <string>
9 #include <vector>
10
11 #include "base/bind.h"
12 #include "base/bind_helpers.h"
13 #include "base/command_line.h"
14 #include "base/containers/scoped_ptr_hash_map.h"
15 #include "base/cpu.h"
16 #include "base/lazy_instance.h"
17 #include "base/logging.h"
18 #include "base/rand_util.h"
19 #include "components/nacl/common/nacl_host_messages.h"
20 #include "components/nacl/common/nacl_messages.h"
21 #include "components/nacl/common/nacl_switches.h"
22 #include "components/nacl/common/nacl_types.h"
23 #include "components/nacl/renderer/histogram.h"
24 #include "components/nacl/renderer/json_manifest.h"
25 #include "components/nacl/renderer/manifest_downloader.h"
26 #include "components/nacl/renderer/manifest_service_channel.h"
27 #include "components/nacl/renderer/nexe_load_manager.h"
28 #include "components/nacl/renderer/pnacl_translation_resource_host.h"
29 #include "components/nacl/renderer/sandbox_arch.h"
30 #include "components/nacl/renderer/trusted_plugin_channel.h"
31 #include "content/public/common/content_client.h"
32 #include "content/public/common/content_switches.h"
33 #include "content/public/common/sandbox_init.h"
34 #include "content/public/renderer/pepper_plugin_instance.h"
35 #include "content/public/renderer/render_thread.h"
36 #include "content/public/renderer/render_view.h"
37 #include "content/public/renderer/renderer_ppapi_host.h"
38 #include "net/base/data_url.h"
39 #include "net/base/net_errors.h"
40 #include "net/http/http_util.h"
41 #include "ppapi/c/pp_bool.h"
42 #include "ppapi/c/private/pp_file_handle.h"
43 #include "ppapi/native_client/src/trusted/plugin/nacl_entry_points.h"
44 #include "ppapi/shared_impl/ppapi_globals.h"
45 #include "ppapi/shared_impl/ppapi_permissions.h"
46 #include "ppapi/shared_impl/ppapi_preferences.h"
47 #include "ppapi/shared_impl/var.h"
48 #include "ppapi/thunk/enter.h"
49 #include "third_party/WebKit/public/platform/WebURLLoader.h"
50 #include "third_party/WebKit/public/web/WebDocument.h"
51 #include "third_party/WebKit/public/web/WebElement.h"
52 #include "third_party/WebKit/public/web/WebLocalFrame.h"
53 #include "third_party/WebKit/public/web/WebPluginContainer.h"
54 #include "third_party/WebKit/public/web/WebSecurityOrigin.h"
55 #include "third_party/WebKit/public/web/WebURLLoaderOptions.h"
56 #include "third_party/jsoncpp/source/include/json/reader.h"
57 #include "third_party/jsoncpp/source/include/json/value.h"
58
59 namespace nacl {
60 namespace {
61
62 base::LazyInstance<scoped_refptr<PnaclTranslationResourceHost> >
63     g_pnacl_resource_host = LAZY_INSTANCE_INITIALIZER;
64
65 bool InitializePnaclResourceHost() {
66   // Must run on the main thread.
67   content::RenderThread* render_thread = content::RenderThread::Get();
68   if (!render_thread)
69     return false;
70   if (!g_pnacl_resource_host.Get()) {
71     g_pnacl_resource_host.Get() = new PnaclTranslationResourceHost(
72         render_thread->GetIOMessageLoopProxy());
73     render_thread->AddFilter(g_pnacl_resource_host.Get());
74   }
75   return true;
76 }
77
78 struct InstanceInfo {
79   InstanceInfo() : plugin_pid(base::kNullProcessId), plugin_child_id(0) {}
80   GURL url;
81   ppapi::PpapiPermissions permissions;
82   base::ProcessId plugin_pid;
83   int plugin_child_id;
84   IPC::ChannelHandle channel_handle;
85 };
86
87 typedef std::map<PP_Instance, InstanceInfo> InstanceInfoMap;
88
89 base::LazyInstance<InstanceInfoMap> g_instance_info =
90     LAZY_INSTANCE_INITIALIZER;
91
92 typedef base::ScopedPtrHashMap<PP_Instance, NexeLoadManager>
93     NexeLoadManagerMap;
94
95 base::LazyInstance<NexeLoadManagerMap> g_load_manager_map =
96     LAZY_INSTANCE_INITIALIZER;
97
98 typedef base::ScopedPtrHashMap<int32_t, nacl::JsonManifest> JsonManifestMap;
99
100 base::LazyInstance<JsonManifestMap> g_manifest_map =
101     LAZY_INSTANCE_INITIALIZER;
102
103 base::LazyInstance<int32_t> g_next_manifest_id =
104     LAZY_INSTANCE_INITIALIZER;
105
106 // We have to define a method here since we can't use a static initializer.
107 int32_t GetPNaClManifestId() {
108   return std::numeric_limits<int32_t>::max();
109 }
110
111 nacl::NexeLoadManager* GetNexeLoadManager(PP_Instance instance) {
112   NexeLoadManagerMap& map = g_load_manager_map.Get();
113   NexeLoadManagerMap::iterator iter = map.find(instance);
114   if (iter != map.end())
115     return iter->second;
116   return NULL;
117 }
118
119 int GetRoutingID(PP_Instance instance) {
120   // Check that we are on the main renderer thread.
121   DCHECK(content::RenderThread::Get());
122   content::RendererPpapiHost *host =
123       content::RendererPpapiHost::GetForPPInstance(instance);
124   if (!host)
125     return 0;
126   return host->GetRoutingIDForWidget(instance);
127 }
128
129 // Returns whether the channel_handle is valid or not.
130 bool IsValidChannelHandle(const IPC::ChannelHandle& channel_handle) {
131   if (channel_handle.name.empty()) {
132     return false;
133   }
134
135 #if defined(OS_POSIX)
136   if (channel_handle.socket.fd == -1) {
137     return false;
138   }
139 #endif
140
141   return true;
142 }
143
144 // Callback invoked when an IPC channel connection is established.
145 // As we will establish multiple IPC channels, this takes the number
146 // of expected invocations and a callback. When all channels are established,
147 // the given callback will be invoked on the main thread. Its argument will be
148 // PP_OK if all the connections are successfully established. Otherwise,
149 // the first error code will be passed, and remaining errors will be ignored.
150 // Note that PP_CompletionCallback is designed to be called exactly once.
151 class ChannelConnectedCallback {
152  public:
153   ChannelConnectedCallback(int num_expect_calls,
154                            PP_CompletionCallback callback)
155       : num_remaining_calls_(num_expect_calls),
156         callback_(callback),
157         result_(PP_OK) {
158   }
159
160   ~ChannelConnectedCallback() {
161   }
162
163   void Run(int32_t result) {
164     if (result_ == PP_OK && result != PP_OK) {
165       // This is the first error, so remember it.
166       result_ = result;
167     }
168
169     --num_remaining_calls_;
170     if (num_remaining_calls_ > 0) {
171       // There still are some pending or on-going tasks. Wait for the results.
172       return;
173     }
174
175     ppapi::PpapiGlobals::Get()->GetMainThreadMessageLoop()->PostTask(
176         FROM_HERE,
177         base::Bind(callback_.func, callback_.user_data, result_));
178   }
179
180  private:
181   int num_remaining_calls_;
182   PP_CompletionCallback callback_;
183   int32_t result_;
184
185   DISALLOW_COPY_AND_ASSIGN(ChannelConnectedCallback);
186 };
187
188 // Thin adapter from PPP_ManifestService to ManifestServiceChannel::Delegate.
189 // Note that user_data is managed by the caller of LaunchSelLdr. Please see
190 // also PP_ManifestService's comment for more details about resource
191 // management.
192 class ManifestServiceProxy : public ManifestServiceChannel::Delegate {
193  public:
194   ManifestServiceProxy(const PPP_ManifestService* manifest_service,
195                        void* user_data)
196       : manifest_service_(*manifest_service),
197         user_data_(user_data) {
198   }
199
200   virtual ~ManifestServiceProxy() {
201     Quit();
202   }
203
204   virtual void StartupInitializationComplete() OVERRIDE {
205     if (!user_data_)
206       return;
207
208     if (!PP_ToBool(
209             manifest_service_.StartupInitializationComplete(user_data_))) {
210       user_data_ = NULL;
211     }
212   }
213
214   virtual void OpenResource(
215       const std::string& key,
216       const ManifestServiceChannel::OpenResourceCallback& callback) OVERRIDE {
217     if (!user_data_)
218       return;
219
220     // The allocated callback will be freed in DidOpenResource, which is always
221     // called regardless whether OpenResource() succeeds or fails.
222     if (!PP_ToBool(manifest_service_.OpenResource(
223             user_data_,
224             key.c_str(),
225             DidOpenResource,
226             new ManifestServiceChannel::OpenResourceCallback(callback)))) {
227       user_data_ = NULL;
228     }
229   }
230
231  private:
232   static void DidOpenResource(void* user_data, PP_FileHandle file_handle) {
233     scoped_ptr<ManifestServiceChannel::OpenResourceCallback> callback(
234         static_cast<ManifestServiceChannel::OpenResourceCallback*>(user_data));
235     callback->Run(file_handle);
236   }
237
238   void Quit() {
239     if (!user_data_)
240       return;
241
242     bool result = PP_ToBool(manifest_service_.Quit(user_data_));
243     DCHECK(!result);
244     user_data_ = NULL;
245   }
246
247   PPP_ManifestService manifest_service_;
248   void* user_data_;
249   DISALLOW_COPY_AND_ASSIGN(ManifestServiceProxy);
250 };
251
252 // Launch NaCl's sel_ldr process.
253 void LaunchSelLdr(PP_Instance instance,
254                   const char* alleged_url,
255                   PP_Bool uses_irt,
256                   PP_Bool uses_ppapi,
257                   PP_Bool uses_nonsfi_mode,
258                   PP_Bool enable_ppapi_dev,
259                   PP_Bool enable_dyncode_syscalls,
260                   PP_Bool enable_exception_handling,
261                   PP_Bool enable_crash_throttling,
262                   const PPP_ManifestService* manifest_service_interface,
263                   void* manifest_service_user_data,
264                   void* imc_handle,
265                   struct PP_Var* error_message,
266                   PP_CompletionCallback callback) {
267   CHECK(ppapi::PpapiGlobals::Get()->GetMainThreadMessageLoop()->
268             BelongsToCurrentThread());
269
270   // Create the manifest service proxy here, so on error case, it will be
271   // destructed (without passing it to ManifestServiceChannel), and QUIT
272   // will be called in its destructor so that the caller of this function
273   // can free manifest_service_user_data properly.
274   scoped_ptr<ManifestServiceChannel::Delegate> manifest_service_proxy(
275       new ManifestServiceProxy(manifest_service_interface,
276                                manifest_service_user_data));
277
278   FileDescriptor result_socket;
279   IPC::Sender* sender = content::RenderThread::Get();
280   DCHECK(sender);
281   *error_message = PP_MakeUndefined();
282   int routing_id = 0;
283   // If the nexe uses ppapi APIs, we need a routing ID.
284   // To get the routing ID, we must be on the main thread.
285   // Some nexes do not use ppapi and launch from the background thread,
286   // so those nexes can skip finding a routing_id.
287   if (uses_ppapi) {
288     routing_id = GetRoutingID(instance);
289     if (!routing_id) {
290       ppapi::PpapiGlobals::Get()->GetMainThreadMessageLoop()->PostTask(
291           FROM_HERE,
292           base::Bind(callback.func, callback.user_data,
293                      static_cast<int32_t>(PP_ERROR_FAILED)));
294       return;
295     }
296   }
297
298   InstanceInfo instance_info;
299   instance_info.url = GURL(alleged_url);
300
301   uint32_t perm_bits = ppapi::PERMISSION_NONE;
302   // Conditionally block 'Dev' interfaces. We do this for the NaCl process, so
303   // it's clearer to developers when they are using 'Dev' inappropriately. We
304   // must also check on the trusted side of the proxy.
305   if (enable_ppapi_dev)
306     perm_bits |= ppapi::PERMISSION_DEV;
307   instance_info.permissions =
308       ppapi::PpapiPermissions::GetForCommandLine(perm_bits);
309   std::string error_message_string;
310   NaClLaunchResult launch_result;
311
312   if (!sender->Send(new NaClHostMsg_LaunchNaCl(
313           NaClLaunchParams(instance_info.url.spec(),
314                            routing_id,
315                            perm_bits,
316                            PP_ToBool(uses_irt),
317                            PP_ToBool(uses_nonsfi_mode),
318                            PP_ToBool(enable_dyncode_syscalls),
319                            PP_ToBool(enable_exception_handling),
320                            PP_ToBool(enable_crash_throttling)),
321           &launch_result,
322           &error_message_string))) {
323     ppapi::PpapiGlobals::Get()->GetMainThreadMessageLoop()->PostTask(
324         FROM_HERE,
325         base::Bind(callback.func, callback.user_data,
326                    static_cast<int32_t>(PP_ERROR_FAILED)));
327     return;
328   }
329   if (!error_message_string.empty()) {
330     *error_message = ppapi::StringVar::StringToPPVar(error_message_string);
331     ppapi::PpapiGlobals::Get()->GetMainThreadMessageLoop()->PostTask(
332         FROM_HERE,
333         base::Bind(callback.func, callback.user_data,
334                    static_cast<int32_t>(PP_ERROR_FAILED)));
335     return;
336   }
337   result_socket = launch_result.imc_channel_handle;
338   instance_info.channel_handle = launch_result.ppapi_ipc_channel_handle;
339   instance_info.plugin_pid = launch_result.plugin_pid;
340   instance_info.plugin_child_id = launch_result.plugin_child_id;
341
342   // Don't save instance_info if channel handle is invalid.
343   if (IsValidChannelHandle(instance_info.channel_handle))
344     g_instance_info.Get()[instance] = instance_info;
345
346   *(static_cast<NaClHandle*>(imc_handle)) = ToNativeHandle(result_socket);
347
348   // Here after, we starts to establish connections for TrustedPluginChannel
349   // and ManifestServiceChannel in parallel. The invocation of the callback
350   // is delegated to their connection completion callback.
351   base::Callback<void(int32_t)> connected_callback = base::Bind(
352       &ChannelConnectedCallback::Run,
353       base::Owned(new ChannelConnectedCallback(
354           2, // For TrustedPluginChannel and ManifestServiceChannel.
355           callback)));
356
357   NexeLoadManager* load_manager = GetNexeLoadManager(instance);
358   DCHECK(load_manager);
359
360   // Stash the trusted handle as well.
361   if (load_manager &&
362       IsValidChannelHandle(launch_result.trusted_ipc_channel_handle)) {
363     scoped_ptr<TrustedPluginChannel> trusted_plugin_channel(
364         new TrustedPluginChannel(
365             launch_result.trusted_ipc_channel_handle,
366             connected_callback,
367             content::RenderThread::Get()->GetShutdownEvent()));
368     load_manager->set_trusted_plugin_channel(trusted_plugin_channel.Pass());
369   } else {
370     connected_callback.Run(PP_ERROR_FAILED);
371   }
372
373   // Stash the manifest service handle as well.
374   // For security hardening, disable the IPCs for open_resource() when they
375   // aren't needed.  PNaCl doesn't expose open_resource(), and the new
376   // open_resource() IPCs are currently only used for Non-SFI NaCl so far,
377   // not SFI NaCl. Note that enable_dyncode_syscalls is true if and only if
378   // the plugin is a non-PNaCl plugin.
379   if (load_manager &&
380       enable_dyncode_syscalls &&
381       uses_nonsfi_mode &&
382       IsValidChannelHandle(
383           launch_result.manifest_service_ipc_channel_handle)) {
384     scoped_ptr<ManifestServiceChannel> manifest_service_channel(
385         new ManifestServiceChannel(
386             launch_result.manifest_service_ipc_channel_handle,
387             connected_callback,
388             manifest_service_proxy.Pass(),
389             content::RenderThread::Get()->GetShutdownEvent()));
390     load_manager->set_manifest_service_channel(
391         manifest_service_channel.Pass());
392   } else {
393     // Currently, manifest service works only on linux/non-SFI mode.
394     // On other platforms, the socket will not be created, and thus this
395     // condition needs to be handled as success.
396     connected_callback.Run(PP_OK);
397   }
398 }
399
400 // Forward declaration.
401 void ReportLoadError(PP_Instance instance,
402                      PP_NaClError error,
403                      const char* error_message,
404                      const char* console_message);
405
406 PP_Bool StartPpapiProxy(PP_Instance instance) {
407   InstanceInfoMap& map = g_instance_info.Get();
408   InstanceInfoMap::iterator it = map.find(instance);
409   if (it == map.end()) {
410     DLOG(ERROR) << "Could not find instance ID";
411     return PP_FALSE;
412   }
413   InstanceInfo instance_info = it->second;
414   map.erase(it);
415
416   content::PepperPluginInstance* plugin_instance =
417       content::PepperPluginInstance::Get(instance);
418   if (!plugin_instance) {
419     DLOG(ERROR) << "GetInstance() failed";
420     return PP_FALSE;
421   }
422
423   PP_ExternalPluginResult result = plugin_instance->SwitchToOutOfProcessProxy(
424       base::FilePath().AppendASCII(instance_info.url.spec()),
425       instance_info.permissions,
426       instance_info.channel_handle,
427       instance_info.plugin_pid,
428       instance_info.plugin_child_id);
429
430   if (result == PP_EXTERNAL_PLUGIN_OK) {
431     // Log the amound of time that has passed between the trusted plugin being
432     // initialized and the untrusted plugin being initialized.  This is
433     // (roughly) the cost of using NaCl, in terms of startup time.
434     NexeLoadManager* load_manager = GetNexeLoadManager(instance);
435     if (load_manager)
436       load_manager->ReportStartupOverhead();
437     return PP_TRUE;
438   } else if (result == PP_EXTERNAL_PLUGIN_ERROR_MODULE) {
439     ReportLoadError(instance,
440                     PP_NACL_ERROR_START_PROXY_MODULE,
441                     "could not initialize module.",
442                     "could not initialize module.");
443   } else if (result == PP_EXTERNAL_PLUGIN_ERROR_INSTANCE) {
444     ReportLoadError(instance,
445                     PP_NACL_ERROR_START_PROXY_MODULE,
446                     "could not create instance.",
447                     "could not create instance.");
448   }
449   return PP_FALSE;
450 }
451
452 int UrandomFD(void) {
453 #if defined(OS_POSIX)
454   return base::GetUrandomFD();
455 #else
456   return -1;
457 #endif
458 }
459
460 PP_Bool Are3DInterfacesDisabled() {
461   return PP_FromBool(CommandLine::ForCurrentProcess()->HasSwitch(
462                          switches::kDisable3DAPIs));
463 }
464
465 int32_t BrokerDuplicateHandle(PP_FileHandle source_handle,
466                               uint32_t process_id,
467                               PP_FileHandle* target_handle,
468                               uint32_t desired_access,
469                               uint32_t options) {
470 #if defined(OS_WIN)
471   return content::BrokerDuplicateHandle(source_handle, process_id,
472                                         target_handle, desired_access,
473                                         options);
474 #else
475   return 0;
476 #endif
477 }
478
479 PP_FileHandle GetReadonlyPnaclFD(const char* filename) {
480   IPC::PlatformFileForTransit out_fd = IPC::InvalidPlatformFileForTransit();
481   IPC::Sender* sender = content::RenderThread::Get();
482   DCHECK(sender);
483   if (!sender->Send(new NaClHostMsg_GetReadonlyPnaclFD(
484           std::string(filename),
485           &out_fd))) {
486     return base::kInvalidPlatformFileValue;
487   }
488   if (out_fd == IPC::InvalidPlatformFileForTransit()) {
489     return base::kInvalidPlatformFileValue;
490   }
491   base::PlatformFile handle =
492       IPC::PlatformFileForTransitToPlatformFile(out_fd);
493   return handle;
494 }
495
496 PP_FileHandle CreateTemporaryFile(PP_Instance instance) {
497   IPC::PlatformFileForTransit transit_fd = IPC::InvalidPlatformFileForTransit();
498   IPC::Sender* sender = content::RenderThread::Get();
499   DCHECK(sender);
500   if (!sender->Send(new NaClHostMsg_NaClCreateTemporaryFile(
501           &transit_fd))) {
502     return base::kInvalidPlatformFileValue;
503   }
504
505   if (transit_fd == IPC::InvalidPlatformFileForTransit()) {
506     return base::kInvalidPlatformFileValue;
507   }
508
509   base::PlatformFile handle = IPC::PlatformFileForTransitToPlatformFile(
510       transit_fd);
511   return handle;
512 }
513
514 int32_t GetNumberOfProcessors() {
515   int32_t num_processors;
516   IPC::Sender* sender = content::RenderThread::Get();
517   DCHECK(sender);
518   if(!sender->Send(new NaClHostMsg_NaClGetNumProcessors(&num_processors))) {
519     return 1;
520   }
521   return num_processors;
522 }
523
524 PP_Bool IsNonSFIModeEnabled() {
525 #if defined(OS_LINUX)
526   return PP_FromBool(CommandLine::ForCurrentProcess()->HasSwitch(
527                          switches::kEnableNaClNonSfiMode));
528 #else
529   return PP_FALSE;
530 #endif
531 }
532
533 int32_t GetNexeFd(PP_Instance instance,
534                   const char* pexe_url,
535                   uint32_t abi_version,
536                   uint32_t opt_level,
537                   const char* http_headers_param,
538                   const char* extra_flags,
539                   PP_Bool* is_hit,
540                   PP_FileHandle* handle,
541                   struct PP_CompletionCallback callback) {
542   ppapi::thunk::EnterInstance enter(instance, callback);
543   if (enter.failed())
544     return enter.retval();
545   if (!pexe_url || !is_hit || !handle)
546     return enter.SetResult(PP_ERROR_BADARGUMENT);
547   if (!InitializePnaclResourceHost())
548     return enter.SetResult(PP_ERROR_FAILED);
549
550   std::string http_headers(http_headers_param);
551   net::HttpUtil::HeadersIterator iter(
552       http_headers.begin(), http_headers.end(), "\r\n");
553
554   std::string last_modified;
555   std::string etag;
556   bool has_no_store_header = false;
557   while (iter.GetNext()) {
558     if (StringToLowerASCII(iter.name()) == "last-modified")
559       last_modified = iter.values();
560     if (StringToLowerASCII(iter.name()) == "etag")
561       etag = iter.values();
562     if (StringToLowerASCII(iter.name()) == "cache-control") {
563       net::HttpUtil::ValuesIterator values_iter(
564           iter.values_begin(), iter.values_end(), ',');
565       while (values_iter.GetNext()) {
566         if (StringToLowerASCII(values_iter.value()) == "no-store")
567           has_no_store_header = true;
568       }
569     }
570   }
571
572   base::Time last_modified_time;
573   // If FromString fails, it doesn't touch last_modified_time and we just send
574   // the default-constructed null value.
575   base::Time::FromString(last_modified.c_str(), &last_modified_time);
576
577   PnaclCacheInfo cache_info;
578   cache_info.pexe_url = GURL(pexe_url);
579   cache_info.abi_version = abi_version;
580   cache_info.opt_level = opt_level;
581   cache_info.last_modified = last_modified_time;
582   cache_info.etag = etag;
583   cache_info.has_no_store_header = has_no_store_header;
584   cache_info.sandbox_isa = GetSandboxArch();
585   cache_info.extra_flags = std::string(extra_flags);
586
587   g_pnacl_resource_host.Get()->RequestNexeFd(
588       GetRoutingID(instance),
589       instance,
590       cache_info,
591       is_hit,
592       handle,
593       enter.callback());
594
595   return enter.SetResult(PP_OK_COMPLETIONPENDING);
596 }
597
598 void ReportTranslationFinished(PP_Instance instance, PP_Bool success) {
599   // If the resource host isn't initialized, don't try to do that here.
600   // Just return because something is already very wrong.
601   if (g_pnacl_resource_host.Get() == NULL)
602     return;
603   g_pnacl_resource_host.Get()->ReportTranslationFinished(instance, success);
604 }
605
606 PP_FileHandle OpenNaClExecutable(PP_Instance instance,
607                                  const char* file_url,
608                                  uint64_t* nonce_lo,
609                                  uint64_t* nonce_hi) {
610   // Fast path only works for installed file URLs.
611   GURL gurl(file_url);
612   if (!gurl.SchemeIs("chrome-extension"))
613     return PP_kInvalidFileHandle;
614
615   content::PepperPluginInstance* plugin_instance =
616       content::PepperPluginInstance::Get(instance);
617   // IMPORTANT: Make sure the document can request the given URL. If we don't
618   // check, a malicious app could probe the extension system. This enforces a
619   // same-origin policy which prevents the app from requesting resources from
620   // another app.
621   blink::WebSecurityOrigin security_origin =
622       plugin_instance->GetContainer()->element().document().securityOrigin();
623   if (!security_origin.canRequest(gurl))
624     return PP_kInvalidFileHandle;
625
626   IPC::PlatformFileForTransit out_fd = IPC::InvalidPlatformFileForTransit();
627   IPC::Sender* sender = content::RenderThread::Get();
628   DCHECK(sender);
629   *nonce_lo = 0;
630   *nonce_hi = 0;
631   base::FilePath file_path;
632   if (!sender->Send(
633       new NaClHostMsg_OpenNaClExecutable(GetRoutingID(instance),
634                                          GURL(file_url),
635                                          &out_fd,
636                                          nonce_lo,
637                                          nonce_hi))) {
638     return base::kInvalidPlatformFileValue;
639   }
640
641   if (out_fd == IPC::InvalidPlatformFileForTransit()) {
642     return base::kInvalidPlatformFileValue;
643   }
644
645   base::PlatformFile handle =
646       IPC::PlatformFileForTransitToPlatformFile(out_fd);
647   return handle;
648 }
649
650 void DispatchEventOnMainThread(PP_Instance instance,
651                                PP_NaClEventType event_type,
652                                const std::string& resource_url,
653                                PP_Bool length_is_computable,
654                                uint64_t loaded_bytes,
655                                uint64_t total_bytes);
656
657 void DispatchEvent(PP_Instance instance,
658                    PP_NaClEventType event_type,
659                    const char *resource_url,
660                    PP_Bool length_is_computable,
661                    uint64_t loaded_bytes,
662                    uint64_t total_bytes) {
663   ppapi::PpapiGlobals::Get()->GetMainThreadMessageLoop()->PostTask(
664       FROM_HERE,
665       base::Bind(&DispatchEventOnMainThread,
666                  instance,
667                  event_type,
668                  std::string(resource_url),
669                  length_is_computable,
670                  loaded_bytes,
671                  total_bytes));
672 }
673
674 void DispatchEventOnMainThread(PP_Instance instance,
675                                PP_NaClEventType event_type,
676                                const std::string& resource_url,
677                                PP_Bool length_is_computable,
678                                uint64_t loaded_bytes,
679                                uint64_t total_bytes) {
680   NexeLoadManager* load_manager =
681       GetNexeLoadManager(instance);
682   // The instance may have been destroyed after we were scheduled, so do
683   // nothing if it's gone.
684   if (load_manager) {
685     NexeLoadManager::ProgressEvent event(event_type);
686     event.resource_url = resource_url;
687     event.length_is_computable = PP_ToBool(length_is_computable);
688     event.loaded_bytes = loaded_bytes;
689     event.total_bytes = total_bytes;
690     load_manager->DispatchEvent(event);
691   }
692 }
693
694 void NexeFileDidOpen(PP_Instance instance,
695                      int32_t pp_error,
696                      int32_t fd,
697                      int32_t http_status,
698                      int64_t nexe_bytes_read,
699                      const char* url,
700                      int64_t time_since_open) {
701   NexeLoadManager* load_manager = GetNexeLoadManager(instance);
702   if (load_manager) {
703     load_manager->NexeFileDidOpen(pp_error,
704                                   fd,
705                                   http_status,
706                                   nexe_bytes_read,
707                                   url,
708                                   time_since_open);
709   }
710 }
711
712 void ReportLoadSuccess(PP_Instance instance,
713                        const char* url,
714                        uint64_t loaded_bytes,
715                        uint64_t total_bytes) {
716   NexeLoadManager* load_manager = GetNexeLoadManager(instance);
717   if (load_manager)
718     load_manager->ReportLoadSuccess(url, loaded_bytes, total_bytes);
719 }
720
721 void ReportLoadError(PP_Instance instance,
722                      PP_NaClError error,
723                      const char* error_message,
724                      const char* console_message) {
725   NexeLoadManager* load_manager = GetNexeLoadManager(instance);
726   if (load_manager)
727     load_manager->ReportLoadError(error, error_message, console_message);
728 }
729
730 void ReportLoadAbort(PP_Instance instance) {
731   NexeLoadManager* load_manager = GetNexeLoadManager(instance);
732   if (load_manager)
733     load_manager->ReportLoadAbort();
734 }
735
736 void NexeDidCrash(PP_Instance instance, const char* crash_log) {
737   NexeLoadManager* load_manager = GetNexeLoadManager(instance);
738   if (load_manager)
739     load_manager->NexeDidCrash(crash_log);
740 }
741
742 void InstanceCreated(PP_Instance instance) {
743   scoped_ptr<NexeLoadManager> new_load_manager(new NexeLoadManager(instance));
744   NexeLoadManagerMap& map = g_load_manager_map.Get();
745   DLOG_IF(ERROR, map.count(instance) != 0) << "Instance count should be 0";
746   map.add(instance, new_load_manager.Pass());
747 }
748
749 void InstanceDestroyed(PP_Instance instance) {
750   NexeLoadManagerMap& map = g_load_manager_map.Get();
751   DLOG_IF(ERROR, map.count(instance) == 0) << "Could not find instance ID";
752   // The erase may call NexeLoadManager's destructor prior to removing it from
753   // the map. In that case, it is possible for the trusted Plugin to re-enter
754   // the NexeLoadManager (e.g., by calling ReportLoadError). Passing out the
755   // NexeLoadManager to a local scoped_ptr just ensures that its entry is gone
756   // from the map prior to the destructor being invoked.
757   scoped_ptr<NexeLoadManager> temp(map.take(instance));
758   map.erase(instance);
759 }
760
761 PP_Bool NaClDebugEnabledForURL(const char* alleged_nmf_url) {
762   if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnableNaClDebug))
763     return PP_FALSE;
764   bool should_debug;
765   IPC::Sender* sender = content::RenderThread::Get();
766   DCHECK(sender);
767   if(!sender->Send(new NaClHostMsg_NaClDebugEnabledForURL(
768          GURL(alleged_nmf_url),
769          &should_debug))) {
770     return PP_FALSE;
771   }
772   return PP_FromBool(should_debug);
773 }
774
775 void LogToConsole(PP_Instance instance, const char* message) {
776   NexeLoadManager* load_manager = GetNexeLoadManager(instance);
777   DCHECK(load_manager);
778   if (load_manager)
779     load_manager->LogToConsole(std::string(message));
780 }
781
782 PP_NaClReadyState GetNaClReadyState(PP_Instance instance) {
783   NexeLoadManager* load_manager = GetNexeLoadManager(instance);
784   DCHECK(load_manager);
785   if (load_manager)
786     return load_manager->nacl_ready_state();
787   return PP_NACL_READY_STATE_UNSENT;
788 }
789
790 PP_Bool GetIsInstalled(PP_Instance instance) {
791   NexeLoadManager* load_manager = GetNexeLoadManager(instance);
792   DCHECK(load_manager);
793   if (load_manager)
794     return PP_FromBool(load_manager->is_installed());
795   return PP_FALSE;
796 }
797
798 int32_t GetExitStatus(PP_Instance instance) {
799   NexeLoadManager* load_manager = GetNexeLoadManager(instance);
800   DCHECK(load_manager);
801   if (load_manager)
802     return load_manager->exit_status();
803   return -1;
804 }
805
806 void SetExitStatus(PP_Instance instance, int32_t exit_status) {
807   NexeLoadManager* load_manager = GetNexeLoadManager(instance);
808   DCHECK(load_manager);
809   if (load_manager)
810     return load_manager->set_exit_status(exit_status);
811 }
812
813 void Vlog(const char* message) {
814   VLOG(1) << message;
815 }
816
817 void InitializePlugin(PP_Instance instance,
818                       uint32_t argc,
819                       const char* argn[],
820                       const char* argv[]) {
821   NexeLoadManager* load_manager = GetNexeLoadManager(instance);
822   DCHECK(load_manager);
823   if (load_manager)
824     load_manager->InitializePlugin(argc, argn, argv);
825 }
826
827 int64_t GetNexeSize(PP_Instance instance) {
828   NexeLoadManager* load_manager = GetNexeLoadManager(instance);
829   DCHECK(load_manager);
830   if (load_manager)
831     return load_manager->nexe_size();
832   return 0;
833 }
834
835 PP_Bool RequestNaClManifest(PP_Instance instance,
836                             const char* url,
837                             PP_Bool* pp_is_data_uri) {
838   NexeLoadManager* load_manager = GetNexeLoadManager(instance);
839   DCHECK(load_manager);
840   if (load_manager) {
841     bool is_data_uri;
842     bool result = load_manager->RequestNaClManifest(url, &is_data_uri);
843     *pp_is_data_uri = PP_FromBool(is_data_uri);
844     return PP_FromBool(result);
845   }
846   return PP_FALSE;
847 }
848
849 PP_Var GetManifestBaseURL(PP_Instance instance) {
850   NexeLoadManager* load_manager = GetNexeLoadManager(instance);
851   DCHECK(load_manager);
852   if (!load_manager)
853     return PP_MakeUndefined();
854   const GURL& gurl = load_manager->manifest_base_url();
855   if (!gurl.is_valid())
856     return PP_MakeUndefined();
857   return ppapi::StringVar::StringToPPVar(gurl.spec());
858 }
859
860 PP_Bool ResolvesRelativeToPluginBaseURL(PP_Instance instance,
861                                         const char *url) {
862   NexeLoadManager* load_manager = GetNexeLoadManager(instance);
863   DCHECK(load_manager);
864   if (!load_manager)
865     return PP_FALSE;
866   const GURL& gurl = load_manager->plugin_base_url().Resolve(url);
867   if (!gurl.is_valid())
868     return PP_FALSE;
869   return PP_TRUE;
870 }
871
872 PP_Var ParseDataURL(const char* data_url) {
873   GURL gurl(data_url);
874   std::string mime_type;
875   std::string charset;
876   std::string data;
877   if (!net::DataURL::Parse(gurl, &mime_type, &charset, &data))
878     return PP_MakeUndefined();
879   return ppapi::StringVar::StringToPPVar(data);
880 }
881
882 void ProcessNaClManifest(PP_Instance instance, const char* program_url) {
883   nacl::NexeLoadManager* load_manager = GetNexeLoadManager(instance);
884   if (load_manager)
885     load_manager->ProcessNaClManifest(program_url);
886 }
887
888 PP_Var GetManifestURLArgument(PP_Instance instance) {
889   nacl::NexeLoadManager* load_manager = GetNexeLoadManager(instance);
890   if (load_manager) {
891     return ppapi::StringVar::StringToPPVar(
892         load_manager->GetManifestURLArgument());
893   }
894   return PP_MakeUndefined();
895 }
896
897 PP_Bool IsPNaCl(PP_Instance instance) {
898   nacl::NexeLoadManager* load_manager = GetNexeLoadManager(instance);
899   if (load_manager)
900     return PP_FromBool(load_manager->IsPNaCl());
901   return PP_FALSE;
902 }
903
904 PP_Bool DevInterfacesEnabled(PP_Instance instance) {
905   nacl::NexeLoadManager* load_manager = GetNexeLoadManager(instance);
906   if (load_manager)
907     return PP_FromBool(load_manager->DevInterfacesEnabled());
908   return PP_FALSE;
909 }
910
911 void DownloadManifestToBufferCompletion(PP_Instance instance,
912                                         struct PP_CompletionCallback callback,
913                                         struct PP_Var* out_data,
914                                         base::Time start_time,
915                                         PP_NaClError pp_nacl_error,
916                                         const std::string& data);
917
918 void DownloadManifestToBuffer(PP_Instance instance,
919                               struct PP_Var* out_data,
920                               struct PP_CompletionCallback callback) {
921   nacl::NexeLoadManager* load_manager = GetNexeLoadManager(instance);
922   DCHECK(load_manager);
923   if (!load_manager) {
924     ppapi::PpapiGlobals::Get()->GetMainThreadMessageLoop()->PostTask(
925         FROM_HERE,
926         base::Bind(callback.func, callback.user_data,
927                    static_cast<int32_t>(PP_ERROR_FAILED)));
928   }
929
930   const GURL& gurl = load_manager->manifest_base_url();
931
932   content::PepperPluginInstance* plugin_instance =
933       content::PepperPluginInstance::Get(instance);
934   blink::WebURLLoaderOptions options;
935   options.untrustedHTTP = true;
936
937   blink::WebSecurityOrigin security_origin =
938       plugin_instance->GetContainer()->element().document().securityOrigin();
939   // Options settings here follow the original behavior in the trusted
940   // plugin and PepperURLLoaderHost.
941   if (security_origin.canRequest(gurl)) {
942     options.allowCredentials = true;
943   } else {
944     // Allow CORS.
945     options.crossOriginRequestPolicy =
946         blink::WebURLLoaderOptions::CrossOriginRequestPolicyUseAccessControl;
947   }
948
949   blink::WebFrame* frame =
950       plugin_instance->GetContainer()->element().document().frame();
951   blink::WebURLLoader* url_loader = frame->createAssociatedURLLoader(options);
952   blink::WebURLRequest request;
953   request.initialize();
954   request.setURL(gurl);
955   request.setFirstPartyForCookies(frame->document().firstPartyForCookies());
956
957   // ManifestDownloader deletes itself after invoking the callback.
958   ManifestDownloader* client = new ManifestDownloader(
959       load_manager->is_installed(),
960       base::Bind(DownloadManifestToBufferCompletion,
961                  instance, callback, out_data, base::Time::Now()));
962   url_loader->loadAsynchronously(request, client);
963 }
964
965 void DownloadManifestToBufferCompletion(PP_Instance instance,
966                                         struct PP_CompletionCallback callback,
967                                         struct PP_Var* out_data,
968                                         base::Time start_time,
969                                         PP_NaClError pp_nacl_error,
970                                         const std::string& data) {
971   base::TimeDelta download_time = base::Time::Now() - start_time;
972   HistogramTimeSmall("NaCl.Perf.StartupTime.ManifestDownload",
973                      download_time.InMilliseconds());
974
975   nacl::NexeLoadManager* load_manager = GetNexeLoadManager(instance);
976   if (!load_manager) {
977     callback.func(callback.user_data, PP_ERROR_ABORTED);
978     return;
979   }
980
981   int32_t pp_error;
982   switch (pp_nacl_error) {
983     case PP_NACL_ERROR_LOAD_SUCCESS:
984       pp_error = PP_OK;
985       break;
986     case PP_NACL_ERROR_MANIFEST_LOAD_URL:
987       pp_error = PP_ERROR_FAILED;
988       load_manager->ReportLoadError(PP_NACL_ERROR_MANIFEST_LOAD_URL,
989                                     "could not load manifest url.");
990       break;
991     case PP_NACL_ERROR_MANIFEST_TOO_LARGE:
992       pp_error = PP_ERROR_FILETOOBIG;
993       load_manager->ReportLoadError(PP_NACL_ERROR_MANIFEST_TOO_LARGE,
994                                     "manifest file too large.");
995       break;
996     case PP_NACL_ERROR_MANIFEST_NOACCESS_URL:
997       pp_error = PP_ERROR_NOACCESS;
998       load_manager->ReportLoadError(PP_NACL_ERROR_MANIFEST_NOACCESS_URL,
999                                     "access to manifest url was denied.");
1000       break;
1001     default:
1002       NOTREACHED();
1003       pp_error = PP_ERROR_FAILED;
1004       load_manager->ReportLoadError(PP_NACL_ERROR_MANIFEST_LOAD_URL,
1005                                     "could not load manifest url.");
1006   }
1007
1008   if (pp_error == PP_OK) {
1009     std::string contents;
1010     *out_data = ppapi::StringVar::StringToPPVar(data);
1011   }
1012   callback.func(callback.user_data, pp_error);
1013 }
1014
1015 int32_t CreatePNaClManifest(PP_Instance /* instance */) {
1016   return GetPNaClManifestId();
1017 }
1018
1019 int32_t CreateJsonManifest(PP_Instance instance,
1020                            const char* manifest_url,
1021                            const char* isa_type,
1022                            const char* manifest_data) {
1023   int32_t manifest_id = g_next_manifest_id.Get();
1024   g_next_manifest_id.Get()++;
1025
1026   scoped_ptr<nacl::JsonManifest> j(
1027       new nacl::JsonManifest(
1028           manifest_url,
1029           isa_type,
1030           PP_ToBool(IsNonSFIModeEnabled()),
1031           PP_ToBool(NaClDebugEnabledForURL(manifest_url))));
1032   JsonManifest::ErrorInfo error_info;
1033   if (j->Init(manifest_data, &error_info)) {
1034     g_manifest_map.Get().add(manifest_id, j.Pass());
1035     return manifest_id;
1036   }
1037   nacl::NexeLoadManager* load_manager = GetNexeLoadManager(instance);
1038   if (load_manager)
1039     load_manager->ReportLoadError(error_info.error, error_info.string);
1040   return -1;
1041 }
1042
1043 void DestroyManifest(PP_Instance /* instance */,
1044                      int32_t manifest_id) {
1045   if (manifest_id == GetPNaClManifestId())
1046     return;
1047   g_manifest_map.Get().erase(manifest_id);
1048 }
1049
1050 PP_Bool ManifestGetProgramURL(PP_Instance instance,
1051                               int32_t manifest_id,
1052                               PP_Var* pp_full_url,
1053                               PP_PNaClOptions* pnacl_options,
1054                               PP_Bool* pp_uses_nonsfi_mode) {
1055   nacl::NexeLoadManager* load_manager = GetNexeLoadManager(instance);
1056   if (manifest_id == GetPNaClManifestId()) {
1057     if (load_manager) {
1058       load_manager->ReportLoadError(
1059           PP_NACL_ERROR_MANIFEST_GET_NEXE_URL,
1060           "pnacl manifest does not contain a program.");
1061     }
1062     return PP_FALSE;
1063   }
1064
1065   JsonManifestMap::iterator it = g_manifest_map.Get().find(manifest_id);
1066   if (it == g_manifest_map.Get().end())
1067     return PP_FALSE;
1068
1069   bool uses_nonsfi_mode;
1070   std::string full_url;
1071   JsonManifest::ErrorInfo error_info;
1072   if (it->second->GetProgramURL(&full_url, pnacl_options, &uses_nonsfi_mode,
1073                                 &error_info)) {
1074     *pp_full_url = ppapi::StringVar::StringToPPVar(full_url);
1075     *pp_uses_nonsfi_mode = PP_FromBool(uses_nonsfi_mode);
1076     return PP_TRUE;
1077   }
1078
1079   if (load_manager)
1080     load_manager->ReportLoadError(error_info.error, error_info.string);
1081   return PP_FALSE;
1082 }
1083
1084 PP_Bool ManifestResolveKey(PP_Instance instance,
1085                            int32_t manifest_id,
1086                            const char* key,
1087                            PP_Var* pp_full_url,
1088                            PP_PNaClOptions* pnacl_options) {
1089   if (manifest_id == GetPNaClManifestId()) {
1090     pnacl_options->translate = PP_FALSE;
1091     // We can only resolve keys in the files/ namespace.
1092     const std::string kFilesPrefix = "files/";
1093     std::string key_string(key);
1094     if (key_string.find(kFilesPrefix) == std::string::npos) {
1095       nacl::NexeLoadManager* load_manager = GetNexeLoadManager(instance);
1096       if (load_manager)
1097         load_manager->ReportLoadError(PP_NACL_ERROR_MANIFEST_RESOLVE_URL,
1098                                       "key did not start with files/");
1099       return PP_FALSE;
1100     }
1101     std::string key_basename = key_string.substr(kFilesPrefix.length());
1102     std::string pnacl_url =
1103         std::string("chrome://pnacl-translator/") + GetSandboxArch() + "/" +
1104         key_basename;
1105     *pp_full_url = ppapi::StringVar::StringToPPVar(pnacl_url);
1106     return PP_TRUE;
1107   }
1108
1109   JsonManifestMap::iterator it = g_manifest_map.Get().find(manifest_id);
1110   if (it == g_manifest_map.Get().end())
1111     return PP_FALSE;
1112
1113   std::string full_url;
1114   bool ok = it->second->ResolveKey(key, &full_url, pnacl_options);
1115   if (ok)
1116     *pp_full_url = ppapi::StringVar::StringToPPVar(full_url);
1117   return PP_FromBool(ok);
1118 }
1119
1120 PP_Bool GetPNaClResourceInfo(PP_Instance instance,
1121                              const char* filename,
1122                              PP_Var* llc_tool_name,
1123                              PP_Var* ld_tool_name) {
1124   NexeLoadManager* load_manager = GetNexeLoadManager(instance);
1125   DCHECK(load_manager);
1126   if (!load_manager)
1127     return PP_FALSE;
1128
1129   base::PlatformFile file = GetReadonlyPnaclFD(filename);
1130   if (file == base::kInvalidPlatformFileValue) {
1131     load_manager->ReportLoadError(
1132         PP_NACL_ERROR_PNACL_RESOURCE_FETCH,
1133         "The Portable Native Client (pnacl) component is not "
1134         "installed. Please consult chrome://components for more "
1135         "information.");
1136     return PP_FALSE;
1137   }
1138
1139   const int kBufferSize = 1 << 20;
1140   scoped_ptr<char[]> buffer(new char[kBufferSize]);
1141   if (base::ReadPlatformFile(file, 0, buffer.get(), kBufferSize) < 0) {
1142     load_manager->ReportLoadError(
1143         PP_NACL_ERROR_PNACL_RESOURCE_FETCH,
1144         std::string("PnaclResources::ReadResourceInfo reading failed for: ") +
1145             filename);
1146     return PP_FALSE;
1147   }
1148
1149   // Expect the JSON file to contain a top-level object (dictionary).
1150   Json::Reader json_reader;
1151   Json::Value json_data;
1152   if (!json_reader.parse(buffer.get(), json_data)) {
1153     load_manager->ReportLoadError(
1154         PP_NACL_ERROR_PNACL_RESOURCE_FETCH,
1155         std::string("Parsing resource info failed: JSON parse error: ") +
1156             json_reader.getFormattedErrorMessages());
1157     return PP_FALSE;
1158   }
1159
1160   if (!json_data.isObject()) {
1161     load_manager->ReportLoadError(
1162         PP_NACL_ERROR_PNACL_RESOURCE_FETCH,
1163         "Parsing resource info failed: Malformed JSON dictionary");
1164     return PP_FALSE;
1165   }
1166
1167   if (json_data.isMember("pnacl-llc-name")) {
1168     Json::Value json_name = json_data["pnacl-llc-name"];
1169     if (json_name.isString()) {
1170       std::string llc_tool_name_str = json_name.asString();
1171       *llc_tool_name = ppapi::StringVar::StringToPPVar(llc_tool_name_str);
1172     }
1173   }
1174
1175   if (json_data.isMember("pnacl-ld-name")) {
1176     Json::Value json_name = json_data["pnacl-ld-name"];
1177     if (json_name.isString()) {
1178       std::string ld_tool_name_str = json_name.asString();
1179       *ld_tool_name = ppapi::StringVar::StringToPPVar(ld_tool_name_str);
1180     }
1181   }
1182   return PP_TRUE;
1183 }
1184
1185 // Helper to std::accumulate that creates a comma-separated list from the input.
1186 std::string CommaAccumulator(const std::string &lhs, const std::string &rhs) {
1187   if (lhs.empty())
1188     return rhs;
1189   return lhs + "," + rhs;
1190 }
1191
1192 PP_Var GetCpuFeatureAttrs() {
1193   // PNaCl's translator from pexe to nexe can be told exactly what
1194   // capabilities the user's machine has because the pexe to nexe
1195   // translation is specific to the machine, and CPU information goes
1196   // into the translation cache. This allows the translator to generate
1197   // faster code.
1198   //
1199   // Care must be taken to avoid instructions which aren't supported by
1200   // the NaCl sandbox. Ideally the translator would do this, but there's
1201   // no point in not doing the whitelist here.
1202   //
1203   // TODO(jfb) Some features are missing, either because the NaCl
1204   //           sandbox doesn't support them, because base::CPU doesn't
1205   //           detect them, or because they don't help vector shuffles
1206   //           (and we omit them because it simplifies testing). Add the
1207   //           other features.
1208   //
1209   // TODO(jfb) The following is x86-specific. The base::CPU class
1210   //           doesn't handle other architectures very well, and we
1211   //           should at least detect the presence of ARM's integer
1212   //           divide.
1213   std::vector<std::string> attrs;
1214   base::CPU cpu;
1215
1216   // On x86, SSE features are ordered: the most recent one implies the
1217   // others. Care is taken here to only specify the latest SSE version,
1218   // whereas non-SSE features don't follow this model: POPCNT is
1219   // effectively always implied by SSE4.2 but has to be specified
1220   // separately.
1221   //
1222   // TODO: AVX2, AVX, SSE 4.2.
1223   if (cpu.has_sse41()) attrs.push_back("+sse4.1");
1224   // TODO: SSE 4A, SSE 4.
1225   else if (cpu.has_ssse3()) attrs.push_back("+ssse3");
1226   // TODO: SSE 3
1227   else if (cpu.has_sse2()) attrs.push_back("+sse2");
1228
1229   // TODO: AES, POPCNT, LZCNT, ...
1230
1231   return ppapi::StringVar::StringToPPVar(std::accumulate(
1232       attrs.begin(), attrs.end(), std::string(), CommaAccumulator));
1233 }
1234
1235 const PPB_NaCl_Private nacl_interface = {
1236   &LaunchSelLdr,
1237   &StartPpapiProxy,
1238   &UrandomFD,
1239   &Are3DInterfacesDisabled,
1240   &BrokerDuplicateHandle,
1241   &GetReadonlyPnaclFD,
1242   &CreateTemporaryFile,
1243   &GetNumberOfProcessors,
1244   &IsNonSFIModeEnabled,
1245   &GetNexeFd,
1246   &ReportTranslationFinished,
1247   &OpenNaClExecutable,
1248   &DispatchEvent,
1249   &NexeFileDidOpen,
1250   &ReportLoadSuccess,
1251   &ReportLoadError,
1252   &ReportLoadAbort,
1253   &NexeDidCrash,
1254   &InstanceCreated,
1255   &InstanceDestroyed,
1256   &NaClDebugEnabledForURL,
1257   &GetSandboxArch,
1258   &LogToConsole,
1259   &GetNaClReadyState,
1260   &GetIsInstalled,
1261   &GetExitStatus,
1262   &SetExitStatus,
1263   &Vlog,
1264   &InitializePlugin,
1265   &GetNexeSize,
1266   &RequestNaClManifest,
1267   &GetManifestBaseURL,
1268   &ResolvesRelativeToPluginBaseURL,
1269   &ParseDataURL,
1270   &ProcessNaClManifest,
1271   &GetManifestURLArgument,
1272   &IsPNaCl,
1273   &DevInterfacesEnabled,
1274   &DownloadManifestToBuffer,
1275   &CreatePNaClManifest,
1276   &CreateJsonManifest,
1277   &DestroyManifest,
1278   &ManifestGetProgramURL,
1279   &ManifestResolveKey,
1280   &GetPNaClResourceInfo,
1281   &GetCpuFeatureAttrs
1282 };
1283
1284 }  // namespace
1285
1286 const PPB_NaCl_Private* GetNaClPrivateInterface() {
1287   return &nacl_interface;
1288 }
1289
1290 }  // namespace nacl