blob: 70891ecf553f9eba9b91f5cc6a5ca5186dfeedba [file] [log] [blame]
[email protected]1e67c2b2011-03-04 01:17:371// Copyright (c) 2011 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]9ec74462010-10-28 16:48:0514#include "base/metrics/nacl_histogram.h"
[email protected]338466a82011-05-03 04:27:4315#include "base/path_service.h"
[email protected]be1ce6a72010-08-03 14:35:2216#include "base/utf_string_conversions.h"
[email protected]1e67c2b2011-03-04 01:17:3717#include "base/win/windows_version.h"
[email protected]338466a82011-05-03 04:27:4318#include "chrome/common/chrome_paths.h"
[email protected]d032f492009-09-29 00:33:4619#include "chrome/common/chrome_switches.h"
20#include "chrome/common/logging_chrome.h"
[email protected]103607e2010-02-01 18:57:0921#include "chrome/common/nacl_cmd_line.h"
[email protected]d032f492009-09-29 00:33:4622#include "chrome/common/nacl_messages.h"
[email protected]fb1277e82009-11-21 20:32:3023#include "chrome/common/render_messages.h"
[email protected]92d56412011-03-24 20:53:5224#include "chrome/browser/renderer_host/chrome_render_message_filter.h"
[email protected]d032f492009-09-29 00:33:4625#include "ipc/ipc_switches.h"
[email protected]1d8a3d1f2011-02-19 07:11:5226#include "native_client/src/shared/imc/nacl_imc.h"
[email protected]d032f492009-09-29 00:33:4627
[email protected]d032f492009-09-29 00:33:4628#if defined(OS_POSIX)
29#include "ipc/ipc_channel_posix.h"
[email protected]4bdde602010-06-16 03:17:3530#elif defined(OS_WIN)
31#include "chrome/browser/nacl_host/nacl_broker_service_win.h"
[email protected]d032f492009-09-29 00:33:4632#endif
33
[email protected]c47ec402010-07-29 10:20:4934namespace {
35
[email protected]ba077002010-09-27 15:22:3036#if !defined(DISABLE_NACL)
[email protected]c47ec402010-07-29 10:20:4937void SetCloseOnExec(nacl::Handle fd) {
38#if defined(OS_POSIX)
39 int flags = fcntl(fd, F_GETFD);
40 CHECK(flags != -1);
41 int rc = fcntl(fd, F_SETFD, flags | FD_CLOEXEC);
42 CHECK(rc == 0);
43#endif
44}
[email protected]ba077002010-09-27 15:22:3045#endif
[email protected]c47ec402010-07-29 10:20:4946
47} // namespace
48
[email protected]1d8a3d1f2011-02-19 07:11:5249struct NaClProcessHost::NaClInternal {
50 std::vector<nacl::Handle> sockets_for_renderer;
51 std::vector<nacl::Handle> sockets_for_sel_ldr;
52};
53
[email protected]1dbaaa702011-04-06 17:43:4254NaClProcessHost::NaClProcessHost(const std::wstring& url)
[email protected]5afcf6882011-04-08 20:11:1555 : BrowserChildProcessHost(NACL_LOADER_PROCESS),
[email protected]fb1277e82009-11-21 20:32:3056 reply_msg_(NULL),
[email protected]1d8a3d1f2011-02-19 07:11:5257 internal_(new NaClInternal()),
[email protected]338466a82011-05-03 04:27:4358 running_on_wow64_(false),
59 ALLOW_THIS_IN_INITIALIZER_LIST(callback_factory_(this)) {
[email protected]f08e47d2009-10-15 21:46:1560 set_name(url);
[email protected]103607e2010-02-01 18:57:0961#if defined(OS_WIN)
[email protected]f481221192011-04-07 22:15:3462 running_on_wow64_ = (base::win::OSInfo::GetInstance()->wow64_status() ==
63 base::win::OSInfo::WOW64_ENABLED);
[email protected]103607e2010-02-01 18:57:0964#endif
[email protected]d032f492009-09-29 00:33:4665}
66
[email protected]fb1277e82009-11-21 20:32:3067NaClProcessHost::~NaClProcessHost() {
[email protected]990b29e2010-07-29 12:53:4768 // nacl::Close() is not available at link time if DISABLE_NACL is
69 // defined, but we still compile a bunch of other code from this
70 // file anyway. TODO(mseaborn): Make this less messy.
71#ifndef DISABLE_NACL
[email protected]1d8a3d1f2011-02-19 07:11:5272 for (size_t i = 0; i < internal_->sockets_for_renderer.size(); i++) {
[email protected]909c2402011-05-09 11:39:0473 if (nacl::Close(internal_->sockets_for_renderer[i]) != 0) {
74 LOG(ERROR) << "nacl::Close() failed";
75 }
[email protected]c47ec402010-07-29 10:20:4976 }
[email protected]1d8a3d1f2011-02-19 07:11:5277 for (size_t i = 0; i < internal_->sockets_for_sel_ldr.size(); i++) {
[email protected]909c2402011-05-09 11:39:0478 if (nacl::Close(internal_->sockets_for_sel_ldr[i]) != 0) {
79 LOG(ERROR) << "nacl::Close() failed";
80 }
[email protected]c47ec402010-07-29 10:20:4981 }
[email protected]990b29e2010-07-29 12:53:4782#endif
[email protected]c47ec402010-07-29 10:20:4983
[email protected]909c2402011-05-09 11:39:0484 if (reply_msg_) {
85 // The process failed to launch for some reason.
86 // Don't keep the renderer hanging.
87 reply_msg_->set_reply_error();
88 chrome_render_message_filter_->Send(reply_msg_);
89 }
[email protected]fb1277e82009-11-21 20:32:3090}
91
[email protected]92d56412011-03-24 20:53:5292bool NaClProcessHost::Launch(
93 ChromeRenderMessageFilter* chrome_render_message_filter,
94 int socket_count,
95 IPC::Message* reply_msg) {
[email protected]d8c7cbcc2009-10-02 19:00:3196#ifdef DISABLE_NACL
97 NOTIMPLEMENTED() << "Native Client disabled at build time";
98 return false;
99#else
[email protected]c47ec402010-07-29 10:20:49100 // Place an arbitrary limit on the number of sockets to limit
101 // exposure in case the renderer is compromised. We can increase
102 // this if necessary.
103 if (socket_count > 8) {
[email protected]d032f492009-09-29 00:33:46104 return false;
[email protected]c47ec402010-07-29 10:20:49105 }
106
107 // Rather than creating a socket pair in the renderer, and passing
108 // one side through the browser to sel_ldr, socket pairs are created
109 // in the browser and then passed to the renderer and sel_ldr.
110 //
111 // This is mainly for the benefit of Windows, where sockets cannot
112 // be passed in messages, but are copied via DuplicateHandle().
113 // This means the sandboxed renderer cannot send handles to the
114 // browser process.
115
116 for (int i = 0; i < socket_count; i++) {
117 nacl::Handle pair[2];
118 // Create a connected socket
119 if (nacl::SocketPair(pair) == -1)
120 return false;
[email protected]1d8a3d1f2011-02-19 07:11:52121 internal_->sockets_for_renderer.push_back(pair[0]);
122 internal_->sockets_for_sel_ldr.push_back(pair[1]);
[email protected]c47ec402010-07-29 10:20:49123 SetCloseOnExec(pair[0]);
124 SetCloseOnExec(pair[1]);
125 }
[email protected]d032f492009-09-29 00:33:46126
127 // Launch the process
[email protected]fb1277e82009-11-21 20:32:30128 if (!LaunchSelLdr()) {
[email protected]d032f492009-09-29 00:33:46129 return false;
130 }
[email protected]9ec74462010-10-28 16:48:05131 UmaNaclHistogramEnumeration(NACL_STARTED);
[email protected]92d56412011-03-24 20:53:52132 chrome_render_message_filter_ = chrome_render_message_filter;
[email protected]fb1277e82009-11-21 20:32:30133 reply_msg_ = reply_msg;
[email protected]f08e47d2009-10-15 21:46:15134
[email protected]d032f492009-09-29 00:33:46135 return true;
[email protected]d8c7cbcc2009-10-02 19:00:31136#endif // DISABLE_NACL
[email protected]d032f492009-09-29 00:33:46137}
138
[email protected]fb1277e82009-11-21 20:32:30139bool NaClProcessHost::LaunchSelLdr() {
[email protected]d032f492009-09-29 00:33:46140 if (!CreateChannel())
141 return false;
142
[email protected]e3fc75a2011-05-05 08:20:42143 CommandLine::StringType nacl_loader_prefix;
144#if defined(OS_POSIX)
145 nacl_loader_prefix = CommandLine::ForCurrentProcess()->GetSwitchValueNative(
146 switches::kNaClLoaderCmdPrefix);
147#endif // defined(OS_POSIX)
148
[email protected]d032f492009-09-29 00:33:46149 // Build command line for nacl.
[email protected]e3fc75a2011-05-05 08:20:42150 FilePath exe_path = GetChildPath(nacl_loader_prefix.empty());
[email protected]fb1277e82009-11-21 20:32:30151 if (exe_path.empty())
[email protected]d032f492009-09-29 00:33:46152 return false;
153
[email protected]fb1277e82009-11-21 20:32:30154 CommandLine* cmd_line = new CommandLine(exe_path);
[email protected]103607e2010-02-01 18:57:09155 nacl::CopyNaClCommandLineArguments(cmd_line);
[email protected]599e6642010-01-27 18:52:13156
[email protected]05076ba22010-07-30 05:59:57157 cmd_line->AppendSwitchASCII(switches::kProcessType,
158 switches::kNaClLoaderProcess);
[email protected]d032f492009-09-29 00:33:46159
[email protected]05076ba22010-07-30 05:59:57160 cmd_line->AppendSwitchASCII(switches::kProcessChannelID, channel_id());
[email protected]d032f492009-09-29 00:33:46161
[email protected]e3fc75a2011-05-05 08:20:42162 if (!nacl_loader_prefix.empty())
163 cmd_line->PrependWrapper(nacl_loader_prefix);
164
[email protected]103607e2010-02-01 18:57:09165 // On Windows we might need to start the broker process to launch a new loader
[email protected]d032f492009-09-29 00:33:46166#if defined(OS_WIN)
[email protected]103607e2010-02-01 18:57:09167 if (running_on_wow64_) {
[email protected]1dbaaa702011-04-06 17:43:42168 return NaClBrokerService::GetInstance()->LaunchLoader(
169 this, ASCIIToWide(channel_id()));
[email protected]4bdde602010-06-16 03:17:35170 } else {
[email protected]d27893f62010-07-03 05:47:42171 BrowserChildProcessHost::Launch(FilePath(), cmd_line);
[email protected]4bdde602010-06-16 03:17:35172 }
[email protected]103607e2010-02-01 18:57:09173#elif defined(OS_POSIX)
[email protected]e3fc75a2011-05-05 08:20:42174 BrowserChildProcessHost::Launch(nacl_loader_prefix.empty(), // use_zygote
[email protected]d27893f62010-07-03 05:47:42175 base::environment_vector(),
176 cmd_line);
[email protected]103607e2010-02-01 18:57:09177#endif
[email protected]d032f492009-09-29 00:33:46178
[email protected]fb1277e82009-11-21 20:32:30179 return true;
[email protected]d032f492009-09-29 00:33:46180}
181
[email protected]103607e2010-02-01 18:57:09182void NaClProcessHost::OnProcessLaunchedByBroker(base::ProcessHandle handle) {
183 set_handle(handle);
184 OnProcessLaunched();
185}
186
[email protected]443b80e2010-12-14 00:42:23187base::TerminationStatus NaClProcessHost::GetChildTerminationStatus(
188 int* exit_code) {
[email protected]cd69619b2010-05-05 02:41:38189 if (running_on_wow64_)
[email protected]443b80e2010-12-14 00:42:23190 return base::GetTerminationStatus(handle(), exit_code);
191 return BrowserChildProcessHost::GetChildTerminationStatus(exit_code);
[email protected]103607e2010-02-01 18:57:09192}
193
[email protected]16e70ae2010-03-08 21:41:28194void NaClProcessHost::OnChildDied() {
195#if defined(OS_WIN)
196 NaClBrokerService::GetInstance()->OnLoaderDied();
197#endif
[email protected]d27893f62010-07-03 05:47:42198 BrowserChildProcessHost::OnChildDied();
[email protected]16e70ae2010-03-08 21:41:28199}
200
[email protected]338466a82011-05-03 04:27:43201FilePath::StringType NaClProcessHost::GetIrtLibraryFilename() {
202 bool on_x86_64 = running_on_wow64_;
203#if defined(__x86_64__)
204 on_x86_64 = true;
205#endif
206 if (on_x86_64) {
207 return FILE_PATH_LITERAL("nacl_irt_x86_64.nexe");
208 } else {
209 return FILE_PATH_LITERAL("nacl_irt_x86_32.nexe");
210 }
211}
212
[email protected]fb1277e82009-11-21 20:32:30213void NaClProcessHost::OnProcessLaunched() {
[email protected]338466a82011-05-03 04:27:43214 // TODO(mseaborn): Opening the IRT file every time a NaCl process is
215 // launched probably does not work with auto-update on Linux. We
216 // might need to open the file on startup. If so, we would need to
217 // ensure that NaCl's ELF loader does not use lseek() on the shared
218 // IRT file descriptor, otherwise there would be a race condition.
219 FilePath plugin_dir;
220 if (!PathService::Get(chrome::DIR_INTERNAL_PLUGINS, &plugin_dir)) {
221 LOG(ERROR) << "Failed to locate the plugins directory";
222 delete this;
223 return;
224 }
225 FilePath irt_path = plugin_dir.Append(GetIrtLibraryFilename());
226 base::FileUtilProxy::CreateOrOpenCallback* callback =
227 callback_factory_.NewCallback(&NaClProcessHost::OpenIrtFileDone);
228 if (!base::FileUtilProxy::CreateOrOpen(
229 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE),
230 irt_path,
231 base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ,
232 callback)) {
233 delete callback;
234 delete this;
235 }
236}
237
238void NaClProcessHost::OpenIrtFileDone(base::PlatformFileError error_code,
239 base::PassPlatformFile file,
240 bool created) {
[email protected]c47ec402010-07-29 10:20:49241 std::vector<nacl::FileDescriptor> handles_for_renderer;
[email protected]fb1277e82009-11-21 20:32:30242 base::ProcessHandle nacl_process_handle;
[email protected]338466a82011-05-03 04:27:43243 bool have_irt_file = false;
244 if (base::PLATFORM_FILE_OK == error_code) {
245 internal_->sockets_for_sel_ldr.push_back(file.ReleaseValue());
246 have_irt_file = true;
247 } else {
248 LOG(ERROR) << "Failed to open the NaCl IRT library file";
249 }
[email protected]fb1277e82009-11-21 20:32:30250
[email protected]1d8a3d1f2011-02-19 07:11:52251 for (size_t i = 0; i < internal_->sockets_for_renderer.size(); i++) {
[email protected]c47ec402010-07-29 10:20:49252#if defined(OS_WIN)
253 // Copy the handle into the renderer process.
254 HANDLE handle_in_renderer;
[email protected]909c2402011-05-09 11:39:04255 if (!DuplicateHandle(base::GetCurrentProcessHandle(),
256 reinterpret_cast<HANDLE>(
257 internal_->sockets_for_renderer[i]),
258 chrome_render_message_filter_->peer_handle(),
259 &handle_in_renderer,
260 0, // Unused given DUPLICATE_SAME_ACCESS.
261 FALSE,
262 DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) {
263 LOG(ERROR) << "DuplicateHandle() failed";
264 delete this;
265 return;
266 }
[email protected]c47ec402010-07-29 10:20:49267 handles_for_renderer.push_back(
268 reinterpret_cast<nacl::FileDescriptor>(handle_in_renderer));
269#else
270 // No need to dup the imc_handle - we don't pass it anywhere else so
271 // it cannot be closed.
272 nacl::FileDescriptor imc_handle;
[email protected]1d8a3d1f2011-02-19 07:11:52273 imc_handle.fd = internal_->sockets_for_renderer[i];
[email protected]c47ec402010-07-29 10:20:49274 imc_handle.auto_close = true;
275 handles_for_renderer.push_back(imc_handle);
276#endif
277 }
278
279#if defined(OS_WIN)
280 // Copy the process handle into the renderer process.
[email protected]909c2402011-05-09 11:39:04281 if (!DuplicateHandle(base::GetCurrentProcessHandle(),
282 handle(),
283 chrome_render_message_filter_->peer_handle(),
284 &nacl_process_handle,
285 PROCESS_DUP_HANDLE,
286 FALSE,
287 0)) {
288 LOG(ERROR) << "DuplicateHandle() failed";
289 delete this;
290 return;
291 }
[email protected]fb1277e82009-11-21 20:32:30292#else
[email protected]fb1277e82009-11-21 20:32:30293 // We use pid as process handle on Posix
294 nacl_process_handle = handle();
[email protected]fb1277e82009-11-21 20:32:30295#endif
296
297 // Get the pid of the NaCl process
298 base::ProcessId nacl_process_id = base::GetProcId(handle());
299
300 ViewHostMsg_LaunchNaCl::WriteReplyParams(
[email protected]c47ec402010-07-29 10:20:49301 reply_msg_, handles_for_renderer, nacl_process_handle, nacl_process_id);
[email protected]92d56412011-03-24 20:53:52302 chrome_render_message_filter_->Send(reply_msg_);
303 chrome_render_message_filter_ = NULL;
[email protected]fb1277e82009-11-21 20:32:30304 reply_msg_ = NULL;
[email protected]1d8a3d1f2011-02-19 07:11:52305 internal_->sockets_for_renderer.clear();
[email protected]fb1277e82009-11-21 20:32:30306
[email protected]c47ec402010-07-29 10:20:49307 std::vector<nacl::FileDescriptor> handles_for_sel_ldr;
[email protected]1d8a3d1f2011-02-19 07:11:52308 for (size_t i = 0; i < internal_->sockets_for_sel_ldr.size(); i++) {
[email protected]d032f492009-09-29 00:33:46309#if defined(OS_WIN)
[email protected]c47ec402010-07-29 10:20:49310 HANDLE channel;
311 if (!DuplicateHandle(GetCurrentProcess(),
[email protected]1d8a3d1f2011-02-19 07:11:52312 reinterpret_cast<HANDLE>(
313 internal_->sockets_for_sel_ldr[i]),
[email protected]c47ec402010-07-29 10:20:49314 handle(),
315 &channel,
[email protected]338466a82011-05-03 04:27:43316 0, // Unused given DUPLICATE_SAME_ACCESS.
317 FALSE,
318 DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) {
[email protected]909c2402011-05-09 11:39:04319 LOG(ERROR) << "DuplicateHandle() failed";
320 delete this;
[email protected]c47ec402010-07-29 10:20:49321 return;
322 }
323 handles_for_sel_ldr.push_back(
324 reinterpret_cast<nacl::FileDescriptor>(channel));
[email protected]d032f492009-09-29 00:33:46325#else
[email protected]c47ec402010-07-29 10:20:49326 nacl::FileDescriptor channel;
[email protected]1d8a3d1f2011-02-19 07:11:52327 channel.fd = dup(internal_->sockets_for_sel_ldr[i]);
[email protected]2c68bf032010-11-11 23:16:30328 if (channel.fd < 0) {
329 LOG(ERROR) << "Failed to dup() a file descriptor";
[email protected]909c2402011-05-09 11:39:04330 delete this;
[email protected]2c68bf032010-11-11 23:16:30331 return;
332 }
[email protected]c47ec402010-07-29 10:20:49333 channel.auto_close = true;
334 handles_for_sel_ldr.push_back(channel);
[email protected]d032f492009-09-29 00:33:46335#endif
[email protected]c47ec402010-07-29 10:20:49336 }
337
[email protected]2c68bf032010-11-11 23:16:30338#if defined(OS_MACOSX)
339 // For dynamic loading support, NaCl requires a file descriptor that
340 // was created in /tmp, since those created with shm_open() are not
341 // mappable with PROT_EXEC. Rather than requiring an extra IPC
342 // round trip out of the sandbox, we create an FD here.
343 base::SharedMemory memory_buffer;
344 if (!memory_buffer.CreateAnonymous(/* size= */ 1)) {
345 LOG(ERROR) << "Failed to allocate memory buffer";
[email protected]909c2402011-05-09 11:39:04346 delete this;
[email protected]2c68bf032010-11-11 23:16:30347 return;
348 }
349 nacl::FileDescriptor memory_fd;
350 memory_fd.fd = dup(memory_buffer.handle().fd);
351 if (memory_fd.fd < 0) {
352 LOG(ERROR) << "Failed to dup() a file descriptor";
[email protected]909c2402011-05-09 11:39:04353 delete this;
[email protected]2c68bf032010-11-11 23:16:30354 return;
355 }
356 memory_fd.auto_close = true;
357 handles_for_sel_ldr.push_back(memory_fd);
358#endif
359
[email protected]338466a82011-05-03 04:27:43360 Send(new NaClProcessMsg_Start(handles_for_sel_ldr, have_irt_file));
[email protected]1d8a3d1f2011-02-19 07:11:52361 internal_->sockets_for_sel_ldr.clear();
[email protected]d032f492009-09-29 00:33:46362}
363
[email protected]a95986a82010-12-24 06:19:28364bool NaClProcessHost::OnMessageReceived(const IPC::Message& msg) {
[email protected]d032f492009-09-29 00:33:46365 NOTREACHED() << "Invalid message with type = " << msg.type();
[email protected]a95986a82010-12-24 06:19:28366 return false;
[email protected]d032f492009-09-29 00:33:46367}
368
[email protected]e4be2dd2010-12-14 00:44:39369bool NaClProcessHost::CanShutdown() {
370 return true;
371}