diff options
author | ncbray@chromium.org <ncbray@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-03-27 00:16:47 +0000 |
---|---|---|
committer | ncbray@chromium.org <ncbray@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-03-27 00:16:47 +0000 |
commit | 43866cd42bd433961d3b631ebbd9afe2ae85699f (patch) | |
tree | dec64d88f0f35f8e00a0b2850d614016b4024381 /chrome | |
parent | 000b98ddf1aca041c77865d1ba8968577a1efa35 (diff) | |
download | chromium_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.cc | 53 | ||||
-rw-r--r-- | chrome/browser/nacl_host/nacl_process_host.h | 7 | ||||
-rw-r--r-- | chrome/chrome_exe.gypi | 1 | ||||
-rw-r--r-- | chrome/common/nacl_messages.h | 13 | ||||
-rw-r--r-- | chrome/nacl/nacl_listener.cc | 91 | ||||
-rw-r--r-- | chrome/nacl/nacl_listener.h | 22 |
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); |