Skip to content

Commit

Permalink
Reland - Create a database for NaCl validation caching that is shared…
Browse files Browse the repository at this point in the history
… between processes.

Originally reverted in 129077 due to perf regression. Followup commit will fix up expectations.
http://chromegw.corp.google.com/i/chromium/builders/Linux%20x64/builds/25780

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

TBR=ncbray@chromium.org
Review URL: https://chromiumcodereview.appspot.com/9808113

TBR=nduca@google.com
Review URL: https://chromiumcodereview.appspot.com/9860020

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@129082 0039d316-1c4b-4281-b951-d872f2087c98
  • Loading branch information
nduca@google.com committed Mar 27, 2012
1 parent 43cfea7 commit 4a0141b
Show file tree
Hide file tree
Showing 9 changed files with 246 additions and 32 deletions.
53 changes: 50 additions & 3 deletions chrome/browser/nacl_host/nacl_process_host.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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();
}

Expand Down Expand Up @@ -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;
}
7 changes: 6 additions & 1 deletion chrome/browser/nacl_host/nacl_process_host.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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;

Expand Down
1 change: 1 addition & 0 deletions chrome/chrome_exe.gypi
Original file line number Diff line number Diff line change
Expand Up @@ -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',
],
Expand Down
13 changes: 12 additions & 1 deletion chrome/common/nacl_messages.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */,
Expand Down Expand Up @@ -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 */)
91 changes: 85 additions & 6 deletions chrome/nacl/nacl_listener.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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;
Expand Down
22 changes: 22 additions & 0 deletions chrome/nacl/nacl_listener.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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);
Expand Down
Loading

0 comments on commit 4a0141b

Please sign in to comment.