Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1232)

Side by Side Diff: chrome/browser/nacl_host/nacl_process_host.cc

Issue 8397001: Open NaCl IRT file only once at startup (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 9 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "build/build_config.h" 5 #include "build/build_config.h"
6 6
7 #include "chrome/browser/nacl_host/nacl_process_host.h" 7 #include "chrome/browser/nacl_host/nacl_process_host.h"
8 8
9 #if defined(OS_POSIX) 9 #if defined(OS_POSIX)
10 #include <fcntl.h> 10 #include <fcntl.h>
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
45 } 45 }
46 #endif 46 #endif
47 47
48 } // namespace 48 } // namespace
49 49
50 struct NaClProcessHost::NaClInternal { 50 struct NaClProcessHost::NaClInternal {
51 std::vector<nacl::Handle> sockets_for_renderer; 51 std::vector<nacl::Handle> sockets_for_renderer;
52 std::vector<nacl::Handle> sockets_for_sel_ldr; 52 std::vector<nacl::Handle> sockets_for_sel_ldr;
53 }; 53 };
54 54
55 bool NaClProcessHost::RunningOnWOW64() {
56 #if defined(OS_WIN)
57 return (base::win::OSInfo::GetInstance()->wow64_status() ==
58 base::win::OSInfo::WOW64_ENABLED);
59 #else
60 return false;
61 #endif
62 }
63
55 NaClProcessHost::NaClProcessHost(const std::wstring& url) 64 NaClProcessHost::NaClProcessHost(const std::wstring& url)
56 : BrowserChildProcessHost(NACL_LOADER_PROCESS), 65 : BrowserChildProcessHost(NACL_LOADER_PROCESS),
57 reply_msg_(NULL), 66 reply_msg_(NULL),
58 internal_(new NaClInternal()), 67 internal_(new NaClInternal()),
59 running_on_wow64_(false),
60 ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)) { 68 ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)) {
61 set_name(WideToUTF16Hack(url)); 69 set_name(WideToUTF16Hack(url));
62 #if defined(OS_WIN)
63 running_on_wow64_ = (base::win::OSInfo::GetInstance()->wow64_status() ==
64 base::win::OSInfo::WOW64_ENABLED);
65 #endif
66 } 70 }
67 71
68 NaClProcessHost::~NaClProcessHost() { 72 NaClProcessHost::~NaClProcessHost() {
69 // nacl::Close() is not available at link time if DISABLE_NACL is 73 // nacl::Close() is not available at link time if DISABLE_NACL is
70 // defined, but we still compile a bunch of other code from this 74 // defined, but we still compile a bunch of other code from this
71 // file anyway. TODO(mseaborn): Make this less messy. 75 // file anyway. TODO(mseaborn): Make this less messy.
72 #ifndef DISABLE_NACL 76 #ifndef DISABLE_NACL
73 for (size_t i = 0; i < internal_->sockets_for_renderer.size(); i++) { 77 for (size_t i = 0; i < internal_->sockets_for_renderer.size(); i++) {
74 if (nacl::Close(internal_->sockets_for_renderer[i]) != 0) { 78 if (nacl::Close(internal_->sockets_for_renderer[i]) != 0) {
75 LOG(ERROR) << "nacl::Close() failed"; 79 LOG(ERROR) << "nacl::Close() failed";
(...skipping 22 matching lines...) Expand all
98 NOTIMPLEMENTED() << "Native Client disabled at build time"; 102 NOTIMPLEMENTED() << "Native Client disabled at build time";
99 return false; 103 return false;
100 #else 104 #else
101 // Place an arbitrary limit on the number of sockets to limit 105 // Place an arbitrary limit on the number of sockets to limit
102 // exposure in case the renderer is compromised. We can increase 106 // exposure in case the renderer is compromised. We can increase
103 // this if necessary. 107 // this if necessary.
104 if (socket_count > 8) { 108 if (socket_count > 8) {
105 return false; 109 return false;
106 } 110 }
107 111
112 if (irt_platform_file_ == base::kInvalidPlatformFileValue) {
113 LOG(ERROR) << "Cannot launch NaCl process after IRT file open failed";
114 return false;
115 }
116
108 // Rather than creating a socket pair in the renderer, and passing 117 // Rather than creating a socket pair in the renderer, and passing
109 // one side through the browser to sel_ldr, socket pairs are created 118 // one side through the browser to sel_ldr, socket pairs are created
110 // in the browser and then passed to the renderer and sel_ldr. 119 // in the browser and then passed to the renderer and sel_ldr.
111 // 120 //
112 // This is mainly for the benefit of Windows, where sockets cannot 121 // This is mainly for the benefit of Windows, where sockets cannot
113 // be passed in messages, but are copied via DuplicateHandle(). 122 // be passed in messages, but are copied via DuplicateHandle().
114 // This means the sandboxed renderer cannot send handles to the 123 // This means the sandboxed renderer cannot send handles to the
115 // browser process. 124 // browser process.
116 125
117 for (int i = 0; i < socket_count; i++) { 126 for (int i = 0; i < socket_count; i++) {
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
173 switches::kNaClLoaderProcess); 182 switches::kNaClLoaderProcess);
174 cmd_line->AppendSwitchASCII(switches::kProcessChannelID, channel_id()); 183 cmd_line->AppendSwitchASCII(switches::kProcessChannelID, channel_id());
175 if (logging::DialogsAreSuppressed()) 184 if (logging::DialogsAreSuppressed())
176 cmd_line->AppendSwitch(switches::kNoErrorDialogs); 185 cmd_line->AppendSwitch(switches::kNoErrorDialogs);
177 186
178 if (!nacl_loader_prefix.empty()) 187 if (!nacl_loader_prefix.empty())
179 cmd_line->PrependWrapper(nacl_loader_prefix); 188 cmd_line->PrependWrapper(nacl_loader_prefix);
180 189
181 // On Windows we might need to start the broker process to launch a new loader 190 // On Windows we might need to start the broker process to launch a new loader
182 #if defined(OS_WIN) 191 #if defined(OS_WIN)
183 if (running_on_wow64_) { 192 if (RunningOnWOW64()) {
184 return NaClBrokerService::GetInstance()->LaunchLoader( 193 return NaClBrokerService::GetInstance()->LaunchLoader(
185 this, ASCIIToWide(channel_id())); 194 this, ASCIIToWide(channel_id()));
186 } else { 195 } else {
187 BrowserChildProcessHost::Launch(FilePath(), cmd_line); 196 BrowserChildProcessHost::Launch(FilePath(), cmd_line);
188 } 197 }
189 #elif defined(OS_POSIX) 198 #elif defined(OS_POSIX)
190 BrowserChildProcessHost::Launch(nacl_loader_prefix.empty(), // use_zygote 199 BrowserChildProcessHost::Launch(nacl_loader_prefix.empty(), // use_zygote
191 base::environment_vector(), 200 base::environment_vector(),
192 cmd_line); 201 cmd_line);
193 #endif 202 #endif
194 203
195 return true; 204 return true;
196 } 205 }
197 206
198 void NaClProcessHost::OnProcessLaunchedByBroker(base::ProcessHandle handle) { 207 void NaClProcessHost::OnProcessLaunchedByBroker(base::ProcessHandle handle) {
199 set_handle(handle); 208 set_handle(handle);
200 OnProcessLaunched(); 209 OnProcessLaunched();
201 } 210 }
202 211
203 base::TerminationStatus NaClProcessHost::GetChildTerminationStatus( 212 base::TerminationStatus NaClProcessHost::GetChildTerminationStatus(
204 int* exit_code) { 213 int* exit_code) {
205 if (running_on_wow64_) 214 if (RunningOnWOW64())
206 return base::GetTerminationStatus(handle(), exit_code); 215 return base::GetTerminationStatus(handle(), exit_code);
207 return BrowserChildProcessHost::GetChildTerminationStatus(exit_code); 216 return BrowserChildProcessHost::GetChildTerminationStatus(exit_code);
208 } 217 }
209 218
210 void NaClProcessHost::OnChildDied() { 219 void NaClProcessHost::OnChildDied() {
211 int exit_code; 220 int exit_code;
212 GetChildTerminationStatus(&exit_code); 221 GetChildTerminationStatus(&exit_code);
213 std::string message = 222 std::string message =
214 base::StringPrintf("NaCl process exited with status %i (0x%x)", 223 base::StringPrintf("NaCl process exited with status %i (0x%x)",
215 exit_code, exit_code); 224 exit_code, exit_code);
216 if (exit_code == 0) { 225 if (exit_code == 0) {
217 LOG(INFO) << message; 226 LOG(INFO) << message;
218 } else { 227 } else {
219 LOG(ERROR) << message; 228 LOG(ERROR) << message;
220 } 229 }
221 230
222 #if defined(OS_WIN) 231 #if defined(OS_WIN)
223 NaClBrokerService::GetInstance()->OnLoaderDied(); 232 NaClBrokerService::GetInstance()->OnLoaderDied();
224 #endif 233 #endif
225 BrowserChildProcessHost::OnChildDied(); 234 BrowserChildProcessHost::OnChildDied();
226 } 235 }
227 236
228 FilePath::StringType NaClProcessHost::GetIrtLibraryFilename() { 237 base::PlatformFile NaClProcessHost::irt_platform_file_;
229 bool on_x86_64 = running_on_wow64_;
230 #if defined(__x86_64__)
231 on_x86_64 = true;
232 #endif
233 if (on_x86_64) {
234 return FILE_PATH_LITERAL("nacl_irt_x86_64.nexe");
235 } else {
236 return FILE_PATH_LITERAL("nacl_irt_x86_32.nexe");
237 }
238 }
239 238
240 void NaClProcessHost::OnProcessLaunched() { 239 void NaClProcessHost::OpenIrtLibraryFile() {
241 // TODO(mseaborn): Opening the IRT file every time a NaCl process is 240 irt_platform_file_ = base::kInvalidPlatformFileValue;
242 // launched probably does not work with auto-update on Linux. We 241
243 // might need to open the file on startup. If so, we would need to 242 FilePath irt_filepath;
244 // ensure that NaCl's ELF loader does not use lseek() on the shared 243
245 // IRT file descriptor, otherwise there would be a race condition.
246 FilePath irt_path;
247 // Allow the IRT library to be overridden via an environment 244 // Allow the IRT library to be overridden via an environment
248 // variable. This allows the NaCl/Chromium integration bot to 245 // variable. This allows the NaCl/Chromium integration bot to
249 // specify a newly-built IRT rather than using a prebuilt one 246 // specify a newly-built IRT rather than using a prebuilt one
250 // downloaded via Chromium's DEPS file. We use the same environment 247 // downloaded via Chromium's DEPS file. We use the same environment
251 // variable that the standalone NaCl PPAPI plugin accepts. 248 // variable that the standalone NaCl PPAPI plugin accepts.
252 const char* irt_path_var = getenv("NACL_IRT_LIBRARY"); 249 const char* irt_path_var = getenv("NACL_IRT_LIBRARY");
253 if (irt_path_var != NULL) { 250 if (irt_path_var != NULL) {
254 FilePath::StringType string(irt_path_var, 251 FilePath::StringType path_string(
255 irt_path_var + strlen(irt_path_var)); 252 irt_path_var, const_cast<const char*>(strchr(irt_path_var, '\0')));
256 irt_path = FilePath(string); 253 irt_filepath = FilePath(path_string);
257 } else { 254 } else {
258 FilePath plugin_dir; 255 FilePath plugin_dir;
259 if (!PathService::Get(chrome::DIR_INTERNAL_PLUGINS, &plugin_dir)) { 256 if (!PathService::Get(chrome::DIR_INTERNAL_PLUGINS, &plugin_dir)) {
260 LOG(ERROR) << "Failed to locate the plugins directory"; 257 LOG(ERROR) << "Failed to locate the plugins directory";
261 delete this;
262 return; 258 return;
263 } 259 }
264 irt_path = plugin_dir.Append(GetIrtLibraryFilename()); 260
261 bool on_x86_64 = RunningOnWOW64();
262 #if defined(__x86_64__)
263 on_x86_64 = true;
264 #endif
265 FilePath::StringType irt_name;
266 if (on_x86_64) {
267 irt_name = FILE_PATH_LITERAL("nacl_irt_x86_64.nexe");
268 } else {
269 irt_name = FILE_PATH_LITERAL("nacl_irt_x86_32.nexe");
270 }
271
272 irt_filepath = plugin_dir.Append(irt_name);
265 } 273 }
266 274
267 if (!base::FileUtilProxy::CreateOrOpen( 275 base::PlatformFileError error_code;
268 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE), 276 irt_platform_file_ = base::CreatePlatformFile(irt_filepath,
269 irt_path, 277 base::PLATFORM_FILE_OPEN |
270 base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ, 278 base::PLATFORM_FILE_READ,
271 base::Bind(&NaClProcessHost::OpenIrtFileDone, 279 NULL,
272 weak_factory_.GetWeakPtr()))) { 280 &error_code);
273 delete this; 281 if (error_code != base::PLATFORM_FILE_OK) {
282 LOG(ERROR) << "Failed to open NaCl IRT file \""
283 << irt_filepath.LossyDisplayName()
284 << "\": " << error_code;
274 } 285 }
275 } 286 }
276 287
277 void NaClProcessHost::OpenIrtFileDone(base::PlatformFileError error_code, 288 void NaClProcessHost::OnProcessLaunched() {
278 base::PassPlatformFile file, 289 SendStart(irt_platform_file_);
279 bool created) { 290 }
291
292 static bool SendHandleToSelLdr(
293 base::ProcessHandle processh,
294 nacl::Handle sourceh, bool close_source,
295 std::vector<nacl::FileDescriptor> *handles_for_sel_ldr) {
296 #if defined(OS_WIN)
297 HANDLE channel;
298 int flags = DUPLICATE_SAME_ACCESS;
299 if (close_source)
300 flags |= DUPLICATE_CLOSE_SOURCE;
301 if (!DuplicateHandle(GetCurrentProcess(),
302 reinterpret_cast<HANDLE>(sourceh),
303 processh,
304 &channel,
305 0, // Unused given DUPLICATE_SAME_ACCESS.
306 FALSE,
307 flags)) {
308 LOG(ERROR) << "DuplicateHandle() failed";
309 return false;
310 }
311 handles_for_sel_ldr->push_back(
312 reinterpret_cast<nacl::FileDescriptor>(channel));
313 #else
314 nacl::FileDescriptor channel;
315 channel.fd = sourceh;
316 channel.auto_close = close_source;
317 handles_for_sel_ldr->push_back(channel);
318 #endif
319 return true;
320 }
321
322 void NaClProcessHost::SendStart(base::PlatformFile irt_file) {
280 std::vector<nacl::FileDescriptor> handles_for_renderer; 323 std::vector<nacl::FileDescriptor> handles_for_renderer;
281 base::ProcessHandle nacl_process_handle; 324 base::ProcessHandle nacl_process_handle;
282 bool have_irt_file = false;
283 if (base::PLATFORM_FILE_OK == error_code) {
284 internal_->sockets_for_sel_ldr.push_back(file.ReleaseValue());
285 have_irt_file = true;
286 } else {
287 LOG(ERROR) << "Failed to open the NaCl IRT library file";
288 }
289 325
290 for (size_t i = 0; i < internal_->sockets_for_renderer.size(); i++) { 326 for (size_t i = 0; i < internal_->sockets_for_renderer.size(); i++) {
291 #if defined(OS_WIN) 327 #if defined(OS_WIN)
292 // Copy the handle into the renderer process. 328 // Copy the handle into the renderer process.
293 HANDLE handle_in_renderer; 329 HANDLE handle_in_renderer;
294 if (!DuplicateHandle(base::GetCurrentProcessHandle(), 330 if (!DuplicateHandle(base::GetCurrentProcessHandle(),
295 reinterpret_cast<HANDLE>( 331 reinterpret_cast<HANDLE>(
296 internal_->sockets_for_renderer[i]), 332 internal_->sockets_for_renderer[i]),
297 chrome_render_message_filter_->peer_handle(), 333 chrome_render_message_filter_->peer_handle(),
298 &handle_in_renderer, 334 &handle_in_renderer,
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
338 374
339 ChromeViewHostMsg_LaunchNaCl::WriteReplyParams( 375 ChromeViewHostMsg_LaunchNaCl::WriteReplyParams(
340 reply_msg_, handles_for_renderer, nacl_process_handle, nacl_process_id); 376 reply_msg_, handles_for_renderer, nacl_process_handle, nacl_process_id);
341 chrome_render_message_filter_->Send(reply_msg_); 377 chrome_render_message_filter_->Send(reply_msg_);
342 chrome_render_message_filter_ = NULL; 378 chrome_render_message_filter_ = NULL;
343 reply_msg_ = NULL; 379 reply_msg_ = NULL;
344 internal_->sockets_for_renderer.clear(); 380 internal_->sockets_for_renderer.clear();
345 381
346 std::vector<nacl::FileDescriptor> handles_for_sel_ldr; 382 std::vector<nacl::FileDescriptor> handles_for_sel_ldr;
347 for (size_t i = 0; i < internal_->sockets_for_sel_ldr.size(); i++) { 383 for (size_t i = 0; i < internal_->sockets_for_sel_ldr.size(); i++) {
348 #if defined(OS_WIN) 384 if (!SendHandleToSelLdr(handle(),
349 HANDLE channel; 385 internal_->sockets_for_sel_ldr[i], true,
350 if (!DuplicateHandle(GetCurrentProcess(), 386 &handles_for_sel_ldr)) {
351 reinterpret_cast<HANDLE>(
352 internal_->sockets_for_sel_ldr[i]),
353 handle(),
354 &channel,
355 0, // Unused given DUPLICATE_SAME_ACCESS.
356 FALSE,
357 DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) {
358 LOG(ERROR) << "DuplicateHandle() failed";
359 delete this; 387 delete this;
360 return; 388 return;
361 } 389 }
362 handles_for_sel_ldr.push_back( 390 }
363 reinterpret_cast<nacl::FileDescriptor>(channel)); 391
364 #else 392 // Send over the IRT file handle. We don't close our own copy!
365 nacl::FileDescriptor channel; 393 if (!SendHandleToSelLdr(handle(), irt_file, false, &handles_for_sel_ldr)) {
366 channel.fd = internal_->sockets_for_sel_ldr[i]; 394 delete this;
367 channel.auto_close = true; 395 return;
368 handles_for_sel_ldr.push_back(channel);
369 #endif
370 } 396 }
371 397
372 #if defined(OS_MACOSX) 398 #if defined(OS_MACOSX)
373 // For dynamic loading support, NaCl requires a file descriptor that 399 // For dynamic loading support, NaCl requires a file descriptor that
374 // was created in /tmp, since those created with shm_open() are not 400 // was created in /tmp, since those created with shm_open() are not
375 // mappable with PROT_EXEC. Rather than requiring an extra IPC 401 // mappable with PROT_EXEC. Rather than requiring an extra IPC
376 // round trip out of the sandbox, we create an FD here. 402 // round trip out of the sandbox, we create an FD here.
377 base::SharedMemory memory_buffer; 403 base::SharedMemory memory_buffer;
378 if (!memory_buffer.CreateAnonymous(/* size= */ 1)) { 404 if (!memory_buffer.CreateAnonymous(/* size= */ 1)) {
379 LOG(ERROR) << "Failed to allocate memory buffer"; 405 LOG(ERROR) << "Failed to allocate memory buffer";
380 delete this; 406 delete this;
381 return; 407 return;
382 } 408 }
383 nacl::FileDescriptor memory_fd; 409 nacl::FileDescriptor memory_fd;
384 memory_fd.fd = dup(memory_buffer.handle().fd); 410 memory_fd.fd = dup(memory_buffer.handle().fd);
385 if (memory_fd.fd < 0) { 411 if (memory_fd.fd < 0) {
386 LOG(ERROR) << "Failed to dup() a file descriptor"; 412 LOG(ERROR) << "Failed to dup() a file descriptor";
387 delete this; 413 delete this;
388 return; 414 return;
389 } 415 }
390 memory_fd.auto_close = true; 416 memory_fd.auto_close = true;
391 handles_for_sel_ldr.push_back(memory_fd); 417 handles_for_sel_ldr.push_back(memory_fd);
392 #endif 418 #endif
393 419
394 Send(new NaClProcessMsg_Start(handles_for_sel_ldr, have_irt_file)); 420 Send(new NaClProcessMsg_Start(handles_for_sel_ldr));
395 internal_->sockets_for_sel_ldr.clear(); 421 internal_->sockets_for_sel_ldr.clear();
396 } 422 }
397 423
398 bool NaClProcessHost::OnMessageReceived(const IPC::Message& msg) { 424 bool NaClProcessHost::OnMessageReceived(const IPC::Message& msg) {
399 NOTREACHED() << "Invalid message with type = " << msg.type(); 425 NOTREACHED() << "Invalid message with type = " << msg.type();
400 return false; 426 return false;
401 } 427 }
402 428
403 bool NaClProcessHost::CanShutdown() { 429 bool NaClProcessHost::CanShutdown() {
404 return true; 430 return true;
405 } 431 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698