summaryrefslogtreecommitdiffstats
path: root/chrome
diff options
context:
space:
mode:
authorncbray@chromium.org <ncbray@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-03-27 00:16:47 +0000
committerncbray@chromium.org <ncbray@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-03-27 00:16:47 +0000
commit43866cd42bd433961d3b631ebbd9afe2ae85699f (patch)
treedec64d88f0f35f8e00a0b2850d614016b4024381 /chrome
parent000b98ddf1aca041c77865d1ba8968577a1efa35 (diff)
downloadchromium_src-43866cd42bd433961d3b631ebbd9afe2ae85699f.zip
chromium_src-43866cd42bd433961d3b631ebbd9afe2ae85699f.tar.gz
chromium_src-43866cd42bd433961d3b631ebbd9afe2ae85699f.tar.bz2
Create a database for NaCl validation caching that is shared between processes.
This change primarily entails creating a SyncChannel between sel_ldr and the browser. Queries to the database could be made from any thread inside sel_ldr, so the query mechanism needs to be thread safe. This feature is currently disabled by default, and requires an environment variable to enable. A few changes need to be made before this features is safe and can be enabled, such as making sure each installation has a unique, crypographically secure key. BUG= http://code.google.com/p/nativeclient/issues/detail?id=2515 TEST= Run NaCl w/ NACL_VALIDATION_CACHE=1 Review URL: http://codereview.chromium.org/9796006 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@129061 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-rw-r--r--chrome/browser/nacl_host/nacl_process_host.cc53
-rw-r--r--chrome/browser/nacl_host/nacl_process_host.h7
-rw-r--r--chrome/chrome_exe.gypi1
-rw-r--r--chrome/common/nacl_messages.h13
-rw-r--r--chrome/nacl/nacl_listener.cc91
-rw-r--r--chrome/nacl/nacl_listener.h22
6 files changed, 176 insertions, 11 deletions
diff --git a/chrome/browser/nacl_host/nacl_process_host.cc b/chrome/browser/nacl_host/nacl_process_host.cc
index e493752..c4c602e 100644
--- a/chrome/browser/nacl_host/nacl_process_host.cc
+++ b/chrome/browser/nacl_host/nacl_process_host.cc
@@ -9,6 +9,7 @@
#include "base/bind.h"
#include "base/command_line.h"
+#include "base/memory/mru_cache.h"
#include "base/memory/singleton.h"
#include "base/path_service.h"
#include "base/string_util.h"
@@ -195,16 +196,27 @@ class NaClBrowser {
// Path to IRT. Available even before IRT is loaded.
const FilePath& GetIrtFilePath();
+ // Is the validation signature in the database?
+ bool QueryKnownToValidate(const std::string& signature);
+
+ // Put the validation signature in the database.
+ void SetKnownToValidate(const std::string& signature);
+
private:
base::PlatformFile irt_platform_file_;
FilePath irt_filepath_;
+ typedef base::HashingMRUCache<std::string, bool> ValidationCacheType;
+ ValidationCacheType validation_cache_;
+
friend struct DefaultSingletonTraits<NaClBrowser>;
NaClBrowser()
: irt_platform_file_(base::kInvalidPlatformFileValue),
- irt_filepath_() {
+ irt_filepath_(),
+ // For the moment, choose an arbitrary cache size.
+ validation_cache_(200) {
InitIrtFilePath();
}
@@ -843,7 +855,42 @@ void NaClProcessHost::SendStart(base::PlatformFile irt_file) {
internal_->sockets_for_sel_ldr.clear();
}
+bool NaClBrowser::QueryKnownToValidate(const std::string& signature) {
+ ValidationCacheType::iterator iter = validation_cache_.Get(signature);
+ if (iter == validation_cache_.end()) {
+ // Not found.
+ return false;
+ } else {
+ return iter->second;
+ }
+}
+
+void NaClBrowser::SetKnownToValidate(const std::string& signature) {
+ validation_cache_.Put(signature, true);
+}
+
+void NaClProcessHost::OnQueryKnownToValidate(const std::string& signature,
+ bool* result) {
+ *result = NaClBrowser::GetInstance()->QueryKnownToValidate(signature);
+}
+
+void NaClProcessHost::OnSetKnownToValidate(const std::string& signature) {
+ NaClBrowser::GetInstance()->SetKnownToValidate(signature);
+}
+
+// Needed to handle sync messages in OnMessageRecieved.
+bool NaClProcessHost::Send(IPC::Message* msg) {
+ return process_->Send(msg);
+}
+
bool NaClProcessHost::OnMessageReceived(const IPC::Message& msg) {
- NOTREACHED() << "Invalid message with type = " << msg.type();
- return false;
+ bool handled = true;
+ IPC_BEGIN_MESSAGE_MAP(NaClProcessHost, msg)
+ IPC_MESSAGE_HANDLER(NaClProcessMsg_QueryKnownToValidate,
+ OnQueryKnownToValidate)
+ IPC_MESSAGE_HANDLER(NaClProcessMsg_SetKnownToValidate,
+ OnSetKnownToValidate)
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_END_MESSAGE_MAP()
+ return handled;
}
diff --git a/chrome/browser/nacl_host/nacl_process_host.h b/chrome/browser/nacl_host/nacl_process_host.h
index f5e51ec..d4fe80b 100644
--- a/chrome/browser/nacl_host/nacl_process_host.h
+++ b/chrome/browser/nacl_host/nacl_process_host.h
@@ -52,6 +52,8 @@ class NaClProcessHost : public content::BrowserChildProcessHostDelegate {
void OnDebugExceptionHandlerLaunchedByBroker();
#endif
+ bool Send(IPC::Message* msg);
+
private:
// Internal class that holds the nacl::Handle objecs so that
// nacl_process_host.h doesn't include NaCl headers. Needed since it's
@@ -73,7 +75,10 @@ class NaClProcessHost : public content::BrowserChildProcessHostDelegate {
void IrtReady();
void SendStart(base::PlatformFile irt_file);
- private:
+ // Message handlers for validation caching.
+ void OnQueryKnownToValidate(const std::string& signature, bool* result);
+ void OnSetKnownToValidate(const std::string& signature);
+
#if defined(OS_WIN)
class DebugContext;
diff --git a/chrome/chrome_exe.gypi b/chrome/chrome_exe.gypi
index 1271a2d..c1f029b 100644
--- a/chrome/chrome_exe.gypi
+++ b/chrome/chrome_exe.gypi
@@ -533,6 +533,7 @@
'../base/base.gyp:base_nacl_win64',
'../base/base.gyp:base_static_win64',
'../base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations_win64',
+ '../crypto/crypto.gyp:crypto_nacl_win64',
'../ipc/ipc.gyp:ipc_win64',
'../sandbox/sandbox.gyp:sandbox_win64',
],
diff --git a/chrome/common/nacl_messages.h b/chrome/common/nacl_messages.h
index 19ead85..9c7a6f9 100644
--- a/chrome/common/nacl_messages.h
+++ b/chrome/common/nacl_messages.h
@@ -18,7 +18,7 @@
//-----------------------------------------------------------------------------
// NaClProcess messages
-// These are messages sent from the browser to the NaCl process.
+// These are messages sent between the browser and the NaCl process.
// Tells the NaCl process to start.
IPC_MESSAGE_CONTROL2(NaClProcessMsg_Start,
std::vector<nacl::FileDescriptor> /* sockets */,
@@ -47,3 +47,14 @@ IPC_MESSAGE_CONTROL1(NaClProcessMsg_DebugExceptionHandlerLaunched,
// Notify the broker that all loader processes have been terminated and it
// should shutdown.
IPC_MESSAGE_CONTROL0(NaClProcessMsg_StopBroker)
+
+// Used by the NaCl process to query a database in the browser. The database
+// contains the signatures of previously validated code chunks.
+IPC_SYNC_MESSAGE_CONTROL1_1(NaClProcessMsg_QueryKnownToValidate,
+ std::string, /* A validation signature */
+ bool /* Can validation be skipped? */)
+
+// Used by the NaCl process to add a validation signature to the validation
+// database in the browser.
+IPC_MESSAGE_CONTROL1(NaClProcessMsg_SetKnownToValidate,
+ std::string /* A validation signature */)
diff --git a/chrome/nacl/nacl_listener.cc b/chrome/nacl/nacl_listener.cc
index d4a4717..0500a85 100644
--- a/chrome/nacl/nacl_listener.cc
+++ b/chrome/nacl/nacl_listener.cc
@@ -5,13 +5,17 @@
#include "chrome/nacl/nacl_listener.h"
#include <errno.h>
+#include <stdlib.h>
#include "base/command_line.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "base/message_loop.h"
#include "chrome/common/nacl_messages.h"
-#include "ipc/ipc_channel.h"
+#include "chrome/nacl/nacl_validation_db.h"
+#include "chrome/nacl/nacl_validation_query.h"
+#include "ipc/ipc_sync_channel.h"
+#include "ipc/ipc_sync_message_filter.h"
#include "ipc/ipc_switches.h"
#include "native_client/src/trusted/service_runtime/sel_main_chrome.h"
@@ -64,19 +68,85 @@ int CreateMemoryObject(size_t size, int executable) {
}
#endif
+
+// Use an env var because command line args are eaten by nacl_helper.
+bool CheckEnvVar(const char* name, bool default_value) {
+ bool result = default_value;
+ const char* var = getenv(name);
+ if (var && strlen(var) > 0) {
+ result = var[0] != '0';
+ }
+ return result;
+}
+
} // namespace
-NaClListener::NaClListener() : debug_enabled_(false) {}
+class BrowserValidationDBProxy : public NaClValidationDB {
+ public:
+ explicit BrowserValidationDBProxy(NaClListener* listener)
+ : listener_(listener) {
+ }
+
+ bool QueryKnownToValidate(const std::string& signature) {
+ // Initialize to false so that if the Send fails to write to the return
+ // value we're safe. For example if the message is (for some reason)
+ // dispatched as an async message the return parameter will not be written.
+ bool result = false;
+ if (!listener_->Send(new NaClProcessMsg_QueryKnownToValidate(signature,
+ &result))) {
+ LOG(ERROR) << "Failed to query NaCl validation cache.";
+ result = false;
+ }
+ return result;
+ }
+
+ void SetKnownToValidate(const std::string& signature) {
+ // Caching is optional: NaCl will still work correctly if the IPC fails.
+ if (!listener_->Send(new NaClProcessMsg_SetKnownToValidate(signature))) {
+ LOG(ERROR) << "Failed to update NaCl validation cache.";
+ }
+ }
+
+ private:
+ // The listener never dies, otherwise this might be a dangling reference.
+ NaClListener* listener_;
+};
+
+
+NaClListener::NaClListener() : shutdown_event_(true, false),
+ io_thread_("NaCl_IOThread"),
+ main_loop_(NULL),
+ debug_enabled_(false) {
+ io_thread_.StartWithOptions(base::Thread::Options(MessageLoop::TYPE_IO, 0));
+}
-NaClListener::~NaClListener() {}
+NaClListener::~NaClListener() {
+ NOTREACHED();
+ shutdown_event_.Signal();
+}
+
+bool NaClListener::Send(IPC::Message* msg) {
+ DCHECK(main_loop_ != NULL);
+ if (MessageLoop::current() == main_loop_) {
+ // This thread owns the channel.
+ return channel_->Send(msg);
+ } else {
+ // This thread does not own the channel.
+ return filter_->Send(msg);
+ }
+}
void NaClListener::Listen() {
std::string channel_name =
CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
switches::kProcessChannelID);
- IPC::Channel channel(channel_name, IPC::Channel::MODE_CLIENT, this);
- CHECK(channel.Connect());
- MessageLoop::current()->Run();
+ channel_.reset(new IPC::SyncChannel(this, io_thread_.message_loop_proxy(),
+ &shutdown_event_));
+ filter_.reset(new IPC::SyncMessageFilter(&shutdown_event_));
+ channel_->AddFilter(filter_.get());
+ channel_->Init(channel_name, IPC::Channel::MODE_CLIENT, true);
+ main_loop_ = MessageLoop::current();
+ main_loop_->Run();
}
bool NaClListener::OnMessageReceived(const IPC::Message& msg) {
@@ -120,6 +190,15 @@ void NaClListener::OnStartSelLdr(std::vector<nacl::FileDescriptor> handles,
args->irt_fd = irt_handle;
#endif
+ if (CheckEnvVar("NACL_VALIDATION_CACHE", false)) {
+ LOG(INFO) << "NaCl validation cache enabled.";
+ // The cache structure is not freed and exists until the NaCl process exits.
+ args->validation_cache = CreateValidationCache(
+ new BrowserValidationDBProxy(this),
+ // TODO(ncbray) plumb through real keys and versions.
+ "bogus key for HMAC....", "bogus version");
+ }
+
CHECK(handles.size() == 1);
args->imc_bootstrap_handle = nacl::ToNativeHandle(handles[0]);
args->enable_exception_handling = enable_exception_handling;
diff --git a/chrome/nacl/nacl_listener.h b/chrome/nacl/nacl_listener.h
index 2738d7b..2b8bb21 100644
--- a/chrome/nacl/nacl_listener.h
+++ b/chrome/nacl/nacl_listener.h
@@ -8,9 +8,17 @@
#include <vector>
+#include "base/memory/scoped_ptr.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/threading/thread.h"
#include "chrome/common/nacl_types.h"
#include "ipc/ipc_channel.h"
+namespace IPC {
+class SyncChannel;
+class SyncMessageFilter;
+}
+
// The NaClListener is an IPC channel listener that waits for a
// request to start a NaCl module.
class NaClListener : public IPC::Channel::Listener {
@@ -21,11 +29,25 @@ class NaClListener : public IPC::Channel::Listener {
void Listen();
void set_debug_enabled(bool value) {debug_enabled_ = value;}
+ bool Send(IPC::Message* msg);
+
private:
void OnStartSelLdr(std::vector<nacl::FileDescriptor> handles,
bool enable_exception_handling);
virtual bool OnMessageReceived(const IPC::Message& msg) OVERRIDE;
+ // A channel back to the browser.
+ scoped_ptr<IPC::SyncChannel> channel_;
+
+ // A filter that allows other threads to use the channel.
+ scoped_ptr<IPC::SyncMessageFilter> filter_;
+
+ base::WaitableEvent shutdown_event_;
+ base::Thread io_thread_;
+
+ // Used to identify what thread we're on.
+ MessageLoop* main_loop_;
+
bool debug_enabled_;
DISALLOW_COPY_AND_ASSIGN(NaClListener);