Index: components/nacl/renderer/ppb_nacl_private_impl.cc |
diff --git a/components/nacl/renderer/ppb_nacl_private_impl.cc b/components/nacl/renderer/ppb_nacl_private_impl.cc |
index 3c84afe5d1ee4a16187fef0b715342f5b239acf4..f3b1aef5d5569c3cafbe8b8dfd7d0944a4ff2c5f 100644 |
--- a/components/nacl/renderer/ppb_nacl_private_impl.cc |
+++ b/components/nacl/renderer/ppb_nacl_private_impl.cc |
@@ -16,6 +16,7 @@ |
#include "base/files/file.h" |
#include "base/lazy_instance.h" |
#include "base/logging.h" |
+#include "base/macros.h" |
#include "base/rand_util.h" |
#include "base/strings/string_split.h" |
#include "base/strings/string_util.h" |
@@ -41,6 +42,7 @@ |
#include "content/public/renderer/render_thread.h" |
#include "content/public/renderer/render_view.h" |
#include "content/public/renderer/renderer_ppapi_host.h" |
+#include "ipc/ipc_message_attachment_set.h" |
#include "native_client/src/public/imc_types.h" |
#include "net/base/data_url.h" |
#include "net/base/net_errors.h" |
@@ -73,6 +75,20 @@ const char* const kPortableArch = "portable"; |
// The base URL for resources used by the PNaCl translator processes. |
const char* kPNaClTranslatorBaseUrl = "chrome://pnacl-translator/"; |
+// The maximum number of resource files DownloadNexe() can open. |
+const size_t kMaxPreOpenResourceFiles = 2; |
Mark Seaborn
2015/02/12 03:57:34
How about adding a TODO to increase this, to docum
Yusuke Sato
2015/02/13 23:01:17
Done. Moved to nacl_host_message_filter.cc.
|
+ |
+#if defined(OS_POSIX) |
+// On POSIX platforms, the maximum number of files a process can pass to |
+// another is limited to kMaxDescriptorsPerMessage. Since the browser process |
+// may use up to 5 descriptors for passing non-resource files when creating |
+// the NaCl plugin process, kMaxPreOpenResourceFiles must be smaller than or |
+// equal to (IPC::MessageAttachmentSet::kMaxDescriptorsPerMessage - 5). |
+COMPILE_ASSERT(kMaxPreOpenResourceFiles <= |
Mark Seaborn
2015/02/12 03:57:34
What would happen if we didn't have this check?
I
Yusuke Sato
2015/02/13 23:01:17
Ok, dropped.
|
+ IPC::MessageAttachmentSet::kMaxDescriptorsPerMessage - 5, |
+ k_max_pre_open_resource_files_too_large); |
+#endif |
+ |
base::LazyInstance<scoped_refptr<PnaclTranslationResourceHost> > |
g_pnacl_resource_host = LAZY_INSTANCE_INITIALIZER; |
@@ -104,10 +120,12 @@ class NaClPluginInstance { |
public: |
NaClPluginInstance(PP_Instance instance): |
nexe_load_manager(instance), pexe_size(0) {} |
+ ~NaClPluginInstance(); |
NexeLoadManager nexe_load_manager; |
scoped_ptr<JsonManifest> json_manifest; |
scoped_ptr<InstanceInfo> instance_info; |
+ std::vector<NaClResourceFileInfo> resource_files_info; |
// When translation is complete, this records the size of the pexe in |
// bytes so that it can be reported in a later load event. |
@@ -117,6 +135,19 @@ class NaClPluginInstance { |
typedef base::ScopedPtrHashMap<PP_Instance, NaClPluginInstance> InstanceMap; |
base::LazyInstance<InstanceMap> g_instance_map = LAZY_INSTANCE_INITIALIZER; |
+NaClPluginInstance::~NaClPluginInstance() { |
+ for (size_t i = 0; i < resource_files_info.size(); ++i) { |
+#if defined(OS_POSIX) |
+ base::FileDescriptor fd(resource_files_info[i].file); |
+ if (fd.auto_close) { |
+ base::ScopedFD closer(ToNativeHandle(fd)); |
+ } |
+#elif defined(OS_WIN) |
+ // TOOD(yusukes): Implement once OS_WIN supports pre-opening resources. |
+#endif |
+ } |
+} |
+ |
NaClPluginInstance* GetNaClPluginInstance(PP_Instance instance) { |
InstanceMap& map = g_instance_map.Get(); |
InstanceMap::iterator iter = map.find(instance); |
@@ -401,6 +432,8 @@ void LaunchSelLdr(PP_Instance instance, |
IPC::PlatformFileForTransit nexe_for_transit = |
IPC::InvalidPlatformFileForTransit(); |
+ |
+ NaClPluginInstance* nacl_plugin_instance = GetNaClPluginInstance(instance); |
#if defined(OS_POSIX) |
if (nexe_file_info->handle != PP_kInvalidFileHandle) |
nexe_for_transit = base::FileDescriptor(nexe_file_info->handle, true); |
@@ -409,6 +442,7 @@ void LaunchSelLdr(PP_Instance instance, |
// This is because BrokerGetFileForProcess isn't part of content/public, and |
// it's simpler to do the duplication in the browser anyway. |
nexe_for_transit = nexe_file_info->handle; |
+ // TODO(yusukes): Support pre-opening resource files on Windows. |
#else |
#error Unsupported target platform. |
#endif |
@@ -418,6 +452,7 @@ void LaunchSelLdr(PP_Instance instance, |
nexe_for_transit, |
nexe_file_info->token_lo, |
nexe_file_info->token_hi, |
+ nacl_plugin_instance->resource_files_info, |
routing_id, |
perm_bits, |
PP_ToBool(uses_nonsfi_mode), |
@@ -428,9 +463,11 @@ void LaunchSelLdr(PP_Instance instance, |
FROM_HERE, |
base::Bind(callback.func, callback.user_data, |
static_cast<int32_t>(PP_ERROR_FAILED))); |
+ nacl_plugin_instance->resource_files_info.clear(); |
return; |
} |
+ nacl_plugin_instance->resource_files_info.clear(); |
load_manager->set_nonsfi(PP_ToBool(uses_nonsfi_mode)); |
if (!error_message_string.empty()) { |
@@ -451,10 +488,8 @@ void LaunchSelLdr(PP_Instance instance, |
instance_info.plugin_child_id = launch_result.plugin_child_id; |
// Don't save instance_info if channel handle is invalid. |
- if (IsValidChannelHandle(instance_info.channel_handle)) { |
- NaClPluginInstance* nacl_plugin_instance = GetNaClPluginInstance(instance); |
+ if (IsValidChannelHandle(instance_info.channel_handle)) |
nacl_plugin_instance->instance_info.reset(new InstanceInfo(instance_info)); |
- } |
*(static_cast<NaClHandle*>(imc_handle)) = ToNativeHandle(result_socket); |
@@ -585,6 +620,7 @@ PP_FileHandle GetReadonlyPnaclFd(const char* url, |
std::string filename = PnaclComponentURLToFilename(url); |
IPC::PlatformFileForTransit out_fd = IPC::InvalidPlatformFileForTransit(); |
Yusuke Sato
2015/02/11 05:54:21
reverted to the original code.
|
IPC::Sender* sender = content::RenderThread::Get(); |
+ NaClResourceFileInfo file_info; |
Mark Seaborn
2015/02/12 03:57:34
Not used now?
Yusuke Sato
2015/02/13 23:01:17
Done.
|
DCHECK(sender); |
if (!sender->Send(new NaClHostMsg_GetReadonlyPnaclFD( |
std::string(filename), is_executable, |
@@ -707,14 +743,13 @@ void ReportTranslationFinished(PP_Instance instance, |
} |
} |
-PP_FileHandle OpenNaClExecutable(PP_Instance instance, |
- const char* file_url, |
- uint64_t* nonce_lo, |
- uint64_t* nonce_hi) { |
- // Fast path only works for installed file URLs. |
- GURL gurl(file_url); |
- if (!gurl.SchemeIs("chrome-extension")) |
- return PP_kInvalidFileHandle; |
+bool OpenNaClResources( |
+ PP_Instance instance, |
+ const std::vector<std::string>& resource_file_urls, |
+ std::vector<NaClResourceFileInfo>* out_resource_file_handles) { |
+ DCHECK(out_resource_file_handles); |
+ if (resource_file_urls.empty()) |
+ return false; |
NexeLoadManager* load_manager = GetNexeLoadManager(instance); |
DCHECK(load_manager); |
@@ -724,36 +759,42 @@ PP_FileHandle OpenNaClExecutable(PP_Instance instance, |
content::PepperPluginInstance* plugin_instance = |
content::PepperPluginInstance::Get(instance); |
if (!plugin_instance) |
- return PP_kInvalidFileHandle; |
- // IMPORTANT: Make sure the document can request the given URL. If we don't |
- // check, a malicious app could probe the extension system. This enforces a |
- // same-origin policy which prevents the app from requesting resources from |
- // another app. |
+ return false; |
blink::WebSecurityOrigin security_origin = |
plugin_instance->GetContainer()->element().document().securityOrigin(); |
- if (!security_origin.canRequest(gurl)) |
- return PP_kInvalidFileHandle; |
- |
- IPC::PlatformFileForTransit out_fd = IPC::InvalidPlatformFileForTransit(); |
IPC::Sender* sender = content::RenderThread::Get(); |
DCHECK(sender); |
- *nonce_lo = 0; |
- *nonce_hi = 0; |
- base::FilePath file_path; |
- if (!sender->Send( |
- new NaClHostMsg_OpenNaClExecutable(GetRoutingID(instance), |
- GURL(file_url), |
- !load_manager->nonsfi(), |
- &out_fd, |
- nonce_lo, |
- nonce_hi))) { |
- return PP_kInvalidFileHandle; |
+ |
+ std::vector<GURL> resource_gurls; |
+ for (size_t i = 0; i < resource_file_urls.size(); ++i) { |
+ const GURL gurl(resource_file_urls[i]); |
+ // Fast path only works for installed file URLs. |
+ if (!gurl.SchemeIs("chrome-extension")) |
+ return false; |
+ // IMPORTANT: Make sure the document can request the given URL. If we don't |
+ // check, a malicious app could probe the extension system. This enforces a |
+ // same-origin policy which prevents the app from requesting resources from |
+ // another app. |
+ if (!security_origin.canRequest(gurl)) |
+ return false; |
+ resource_gurls.push_back(gurl); |
} |
- if (out_fd == IPC::InvalidPlatformFileForTransit()) |
- return PP_kInvalidFileHandle; |
+ if (!sender->Send(new NaClHostMsg_OpenNaClResources( |
+ GetRoutingID(instance), |
+ resource_gurls, |
+ !load_manager->nonsfi(), |
+ out_resource_file_handles))) { |
+ return false; |
+ } |
- return IPC::PlatformFileForTransitToPlatformFile(out_fd); |
+ if (out_resource_file_handles->empty() || |
+ (out_resource_file_handles->at(0).file == |
+ IPC::InvalidPlatformFileForTransit())) { |
+ DLOG(ERROR) << "Could not open the main nexe: " << resource_gurls[0]; |
Mark Seaborn
2015/02/12 03:57:34
I don't think you need this special-cased check.
Yusuke Sato
2015/02/13 23:01:17
Done, removed
|
+ return false; |
+ } |
+ return true; |
} |
void DispatchEvent(PP_Instance instance, |
@@ -1211,6 +1252,7 @@ void DownloadNexeCompletion(const DownloadNexeRequest& request, |
void DownloadNexe(PP_Instance instance, |
const char* url, |
+ PP_Bool download_resource_files, |
PP_NaClFileInfo* out_file_info, |
PP_CompletionCallback callback) { |
CHECK(url); |
@@ -1221,16 +1263,43 @@ void DownloadNexe(PP_Instance instance, |
request.callback = callback; |
request.start_time = base::Time::Now(); |
+ std::vector<std::string> file_urls; |
+ file_urls.push_back(url); // the main nexe must be the first element. |
+ |
+ std::vector< |
+ std::pair<std::string /*url*/, std::string /*key*/> > resource_files; |
+ if (download_resource_files) { |
+ JsonManifest* manifest = GetJsonManifest(instance); |
+ if (manifest) |
+ manifest->GetFiles(&resource_files, "chrome-extension"); |
+ if (resource_files.size() > kMaxPreOpenResourceFiles) |
+ resource_files.resize(kMaxPreOpenResourceFiles); |
+ for (size_t i = 0; i < resource_files.size(); ++i) { |
+ file_urls.push_back(resource_files[i].first); |
+ } |
+ } |
+ |
// Try the fast path for retrieving the file first. |
- PP_FileHandle handle = OpenNaClExecutable(instance, |
- url, |
- &out_file_info->token_lo, |
- &out_file_info->token_hi); |
- if (handle != PP_kInvalidFileHandle) { |
+ std::vector<NaClResourceFileInfo> file_handles; |
+ if (OpenNaClResources(instance, file_urls, &file_handles)) { |
+ DCHECK(!file_handles.empty()); |
+ out_file_info->handle = |
+ IPC::PlatformFileForTransitToPlatformFile(file_handles[0].file); |
+ out_file_info->token_lo = file_handles[0].file_token_lo; |
+ out_file_info->token_hi = file_handles[0].file_token_hi; |
+ NaClPluginInstance* nacl_plugin_instance = GetNaClPluginInstance(instance); |
+ for (size_t i = 1; i < file_handles.size(); ++i) { |
+ std::string key = resource_files[i - 1].second; |
+ nacl_plugin_instance->resource_files_info.push_back( |
+ NaClResourceFileInfo(file_handles[i].file, |
+ file_handles[i].file_token_lo, |
+ file_handles[i].file_token_hi, |
+ key)); |
+ } |
DownloadNexeCompletion(request, |
out_file_info, |
FileDownloader::SUCCESS, |
- base::File(handle), |
+ base::File(out_file_info->handle), |
200); |
return; |
} |
@@ -1240,6 +1309,7 @@ void DownloadNexe(PP_Instance instance, |
base::File target_file(CreateTemporaryFile(instance)); |
GURL gurl(url); |
+ // On the slow path, do not retry to pre-open the resource files. |
content::PepperPluginInstance* plugin_instance = |
content::PepperPluginInstance::Get(instance); |
if (!plugin_instance) { |
@@ -1375,17 +1445,15 @@ void DownloadFile(PP_Instance instance, |
} |
// Try the fast path for retrieving the file first. |
- uint64_t file_token_lo = 0; |
- uint64_t file_token_hi = 0; |
- PP_FileHandle file_handle = OpenNaClExecutable(instance, |
- url.c_str(), |
- &file_token_lo, |
- &file_token_hi); |
- if (file_handle != PP_kInvalidFileHandle) { |
+ std::vector<std::string> file_urls; |
+ file_urls.push_back(url); |
+ std::vector<NaClResourceFileInfo> out_handles; |
+ if (OpenNaClResources(instance, file_urls, &out_handles)) { |
PP_NaClFileInfo file_info; |
- file_info.handle = file_handle; |
- file_info.token_lo = file_token_lo; |
- file_info.token_hi = file_token_hi; |
+ file_info.handle = |
+ IPC::PlatformFileForTransitToPlatformFile(out_handles[0].file); |
+ file_info.token_lo = out_handles[0].file_token_lo; |
+ file_info.token_hi = out_handles[0].file_token_hi; |
base::MessageLoop::current()->PostTask( |
FROM_HERE, |
base::Bind(callback, static_cast<int32_t>(PP_OK), file_info)); |