blob: 6adccd0d0bc02a5294519779deb30814bcb93508 [file] [log] [blame]
[email protected]4bdde602010-06-16 03:17:351// Copyright (c) 2010 The Chromium Authors. All rights reserved.
[email protected]d032f492009-09-29 00:33:462// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "build/build_config.h"
6
[email protected]e15a4fa2010-02-11 23:09:297#include "chrome/browser/nacl_host/nacl_process_host.h"
[email protected]d032f492009-09-29 00:33:468
9#if defined(OS_POSIX)
10#include <fcntl.h>
11#endif
12
[email protected]103607e2010-02-01 18:57:0913#include "base/command_line.h"
[email protected]d032f492009-09-29 00:33:4614#include "chrome/browser/renderer_host/resource_message_filter.h"
[email protected]d032f492009-09-29 00:33:4615#include "chrome/common/chrome_switches.h"
16#include "chrome/common/logging_chrome.h"
[email protected]103607e2010-02-01 18:57:0917#include "chrome/common/nacl_cmd_line.h"
[email protected]d032f492009-09-29 00:33:4618#include "chrome/common/nacl_messages.h"
[email protected]fb1277e82009-11-21 20:32:3019#include "chrome/common/render_messages.h"
[email protected]d032f492009-09-29 00:33:4620#include "ipc/ipc_switches.h"
21
[email protected]d032f492009-09-29 00:33:4622#if defined(OS_POSIX)
23#include "ipc/ipc_channel_posix.h"
[email protected]4bdde602010-06-16 03:17:3524#elif defined(OS_WIN)
25#include "chrome/browser/nacl_host/nacl_broker_service_win.h"
[email protected]d032f492009-09-29 00:33:4626#endif
27
[email protected]c47ec402010-07-29 10:20:4928namespace {
29
30void SetCloseOnExec(nacl::Handle fd) {
31#if defined(OS_POSIX)
32 int flags = fcntl(fd, F_GETFD);
33 CHECK(flags != -1);
34 int rc = fcntl(fd, F_SETFD, flags | FD_CLOEXEC);
35 CHECK(rc == 0);
36#endif
37}
38
39} // namespace
40
[email protected]d032f492009-09-29 00:33:4641NaClProcessHost::NaClProcessHost(
[email protected]f08e47d2009-10-15 21:46:1542 ResourceDispatcherHost *resource_dispatcher_host,
43 const std::wstring& url)
[email protected]d27893f62010-07-03 05:47:4244 : BrowserChildProcessHost(NACL_LOADER_PROCESS, resource_dispatcher_host),
[email protected]fb1277e82009-11-21 20:32:3045 resource_dispatcher_host_(resource_dispatcher_host),
46 reply_msg_(NULL),
[email protected]103607e2010-02-01 18:57:0947 running_on_wow64_(false) {
[email protected]f08e47d2009-10-15 21:46:1548 set_name(url);
[email protected]103607e2010-02-01 18:57:0949#if defined(OS_WIN)
50 CheckIsWow64();
51#endif
[email protected]d032f492009-09-29 00:33:4652}
53
[email protected]fb1277e82009-11-21 20:32:3054NaClProcessHost::~NaClProcessHost() {
55 if (!reply_msg_)
56 return;
57
[email protected]990b29e2010-07-29 12:53:4758 // nacl::Close() is not available at link time if DISABLE_NACL is
59 // defined, but we still compile a bunch of other code from this
60 // file anyway. TODO(mseaborn): Make this less messy.
61#ifndef DISABLE_NACL
[email protected]c47ec402010-07-29 10:20:4962 for (size_t i = 0; i < sockets_for_renderer_.size(); i++) {
63 nacl::Close(sockets_for_renderer_[i]);
64 }
65 for (size_t i = 0; i < sockets_for_sel_ldr_.size(); i++) {
66 nacl::Close(sockets_for_sel_ldr_[i]);
67 }
[email protected]990b29e2010-07-29 12:53:4768#endif
[email protected]c47ec402010-07-29 10:20:4969
[email protected]fb1277e82009-11-21 20:32:3070 // OnProcessLaunched didn't get called because the process couldn't launch.
71 // Don't keep the renderer hanging.
72 reply_msg_->set_reply_error();
73 resource_message_filter_->Send(reply_msg_);
74}
75
76bool NaClProcessHost::Launch(ResourceMessageFilter* resource_message_filter,
[email protected]c47ec402010-07-29 10:20:4977 int socket_count,
[email protected]fb1277e82009-11-21 20:32:3078 IPC::Message* reply_msg) {
[email protected]d8c7cbcc2009-10-02 19:00:3179#ifdef DISABLE_NACL
80 NOTIMPLEMENTED() << "Native Client disabled at build time";
81 return false;
82#else
[email protected]c47ec402010-07-29 10:20:4983 // Place an arbitrary limit on the number of sockets to limit
84 // exposure in case the renderer is compromised. We can increase
85 // this if necessary.
86 if (socket_count > 8) {
[email protected]d032f492009-09-29 00:33:4687 return false;
[email protected]c47ec402010-07-29 10:20:4988 }
89
90 // Rather than creating a socket pair in the renderer, and passing
91 // one side through the browser to sel_ldr, socket pairs are created
92 // in the browser and then passed to the renderer and sel_ldr.
93 //
94 // This is mainly for the benefit of Windows, where sockets cannot
95 // be passed in messages, but are copied via DuplicateHandle().
96 // This means the sandboxed renderer cannot send handles to the
97 // browser process.
98
99 for (int i = 0; i < socket_count; i++) {
100 nacl::Handle pair[2];
101 // Create a connected socket
102 if (nacl::SocketPair(pair) == -1)
103 return false;
104 sockets_for_renderer_.push_back(pair[0]);
105 sockets_for_sel_ldr_.push_back(pair[1]);
106 SetCloseOnExec(pair[0]);
107 SetCloseOnExec(pair[1]);
108 }
[email protected]d032f492009-09-29 00:33:46109
110 // Launch the process
[email protected]fb1277e82009-11-21 20:32:30111 if (!LaunchSelLdr()) {
[email protected]d032f492009-09-29 00:33:46112 return false;
113 }
114
[email protected]fb1277e82009-11-21 20:32:30115 resource_message_filter_ = resource_message_filter;
116 reply_msg_ = reply_msg;
[email protected]f08e47d2009-10-15 21:46:15117
[email protected]d032f492009-09-29 00:33:46118 return true;
[email protected]d8c7cbcc2009-10-02 19:00:31119#endif // DISABLE_NACL
[email protected]d032f492009-09-29 00:33:46120}
121
[email protected]fb1277e82009-11-21 20:32:30122bool NaClProcessHost::LaunchSelLdr() {
[email protected]d032f492009-09-29 00:33:46123 if (!CreateChannel())
124 return false;
125
126 // Build command line for nacl.
[email protected]7c4ea142010-01-26 05:15:42127 FilePath exe_path = GetChildPath(true);
[email protected]fb1277e82009-11-21 20:32:30128 if (exe_path.empty())
[email protected]d032f492009-09-29 00:33:46129 return false;
130
[email protected]fb1277e82009-11-21 20:32:30131 CommandLine* cmd_line = new CommandLine(exe_path);
[email protected]103607e2010-02-01 18:57:09132 nacl::CopyNaClCommandLineArguments(cmd_line);
[email protected]599e6642010-01-27 18:52:13133
[email protected]05076ba22010-07-30 05:59:57134 cmd_line->AppendSwitchASCII(switches::kProcessType,
135 switches::kNaClLoaderProcess);
[email protected]d032f492009-09-29 00:33:46136
[email protected]05076ba22010-07-30 05:59:57137 cmd_line->AppendSwitchASCII(switches::kProcessChannelID, channel_id());
[email protected]d032f492009-09-29 00:33:46138
[email protected]103607e2010-02-01 18:57:09139 // On Windows we might need to start the broker process to launch a new loader
[email protected]d032f492009-09-29 00:33:46140#if defined(OS_WIN)
[email protected]103607e2010-02-01 18:57:09141 if (running_on_wow64_) {
142 NaClBrokerService::GetInstance()->Init(resource_dispatcher_host_);
[email protected]2a4d7542010-03-17 02:06:33143 return NaClBrokerService::GetInstance()->LaunchLoader(this,
144 ASCIIToWide(channel_id()));
[email protected]4bdde602010-06-16 03:17:35145 } else {
[email protected]d27893f62010-07-03 05:47:42146 BrowserChildProcessHost::Launch(FilePath(), cmd_line);
[email protected]4bdde602010-06-16 03:17:35147 }
[email protected]103607e2010-02-01 18:57:09148#elif defined(OS_POSIX)
[email protected]d27893f62010-07-03 05:47:42149 BrowserChildProcessHost::Launch(true, // use_zygote
150 base::environment_vector(),
151 cmd_line);
[email protected]103607e2010-02-01 18:57:09152#endif
[email protected]d032f492009-09-29 00:33:46153
[email protected]fb1277e82009-11-21 20:32:30154 return true;
[email protected]d032f492009-09-29 00:33:46155}
156
[email protected]103607e2010-02-01 18:57:09157void NaClProcessHost::OnProcessLaunchedByBroker(base::ProcessHandle handle) {
158 set_handle(handle);
159 OnProcessLaunched();
160}
161
[email protected]cd69619b2010-05-05 02:41:38162bool NaClProcessHost::DidChildCrash() {
163 if (running_on_wow64_)
164 return base::DidProcessCrash(NULL, handle());
[email protected]d27893f62010-07-03 05:47:42165 return BrowserChildProcessHost::DidChildCrash();
[email protected]103607e2010-02-01 18:57:09166}
167
[email protected]16e70ae2010-03-08 21:41:28168void NaClProcessHost::OnChildDied() {
169#if defined(OS_WIN)
170 NaClBrokerService::GetInstance()->OnLoaderDied();
171#endif
[email protected]d27893f62010-07-03 05:47:42172 BrowserChildProcessHost::OnChildDied();
[email protected]16e70ae2010-03-08 21:41:28173}
174
[email protected]fb1277e82009-11-21 20:32:30175void NaClProcessHost::OnProcessLaunched() {
[email protected]c47ec402010-07-29 10:20:49176 std::vector<nacl::FileDescriptor> handles_for_renderer;
[email protected]fb1277e82009-11-21 20:32:30177 base::ProcessHandle nacl_process_handle;
[email protected]fb1277e82009-11-21 20:32:30178
[email protected]c47ec402010-07-29 10:20:49179 for (size_t i = 0; i < sockets_for_renderer_.size(); i++) {
180#if defined(OS_WIN)
181 // Copy the handle into the renderer process.
182 HANDLE handle_in_renderer;
183 DuplicateHandle(base::GetCurrentProcessHandle(),
184 reinterpret_cast<HANDLE>(sockets_for_renderer_[i]),
185 resource_message_filter_->handle(),
186 &handle_in_renderer,
187 GENERIC_READ | GENERIC_WRITE,
188 FALSE,
189 DUPLICATE_CLOSE_SOURCE);
190 handles_for_renderer.push_back(
191 reinterpret_cast<nacl::FileDescriptor>(handle_in_renderer));
192#else
193 // No need to dup the imc_handle - we don't pass it anywhere else so
194 // it cannot be closed.
195 nacl::FileDescriptor imc_handle;
196 imc_handle.fd = sockets_for_renderer_[i];
197 imc_handle.auto_close = true;
198 handles_for_renderer.push_back(imc_handle);
199#endif
200 }
201
202#if defined(OS_WIN)
203 // Copy the process handle into the renderer process.
[email protected]fb1277e82009-11-21 20:32:30204 DuplicateHandle(base::GetCurrentProcessHandle(),
205 handle(),
206 resource_message_filter_->handle(),
207 &nacl_process_handle,
208 PROCESS_DUP_HANDLE,
209 FALSE,
210 0);
[email protected]fb1277e82009-11-21 20:32:30211#else
[email protected]fb1277e82009-11-21 20:32:30212 // We use pid as process handle on Posix
213 nacl_process_handle = handle();
[email protected]fb1277e82009-11-21 20:32:30214#endif
215
216 // Get the pid of the NaCl process
217 base::ProcessId nacl_process_id = base::GetProcId(handle());
218
219 ViewHostMsg_LaunchNaCl::WriteReplyParams(
[email protected]c47ec402010-07-29 10:20:49220 reply_msg_, handles_for_renderer, nacl_process_handle, nacl_process_id);
[email protected]fb1277e82009-11-21 20:32:30221 resource_message_filter_->Send(reply_msg_);
222 resource_message_filter_ = NULL;
223 reply_msg_ = NULL;
[email protected]c47ec402010-07-29 10:20:49224 sockets_for_renderer_.clear();
[email protected]fb1277e82009-11-21 20:32:30225
226 SendStartMessage();
227}
228
229void NaClProcessHost::SendStartMessage() {
[email protected]c47ec402010-07-29 10:20:49230 std::vector<nacl::FileDescriptor> handles_for_sel_ldr;
231 for (size_t i = 0; i < sockets_for_sel_ldr_.size(); i++) {
[email protected]d032f492009-09-29 00:33:46232#if defined(OS_WIN)
[email protected]c47ec402010-07-29 10:20:49233 HANDLE channel;
234 if (!DuplicateHandle(GetCurrentProcess(),
235 reinterpret_cast<HANDLE>(sockets_for_sel_ldr_[i]),
236 handle(),
237 &channel,
238 GENERIC_READ | GENERIC_WRITE,
239 FALSE, DUPLICATE_CLOSE_SOURCE)) {
240 return;
241 }
242 handles_for_sel_ldr.push_back(
243 reinterpret_cast<nacl::FileDescriptor>(channel));
[email protected]d032f492009-09-29 00:33:46244#else
[email protected]c47ec402010-07-29 10:20:49245 nacl::FileDescriptor channel;
246 channel.fd = dup(sockets_for_sel_ldr_[i]);
247 channel.auto_close = true;
248 handles_for_sel_ldr.push_back(channel);
[email protected]d032f492009-09-29 00:33:46249#endif
[email protected]c47ec402010-07-29 10:20:49250 }
251
252 Send(new NaClProcessMsg_Start(handles_for_sel_ldr));
253 sockets_for_sel_ldr_.clear();
[email protected]d032f492009-09-29 00:33:46254}
255
256void NaClProcessHost::OnMessageReceived(const IPC::Message& msg) {
257 NOTREACHED() << "Invalid message with type = " << msg.type();
258}
259
260URLRequestContext* NaClProcessHost::GetRequestContext(
261 uint32 request_id,
262 const ViewHostMsg_Resource_Request& request_data) {
263 return NULL;
264}
[email protected]103607e2010-02-01 18:57:09265
266#if defined(OS_WIN)
267// TODO(gregoryd): invoke CheckIsWow64 only once, not for each NaClProcessHost
268typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL);
269void NaClProcessHost::CheckIsWow64() {
270 LPFN_ISWOW64PROCESS fnIsWow64Process;
271
272 fnIsWow64Process = (LPFN_ISWOW64PROCESS) GetProcAddress(
273 GetModuleHandle(TEXT("kernel32")),
274 "IsWow64Process");
275
276 if (fnIsWow64Process != NULL) {
277 BOOL bIsWow64 = FALSE;
278 if (fnIsWow64Process(GetCurrentProcess(),&bIsWow64)) {
279 if (bIsWow64) {
280 running_on_wow64_ = true;
281 }
282 }
283 }
284}
285#endif