OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 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 "components/nacl/loader/nacl_listener.h" | 5 #include "components/nacl/loader/nacl_listener.h" |
6 | 6 |
7 #include <errno.h> | 7 #include <errno.h> |
8 #include <stdlib.h> | 8 #include <stdlib.h> |
9 | 9 |
10 #if defined(OS_POSIX) | 10 #if defined(OS_POSIX) |
(...skipping 245 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
256 bool NaClListener::OnMessageReceived(const IPC::Message& msg) { | 256 bool NaClListener::OnMessageReceived(const IPC::Message& msg) { |
257 bool handled = true; | 257 bool handled = true; |
258 IPC_BEGIN_MESSAGE_MAP(NaClListener, msg) | 258 IPC_BEGIN_MESSAGE_MAP(NaClListener, msg) |
259 IPC_MESSAGE_HANDLER(NaClProcessMsg_Start, OnStart) | 259 IPC_MESSAGE_HANDLER(NaClProcessMsg_Start, OnStart) |
260 IPC_MESSAGE_UNHANDLED(handled = false) | 260 IPC_MESSAGE_UNHANDLED(handled = false) |
261 IPC_END_MESSAGE_MAP() | 261 IPC_END_MESSAGE_MAP() |
262 return handled; | 262 return handled; |
263 } | 263 } |
264 | 264 |
265 void NaClListener::OnStart(const nacl::NaClStartParams& params) { | 265 void NaClListener::OnStart(const nacl::NaClStartParams& params) { |
266 #if !defined(OS_LINUX) | 266 if (uses_nonsfi_mode_) { |
267 CHECK(!uses_nonsfi_mode_) << "Non-SFI NaCl is only supported on Linux"; | 267 StartNonSfi(params); |
268 #endif | 268 return; |
| 269 } |
269 | 270 |
270 // Random number source initialization. | 271 #if defined(OS_LINUX) || defined(OS_MACOSX) |
271 #if defined(OS_LINUX) | 272 int urandom_fd = dup(base::GetUrandomFD()); |
272 if (uses_nonsfi_mode_) { | 273 if (urandom_fd < 0) { |
273 nacl::nonsfi::SetUrandomFd(base::GetUrandomFD()); | 274 LOG(ERROR) << "Failed to dup() the urandom FD"; |
| 275 return; |
274 } | 276 } |
275 #endif | 277 NaClChromeMainSetUrandomFd(urandom_fd); |
276 #if defined(OS_LINUX) || defined(OS_MACOSX) | |
277 if (!uses_nonsfi_mode_) { | |
278 int urandom_fd = dup(base::GetUrandomFD()); | |
279 if (urandom_fd < 0) { | |
280 LOG(ERROR) << "Failed to dup() the urandom FD"; | |
281 return; | |
282 } | |
283 NaClChromeMainSetUrandomFd(urandom_fd); | |
284 } | |
285 #endif | 278 #endif |
286 | 279 |
287 struct NaClApp* nap = NULL; | 280 struct NaClApp* nap = NULL; |
288 if (!uses_nonsfi_mode_) { | 281 NaClChromeMainInit(); |
289 NaClChromeMainInit(); | 282 nap = NaClAppCreate(); |
290 nap = NaClAppCreate(); | 283 if (nap == NULL) { |
291 if (nap == NULL) { | 284 LOG(ERROR) << "NaClAppCreate() failed"; |
292 LOG(ERROR) << "NaClAppCreate() failed"; | 285 return; |
293 return; | |
294 } | |
295 } | 286 } |
296 | 287 |
297 IPC::ChannelHandle browser_handle; | 288 IPC::ChannelHandle browser_handle; |
298 IPC::ChannelHandle ppapi_renderer_handle; | 289 IPC::ChannelHandle ppapi_renderer_handle; |
299 IPC::ChannelHandle manifest_service_handle; | |
300 | 290 |
301 if (params.enable_ipc_proxy) { | 291 if (params.enable_ipc_proxy) { |
302 browser_handle = IPC::Channel::GenerateVerifiedChannelID("nacl"); | 292 browser_handle = IPC::Channel::GenerateVerifiedChannelID("nacl"); |
303 ppapi_renderer_handle = IPC::Channel::GenerateVerifiedChannelID("nacl"); | 293 ppapi_renderer_handle = IPC::Channel::GenerateVerifiedChannelID("nacl"); |
304 | 294 |
305 #if defined(OS_LINUX) | 295 // Create the PPAPI IPC channels between the NaCl IRT and the host |
306 if (uses_nonsfi_mode_) { | 296 // (browser/renderer) processes. The IRT uses these channels to |
307 manifest_service_handle = | 297 // communicate with the host and to initialize the IPC dispatchers. |
308 IPC::Channel::GenerateVerifiedChannelID("nacl"); | 298 SetUpIPCAdapter(&browser_handle, io_thread_.message_loop_proxy(), |
309 | 299 nap, NACL_CHROME_DESC_BASE); |
310 // In non-SFI mode, we neither intercept nor rewrite the message using | 300 SetUpIPCAdapter(&ppapi_renderer_handle, io_thread_.message_loop_proxy(), |
311 // NaClIPCAdapter, and the channels are connected between the plugin and | 301 nap, NACL_CHROME_DESC_BASE + 1); |
312 // the hosts directly. So, the IPC::Channel instances will be created in | |
313 // the plugin side, because the IPC::Listener needs to live on the | |
314 // plugin's main thread. However, on initialization (i.e. before loading | |
315 // the plugin binary), the FD needs to be passed to the hosts. So, here | |
316 // we create raw FD pairs, and pass the client side FDs to the hosts, | |
317 // and the server side FDs to the plugin. | |
318 int browser_server_ppapi_fd; | |
319 int browser_client_ppapi_fd; | |
320 int renderer_server_ppapi_fd; | |
321 int renderer_client_ppapi_fd; | |
322 int manifest_service_server_fd; | |
323 int manifest_service_client_fd; | |
324 if (!IPC::SocketPair( | |
325 &browser_server_ppapi_fd, &browser_client_ppapi_fd) || | |
326 !IPC::SocketPair( | |
327 &renderer_server_ppapi_fd, &renderer_client_ppapi_fd) || | |
328 !IPC::SocketPair( | |
329 &manifest_service_server_fd, &manifest_service_client_fd)) { | |
330 LOG(ERROR) << "Failed to create sockets for IPC."; | |
331 return; | |
332 } | |
333 | |
334 // Set the plugin IPC channel FDs. | |
335 ppapi::SetIPCFileDescriptors(browser_server_ppapi_fd, | |
336 renderer_server_ppapi_fd, | |
337 manifest_service_server_fd); | |
338 ppapi::StartUpPlugin(); | |
339 | |
340 // Send back to the client side IPC channel FD to the host. | |
341 browser_handle.socket = | |
342 base::FileDescriptor(browser_client_ppapi_fd, true); | |
343 ppapi_renderer_handle.socket = | |
344 base::FileDescriptor(renderer_client_ppapi_fd, true); | |
345 manifest_service_handle.socket = | |
346 base::FileDescriptor(manifest_service_client_fd, true); | |
347 } else { | |
348 #endif | |
349 // Create the PPAPI IPC channels between the NaCl IRT and the host | |
350 // (browser/renderer) processes. The IRT uses these channels to | |
351 // communicate with the host and to initialize the IPC dispatchers. | |
352 SetUpIPCAdapter(&browser_handle, io_thread_.message_loop_proxy(), | |
353 nap, NACL_CHROME_DESC_BASE); | |
354 SetUpIPCAdapter(&ppapi_renderer_handle, io_thread_.message_loop_proxy(), | |
355 nap, NACL_CHROME_DESC_BASE + 1); | |
356 #if defined(OS_LINUX) | |
357 } | |
358 #endif | |
359 } | 302 } |
360 | 303 |
361 // The argument passed to GenerateVerifiedChannelID() here MUST be "nacl". | 304 IPC::ChannelHandle trusted_renderer_handle = CreateTrustedListener( |
362 // Using an alternate channel name prevents the pipe from being created on | 305 io_thread_.message_loop_proxy(), &shutdown_event_); |
363 // Windows when the sandbox is enabled. | |
364 IPC::ChannelHandle trusted_renderer_handle = | |
365 IPC::Channel::GenerateVerifiedChannelID("nacl"); | |
366 trusted_listener_ = new NaClTrustedListener( | |
367 trusted_renderer_handle, io_thread_.message_loop_proxy(), | |
368 &shutdown_event_); | |
369 #if defined(OS_POSIX) | |
370 trusted_renderer_handle.socket = base::FileDescriptor( | |
371 trusted_listener_->TakeClientFileDescriptor(), true); | |
372 #endif | |
373 if (!Send(new NaClProcessHostMsg_PpapiChannelsCreated( | 306 if (!Send(new NaClProcessHostMsg_PpapiChannelsCreated( |
374 browser_handle, ppapi_renderer_handle, | 307 browser_handle, ppapi_renderer_handle, |
375 trusted_renderer_handle, manifest_service_handle))) | 308 trusted_renderer_handle, IPC::ChannelHandle()))) |
376 LOG(ERROR) << "Failed to send IPC channel handle to NaClProcessHost."; | 309 LOG(ERROR) << "Failed to send IPC channel handle to NaClProcessHost."; |
377 | 310 |
378 std::vector<nacl::FileDescriptor> handles = params.handles; | 311 std::vector<nacl::FileDescriptor> handles = params.handles; |
379 | |
380 #if defined(OS_LINUX) | |
381 if (uses_nonsfi_mode_) { | |
382 // Ensure that the validation cache key (used as an extra input to the | |
383 // validation cache's hashing) isn't exposed accidentally. | |
384 CHECK(!params.validation_cache_enabled); | |
385 CHECK(params.validation_cache_key.size() == 0); | |
386 CHECK(params.version.size() == 0); | |
387 // Ensure that a debug stub FD isn't passed through accidentally. | |
388 CHECK(!params.enable_debug_stub); | |
389 CHECK(params.debug_stub_server_bound_socket.fd == -1); | |
390 | |
391 CHECK(!params.uses_irt); | |
392 CHECK(handles.size() == 1); | |
393 int imc_bootstrap_handle = nacl::ToNativeHandle(handles[0]); | |
394 nacl::nonsfi::MainStart(imc_bootstrap_handle); | |
395 return; | |
396 } | |
397 #endif | |
398 | |
399 struct NaClChromeMainArgs* args = NaClChromeMainArgsCreate(); | 312 struct NaClChromeMainArgs* args = NaClChromeMainArgsCreate(); |
400 if (args == NULL) { | 313 if (args == NULL) { |
401 LOG(ERROR) << "NaClChromeMainArgsCreate() failed"; | 314 LOG(ERROR) << "NaClChromeMainArgsCreate() failed"; |
402 return; | 315 return; |
403 } | 316 } |
404 | 317 |
405 #if defined(OS_LINUX) || defined(OS_MACOSX) | 318 #if defined(OS_LINUX) || defined(OS_MACOSX) |
406 args->number_of_cores = number_of_cores_; | 319 args->number_of_cores = number_of_cores_; |
407 args->create_memory_object_func = CreateMemoryObject; | 320 args->create_memory_object_func = CreateMemoryObject; |
408 # if defined(OS_MACOSX) | 321 # if defined(OS_MACOSX) |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
471 args->debug_stub_server_port_selected_handler_func = | 384 args->debug_stub_server_port_selected_handler_func = |
472 DebugStubPortSelectedHandler; | 385 DebugStubPortSelectedHandler; |
473 #endif | 386 #endif |
474 #if defined(OS_LINUX) | 387 #if defined(OS_LINUX) |
475 args->prereserved_sandbox_size = prereserved_sandbox_size_; | 388 args->prereserved_sandbox_size = prereserved_sandbox_size_; |
476 #endif | 389 #endif |
477 | 390 |
478 NaClChromeMainStartApp(nap, args); | 391 NaClChromeMainStartApp(nap, args); |
479 NOTREACHED(); | 392 NOTREACHED(); |
480 } | 393 } |
| 394 |
| 395 void NaClListener::StartNonSfi(const nacl::NaClStartParams& params) { |
| 396 #if !defined(OS_LINUX) |
| 397 NOTREACHED() << "Non-SFI NaCl is only supported on Linux"; |
| 398 #else |
| 399 // Random number source initialization. |
| 400 nacl::nonsfi::SetUrandomFd(base::GetUrandomFD()); |
| 401 |
| 402 IPC::ChannelHandle browser_handle; |
| 403 IPC::ChannelHandle ppapi_renderer_handle; |
| 404 IPC::ChannelHandle manifest_service_handle; |
| 405 |
| 406 if (params.enable_ipc_proxy) { |
| 407 browser_handle = IPC::Channel::GenerateVerifiedChannelID("nacl"); |
| 408 ppapi_renderer_handle = IPC::Channel::GenerateVerifiedChannelID("nacl"); |
| 409 manifest_service_handle = |
| 410 IPC::Channel::GenerateVerifiedChannelID("nacl"); |
| 411 |
| 412 // In non-SFI mode, we neither intercept nor rewrite the message using |
| 413 // NaClIPCAdapter, and the channels are connected between the plugin and |
| 414 // the hosts directly. So, the IPC::Channel instances will be created in |
| 415 // the plugin side, because the IPC::Listener needs to live on the |
| 416 // plugin's main thread. However, on initialization (i.e. before loading |
| 417 // the plugin binary), the FD needs to be passed to the hosts. So, here |
| 418 // we create raw FD pairs, and pass the client side FDs to the hosts, |
| 419 // and the server side FDs to the plugin. |
| 420 int browser_server_ppapi_fd; |
| 421 int browser_client_ppapi_fd; |
| 422 int renderer_server_ppapi_fd; |
| 423 int renderer_client_ppapi_fd; |
| 424 int manifest_service_server_fd; |
| 425 int manifest_service_client_fd; |
| 426 if (!IPC::SocketPair( |
| 427 &browser_server_ppapi_fd, &browser_client_ppapi_fd) || |
| 428 !IPC::SocketPair( |
| 429 &renderer_server_ppapi_fd, &renderer_client_ppapi_fd) || |
| 430 !IPC::SocketPair( |
| 431 &manifest_service_server_fd, &manifest_service_client_fd)) { |
| 432 LOG(ERROR) << "Failed to create sockets for IPC."; |
| 433 return; |
| 434 } |
| 435 |
| 436 // Set the plugin IPC channel FDs. |
| 437 ppapi::SetIPCFileDescriptors(browser_server_ppapi_fd, |
| 438 renderer_server_ppapi_fd, |
| 439 manifest_service_server_fd); |
| 440 ppapi::StartUpPlugin(); |
| 441 |
| 442 // Send back to the client side IPC channel FD to the host. |
| 443 browser_handle.socket = |
| 444 base::FileDescriptor(browser_client_ppapi_fd, true); |
| 445 ppapi_renderer_handle.socket = |
| 446 base::FileDescriptor(renderer_client_ppapi_fd, true); |
| 447 manifest_service_handle.socket = |
| 448 base::FileDescriptor(manifest_service_client_fd, true); |
| 449 } |
| 450 |
| 451 // TODO(teravest): Do we plan on using this renderer handle for nexe loading |
| 452 // for non-SFI? Right now, passing an empty channel handle instead causes |
| 453 // hangs, so we'll keep it. |
| 454 IPC::ChannelHandle trusted_renderer_handle = CreateTrustedListener( |
| 455 io_thread_.message_loop_proxy(), &shutdown_event_); |
| 456 if (!Send(new NaClProcessHostMsg_PpapiChannelsCreated( |
| 457 browser_handle, ppapi_renderer_handle, |
| 458 trusted_renderer_handle, manifest_service_handle))) |
| 459 LOG(ERROR) << "Failed to send IPC channel handle to NaClProcessHost."; |
| 460 |
| 461 // Ensure that the validation cache key (used as an extra input to the |
| 462 // validation cache's hashing) isn't exposed accidentally. |
| 463 CHECK(!params.validation_cache_enabled); |
| 464 CHECK(params.validation_cache_key.size() == 0); |
| 465 CHECK(params.version.size() == 0); |
| 466 // Ensure that a debug stub FD isn't passed through accidentally. |
| 467 CHECK(!params.enable_debug_stub); |
| 468 CHECK(params.debug_stub_server_bound_socket.fd == -1); |
| 469 |
| 470 CHECK(!params.uses_irt); |
| 471 CHECK(params.handles.size() == 1); |
| 472 int imc_bootstrap_handle = nacl::ToNativeHandle(params.handles[0]); |
| 473 nacl::nonsfi::MainStart(imc_bootstrap_handle); |
| 474 #endif // defined(OS_LINUX) |
| 475 } |
| 476 |
| 477 IPC::ChannelHandle NaClListener::CreateTrustedListener( |
| 478 base::MessageLoopProxy* message_loop_proxy, |
| 479 base::WaitableEvent* shutdown_event) { |
| 480 // The argument passed to GenerateVerifiedChannelID() here MUST be "nacl". |
| 481 // Using an alternate channel name prevents the pipe from being created on |
| 482 // Windows when the sandbox is enabled. |
| 483 IPC::ChannelHandle trusted_renderer_handle = |
| 484 IPC::Channel::GenerateVerifiedChannelID("nacl"); |
| 485 trusted_listener_ = new NaClTrustedListener( |
| 486 trusted_renderer_handle, io_thread_.message_loop_proxy(), |
| 487 &shutdown_event_); |
| 488 #if defined(OS_POSIX) |
| 489 trusted_renderer_handle.socket = base::FileDescriptor( |
| 490 trusted_listener_->TakeClientFileDescriptor(), true); |
| 491 #endif |
| 492 return trusted_renderer_handle; |
| 493 } |
OLD | NEW |