Commit c47ec40b authored by mseaborn@chromium.org's avatar mseaborn@chromium.org

NaCl: Allow setting up multiple sockets for subprocess instead of just one

Remove the "channel number" parameter from messages, since this is now
fixed in the NaCl plugin code in sel_main_chrome.c.

Replace pair_ and descriptor_ with sockets_for_renderer_ and
sockets_for_sel_ldr_.

NaClProcessMsg_Start: Pass an array of FDs instead of one FD.

ViewHostMsg_LaunchNaCl:
 * Add socket count.
 * Return an array of FDs instead of one FD.

Expose this functionality to the NaCl plugin via a new function,
"launch_nacl_process_multi_fd".

BUG=50626
TEST=nacl_ui_tests

Review URL: http://codereview.chromium.org/2832093

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@54113 0039d316-1c4b-4281-b951-d872f2087c98
parent a4a84960
......@@ -25,13 +25,25 @@
#include "chrome/browser/nacl_host/nacl_broker_service_win.h"
#endif
namespace {
void SetCloseOnExec(nacl::Handle fd) {
#if defined(OS_POSIX)
int flags = fcntl(fd, F_GETFD);
CHECK(flags != -1);
int rc = fcntl(fd, F_SETFD, flags | FD_CLOEXEC);
CHECK(rc == 0);
#endif
}
} // namespace
NaClProcessHost::NaClProcessHost(
ResourceDispatcherHost *resource_dispatcher_host,
const std::wstring& url)
: BrowserChildProcessHost(NACL_LOADER_PROCESS, resource_dispatcher_host),
resource_dispatcher_host_(resource_dispatcher_host),
reply_msg_(NULL),
descriptor_(0),
running_on_wow64_(false) {
set_name(url);
#if defined(OS_WIN)
......@@ -43,6 +55,13 @@ NaClProcessHost::~NaClProcessHost() {
if (!reply_msg_)
return;
for (size_t i = 0; i < sockets_for_renderer_.size(); i++) {
nacl::Close(sockets_for_renderer_[i]);
}
for (size_t i = 0; i < sockets_for_sel_ldr_.size(); i++) {
nacl::Close(sockets_for_sel_ldr_[i]);
}
// OnProcessLaunched didn't get called because the process couldn't launch.
// Don't keep the renderer hanging.
reply_msg_->set_reply_error();
......@@ -50,20 +69,41 @@ NaClProcessHost::~NaClProcessHost() {
}
bool NaClProcessHost::Launch(ResourceMessageFilter* resource_message_filter,
const int descriptor,
int socket_count,
IPC::Message* reply_msg) {
#ifdef DISABLE_NACL
NOTIMPLEMENTED() << "Native Client disabled at build time";
return false;
#else
// Create a connected socket
if (nacl::SocketPair(pair_) == -1)
// Place an arbitrary limit on the number of sockets to limit
// exposure in case the renderer is compromised. We can increase
// this if necessary.
if (socket_count > 8) {
return false;
}
// Rather than creating a socket pair in the renderer, and passing
// one side through the browser to sel_ldr, socket pairs are created
// in the browser and then passed to the renderer and sel_ldr.
//
// This is mainly for the benefit of Windows, where sockets cannot
// be passed in messages, but are copied via DuplicateHandle().
// This means the sandboxed renderer cannot send handles to the
// browser process.
for (int i = 0; i < socket_count; i++) {
nacl::Handle pair[2];
// Create a connected socket
if (nacl::SocketPair(pair) == -1)
return false;
sockets_for_renderer_.push_back(pair[0]);
sockets_for_sel_ldr_.push_back(pair[1]);
SetCloseOnExec(pair[0]);
SetCloseOnExec(pair[1]);
}
// Launch the process
descriptor_ = descriptor;
if (!LaunchSelLdr()) {
nacl::Close(pair_[0]);
return false;
}
......@@ -129,22 +169,34 @@ void NaClProcessHost::OnChildDied() {
}
void NaClProcessHost::OnProcessLaunched() {
nacl::FileDescriptor imc_handle;
std::vector<nacl::FileDescriptor> handles_for_renderer;
base::ProcessHandle nacl_process_handle;
for (size_t i = 0; i < sockets_for_renderer_.size(); i++) {
#if defined(OS_WIN)
// Duplicate the IMC handle
// We assume the size of imc_handle has the same size as HANDLE, so the cast
// below is safe.
DCHECK(sizeof(HANDLE) == sizeof(imc_handle));
DuplicateHandle(base::GetCurrentProcessHandle(),
reinterpret_cast<HANDLE>(pair_[0]),
resource_message_filter_->handle(),
reinterpret_cast<HANDLE*>(&imc_handle),
GENERIC_READ | GENERIC_WRITE,
FALSE,
DUPLICATE_CLOSE_SOURCE);
// Copy the handle into the renderer process.
HANDLE handle_in_renderer;
DuplicateHandle(base::GetCurrentProcessHandle(),
reinterpret_cast<HANDLE>(sockets_for_renderer_[i]),
resource_message_filter_->handle(),
&handle_in_renderer,
GENERIC_READ | GENERIC_WRITE,
FALSE,
DUPLICATE_CLOSE_SOURCE);
handles_for_renderer.push_back(
reinterpret_cast<nacl::FileDescriptor>(handle_in_renderer));
#else
// No need to dup the imc_handle - we don't pass it anywhere else so
// it cannot be closed.
nacl::FileDescriptor imc_handle;
imc_handle.fd = sockets_for_renderer_[i];
imc_handle.auto_close = true;
handles_for_renderer.push_back(imc_handle);
#endif
}
// Duplicate the process handle
#if defined(OS_WIN)
// Copy the process handle into the renderer process.
DuplicateHandle(base::GetCurrentProcessHandle(),
handle(),
resource_message_filter_->handle(),
......@@ -153,16 +205,6 @@ void NaClProcessHost::OnProcessLaunched() {
FALSE,
0);
#else
int flags = fcntl(pair_[0], F_GETFD);
if (flags != -1) {
flags |= FD_CLOEXEC;
fcntl(pair_[0], F_SETFD, flags);
}
// No need to dup the imc_handle - we don't pass it anywhere else so
// it cannot be closed.
imc_handle.fd = pair_[0];
imc_handle.auto_close = true;
// We use pid as process handle on Posix
nacl_process_handle = handle();
#endif
......@@ -171,30 +213,40 @@ void NaClProcessHost::OnProcessLaunched() {
base::ProcessId nacl_process_id = base::GetProcId(handle());
ViewHostMsg_LaunchNaCl::WriteReplyParams(
reply_msg_, imc_handle, nacl_process_handle, nacl_process_id);
reply_msg_, handles_for_renderer, nacl_process_handle, nacl_process_id);
resource_message_filter_->Send(reply_msg_);
resource_message_filter_ = NULL;
reply_msg_ = NULL;
sockets_for_renderer_.clear();
SendStartMessage();
}
void NaClProcessHost::SendStartMessage() {
nacl::FileDescriptor channel;
std::vector<nacl::FileDescriptor> handles_for_sel_ldr;
for (size_t i = 0; i < sockets_for_sel_ldr_.size(); i++) {
#if defined(OS_WIN)
if (!DuplicateHandle(GetCurrentProcess(),
reinterpret_cast<HANDLE>(pair_[1]),
handle(),
reinterpret_cast<HANDLE*>(&channel),
GENERIC_READ | GENERIC_WRITE,
FALSE, DUPLICATE_CLOSE_SOURCE)) {
return;
}
HANDLE channel;
if (!DuplicateHandle(GetCurrentProcess(),
reinterpret_cast<HANDLE>(sockets_for_sel_ldr_[i]),
handle(),
&channel,
GENERIC_READ | GENERIC_WRITE,
FALSE, DUPLICATE_CLOSE_SOURCE)) {
return;
}
handles_for_sel_ldr.push_back(
reinterpret_cast<nacl::FileDescriptor>(channel));
#else
channel.fd = dup(pair_[1]);
channel.auto_close = true;
nacl::FileDescriptor channel;
channel.fd = dup(sockets_for_sel_ldr_[i]);
channel.auto_close = true;
handles_for_sel_ldr.push_back(channel);
#endif
Send(new NaClProcessMsg_Start(descriptor_, channel));
}
Send(new NaClProcessMsg_Start(handles_for_sel_ldr));
sockets_for_sel_ldr_.clear();
}
void NaClProcessHost::OnMessageReceived(const IPC::Message& msg) {
......
......@@ -29,7 +29,7 @@ class NaClProcessHost : public BrowserChildProcessHost {
// Initialize the new NaCl process, returning true on success.
bool Launch(ResourceMessageFilter* resource_message_filter,
const int descriptor,
int socket_count,
IPC::Message* reply_msg);
virtual void OnMessageReceived(const IPC::Message& msg);
......@@ -69,11 +69,9 @@ class NaClProcessHost : public BrowserChildProcessHost {
// The reply message to send.
IPC::Message* reply_msg_;
// The socket pair for the NaCl process.
nacl::Handle pair_[2];
// The NaCl specific descriptor for this process.
int descriptor_;
// Socket pairs for the NaCl process and renderer.
std::vector<nacl::Handle> sockets_for_renderer_;
std::vector<nacl::Handle> sockets_for_sel_ldr_;
// Windows platform flag
bool running_on_wow64_;
......
......@@ -10,9 +10,8 @@
// These are messages sent from the browser to the NaCl process.
IPC_BEGIN_MESSAGES(NaClProcess)
// Tells the NaCl process to start.
IPC_MESSAGE_CONTROL2(NaClProcessMsg_Start,
int /* descriptor id */,
nacl::FileDescriptor /* handle value */)
IPC_MESSAGE_CONTROL1(NaClProcessMsg_Start,
std::vector<nacl::FileDescriptor> /* sockets */)
// Tells the NaCl broker to launch a NaCl loader process.
IPC_MESSAGE_CONTROL1(NaClProcessMsg_LaunchLoaderThroughBroker,
......
......@@ -1409,8 +1409,9 @@ IPC_BEGIN_MESSAGES(ViewHost)
// the process and return a handle to an IMC channel.
IPC_SYNC_MESSAGE_CONTROL2_3(ViewHostMsg_LaunchNaCl,
std::wstring /* url for the NaCl module */,
int /* channel number */,
nacl::FileDescriptor /* imc channel handle */,
int /* socket count */,
std::vector<nacl::FileDescriptor>
/* imc channel handles */,
base::ProcessHandle /* NaCl process handle */,
base::ProcessId /* NaCl process id */)
......
......@@ -36,8 +36,11 @@ void NaClThread::OnControlMessageReceived(const IPC::Message& msg) {
IPC_END_MESSAGE_MAP()
}
void NaClThread::OnStartSelLdr(int channel_descriptor,
nacl::FileDescriptor handle) {
NaClHandle nacl_handle = nacl::ToNativeHandle(handle);
NaClMainForChromium(/* handle_count= */ 1, &nacl_handle);
void NaClThread::OnStartSelLdr(std::vector<nacl::FileDescriptor> handles) {
NaClHandle* array = new NaClHandle[handles.size()];
for (size_t i = 0; i < handles.size(); i++) {
array[i] = nacl::ToNativeHandle(handles[i]);
}
NaClMainForChromium(static_cast<int>(handles.size()), array);
delete array;
}
......@@ -22,7 +22,7 @@ class NaClThread : public ChildThread {
private:
virtual void OnControlMessageReceived(const IPC::Message& msg);
void OnStartSelLdr(int channel_descriptor, nacl::FileDescriptor handle);
void OnStartSelLdr(std::vector<nacl::FileDescriptor> handles);
// TODO(gregoryd): do we need to override Cleanup as in PluginThread?
DISALLOW_COPY_AND_ASSIGN(NaClThread);
......
......@@ -52,17 +52,45 @@ bool LaunchNaClProcess(const char* url,
int* nacl_process_id) {
// TODO(gregoryd): nacl::FileDescriptor will be soon merged with
// base::FileDescriptor
nacl::FileDescriptor imc_descriptor;
std::vector<nacl::FileDescriptor> sockets;
base::ProcessHandle nacl_process;
if (!RenderThread::current()->Send(
new ViewHostMsg_LaunchNaCl(ASCIIToWide(url),
imc_fd,
&imc_descriptor,
new ViewHostMsg_LaunchNaCl(
ASCIIToWide(url),
/* socket_count= */ 1,
&sockets,
&nacl_process,
reinterpret_cast<base::ProcessId*>(nacl_process_id)))) {
return false;
}
*imc_handle = nacl::ToNativeHandle(imc_descriptor);
CHECK(static_cast<int>(sockets.size()) == 1);
*imc_handle = nacl::ToNativeHandle(sockets[0]);
*nacl_process_handle = nacl_process;
return true;
}
bool LaunchNaClProcessMultiFD(const char* alleged_url,
int socket_count,
nacl::Handle* imc_handles,
nacl::Handle* nacl_process_handle,
int* nacl_process_id) {
// TODO(gregoryd): nacl::FileDescriptor will be soon merged with
// base::FileDescriptor
std::vector<nacl::FileDescriptor> sockets;
base::ProcessHandle nacl_process;
if (!RenderThread::current()->Send(
new ViewHostMsg_LaunchNaCl(
ASCIIToWide(alleged_url),
socket_count,
&sockets,
&nacl_process,
reinterpret_cast<base::ProcessId*>(nacl_process_id)))) {
return false;
}
CHECK(static_cast<int>(sockets.size()) == socket_count);
for (int i = 0; i < socket_count; i++) {
imc_handles[i] = nacl::ToNativeHandle(sockets[i]);
}
*nacl_process_handle = nacl_process;
return true;
}
......@@ -160,6 +188,8 @@ RenderProcessImpl::RenderProcessImpl()
std::map<std::string, uintptr_t> funcs;
funcs["launch_nacl_process"] =
reinterpret_cast<uintptr_t>(LaunchNaClProcess);
funcs["launch_nacl_process_multi_fd"] =
reinterpret_cast<uintptr_t>(LaunchNaClProcessMultiFD);
RegisterInternalNaClPlugin(funcs);
}
#endif
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment