nacl_listener.cc revision 5d1f7b1de12d16ceb2c938c56701a3e8bfa558f7
1a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#include "components/nacl/loader/nacl_listener.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <errno.h>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stdlib.h>
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#if defined(OS_POSIX)
11eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include <unistd.h>
12eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#endif
13eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/command_line.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/scoped_ptr.h"
179ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch#include "base/message_loop/message_loop.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/rand_util.h"
19a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch#include "components/nacl/common/nacl_messages.h"
20a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#include "components/nacl/loader/nacl_ipc_adapter.h"
21a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#include "components/nacl/loader/nacl_validation_db.h"
22a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#include "components/nacl/loader/nacl_validation_query.h"
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ipc/ipc_channel_handle.h"
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ipc/ipc_switches.h"
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ipc/ipc_sync_channel.h"
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ipc/ipc_sync_message_filter.h"
275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "native_client/src/public/chrome_main.h"
285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "native_client/src/public/nacl_app.h"
2990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "native_client/src/trusted/validator/nacl_file_info.h"
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_POSIX)
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/file_descriptor_posix.h"
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_LINUX)
365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "components/nacl/loader/nonsfi/nonsfi_main.h"
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/common/child_process_sandbox_support_linux.h"
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_WIN)
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <fcntl.h>
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <io.h>
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/common/sandbox_init.h"
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_MACOSX)
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// On Mac OS X, shm_open() works in the sandbox but does not give us
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// an FD that we can map as PROT_EXEC.  Rather than doing an IPC to
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// get an executable SHM region when CreateMemoryObject() is called,
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// we preallocate one on startup, since NaCl's sel_ldr only needs one
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// of them.  This saves a round trip.
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)base::subtle::Atomic32 g_shm_fd = -1;
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int CreateMemoryObject(size_t size, int executable) {
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (executable && size > 0) {
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int result_fd = base::subtle::NoBarrier_AtomicExchange(&g_shm_fd, -1);
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (result_fd != -1) {
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // ftruncate() is disallowed by the Mac OS X sandbox and
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // returns EPERM.  Luckily, we can get the same effect with
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // lseek() + write().
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (lseek(result_fd, size - 1, SEEK_SET) == -1) {
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        LOG(ERROR) << "lseek() failed: " << errno;
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return -1;
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (write(result_fd, "", 1) != 1) {
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        LOG(ERROR) << "write() failed: " << errno;
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return -1;
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return result_fd;
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Fall back to NaCl's default implementation.
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return -1;
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#elif defined(OS_LINUX)
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int CreateMemoryObject(size_t size, int executable) {
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return content::MakeSharedMemorySegmentViaIPC(size, executable);
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#elif defined(OS_WIN)
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)NaClListener* g_listener;
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// We wrap the function to convert the bool return value to an int.
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int BrokerDuplicateHandle(NaClHandle source_handle,
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          uint32_t process_id,
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          NaClHandle* target_handle,
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          uint32_t desired_access,
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          uint32_t options) {
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return content::BrokerDuplicateHandle(source_handle, process_id,
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                        target_handle, desired_access,
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                        options);
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int AttachDebugExceptionHandler(const void* info, size_t info_size) {
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string info_string(reinterpret_cast<const char*>(info), info_size);
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool result = false;
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!g_listener->Send(new NaClProcessMsg_AttachDebugExceptionHandler(
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           info_string, &result)))
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return result;
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Creates the PPAPI IPC channel between the NaCl IRT and the host
1135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// (browser/renderer) process, and starts to listen it on the thread where
1145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// the given message_loop_proxy runs.
1155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Also, creates and sets the corresponding NaClDesc to the given nap with
1165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// the FD #.
1175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void SetUpIPCAdapter(IPC::ChannelHandle* handle,
1185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                     scoped_refptr<base::MessageLoopProxy> message_loop_proxy,
1195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                     struct NaClApp* nap,
1205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                     int nacl_fd) {
1215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_refptr<NaClIPCAdapter> ipc_adapter(
1225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      new NaClIPCAdapter(*handle, message_loop_proxy.get()));
1235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ipc_adapter->ConnectChannel();
1245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#if defined(OS_POSIX)
1255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  handle->socket =
1265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::FileDescriptor(ipc_adapter->TakeClientFileDescriptor(), true);
1275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#endif
1285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Pass a NaClDesc to the untrusted side. This will hold a ref to the
1305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // NaClIPCAdapter.
1315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  NaClAppSetDesc(nap, nacl_fd, ipc_adapter->MakeNaClDesc());
1325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class BrowserValidationDBProxy : public NaClValidationDB {
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  explicit BrowserValidationDBProxy(NaClListener* listener)
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      : listener_(listener) {
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual bool QueryKnownToValidate(const std::string& signature) OVERRIDE {
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Initialize to false so that if the Send fails to write to the return
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // value we're safe.  For example if the message is (for some reason)
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // dispatched as an async message the return parameter will not be written.
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool result = false;
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!listener_->Send(new NaClProcessMsg_QueryKnownToValidate(signature,
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                                 &result))) {
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      LOG(ERROR) << "Failed to query NaCl validation cache.";
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      result = false;
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return result;
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual void SetKnownToValidate(const std::string& signature) OVERRIDE {
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Caching is optional: NaCl will still work correctly if the IPC fails.
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!listener_->Send(new NaClProcessMsg_SetKnownToValidate(signature))) {
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      LOG(ERROR) << "Failed to update NaCl validation cache.";
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  virtual bool ResolveFileToken(struct NaClFileToken* file_token,
16390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                int32* fd, std::string* path) OVERRIDE {
16490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    *fd = -1;
16590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    *path = "";
16690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if (file_token->lo == 0 && file_token->hi == 0) {
16790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      return false;
16890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    }
16990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    IPC::PlatformFileForTransit ipc_fd = IPC::InvalidPlatformFileForTransit();
17090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::FilePath ipc_path;
17190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if (!listener_->Send(new NaClProcessMsg_ResolveFileToken(file_token->lo,
17290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                                             file_token->hi,
17390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                                             &ipc_fd,
17490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                                             &ipc_path))) {
17590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      return false;
17690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    }
17790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if (ipc_fd == IPC::InvalidPlatformFileForTransit()) {
17890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      return false;
17990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    }
18090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    base::PlatformFile handle =
18190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        IPC::PlatformFileForTransitToPlatformFile(ipc_fd);
18290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#if defined(OS_WIN)
18390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // On Windows, valid handles are 32 bit unsigned integers so this is safe.
18490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    *fd = reinterpret_cast<uintptr_t>(handle);
18590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#else
18690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    *fd = handle;
18790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#endif
18890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // It doesn't matter if the path is invalid UTF8 as long as it's consistent
18990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // and unforgeable.
19090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    *path = ipc_path.AsUTF8Unsafe();
19190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    return true;
19290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
19390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The listener never dies, otherwise this might be a dangling reference.
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NaClListener* listener_;
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)NaClListener::NaClListener() : shutdown_event_(true, false),
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               io_thread_("NaCl_IOThread"),
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_LINUX)
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               prereserved_sandbox_size_(0),
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
205eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#if defined(OS_POSIX)
206eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                               number_of_cores_(-1),  // unknown/error
207eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#endif
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               main_loop_(NULL) {
209a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  io_thread_.StartWithOptions(
210a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      base::Thread::Options(base::MessageLoop::TYPE_IO, 0));
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_WIN)
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(g_listener == NULL);
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  g_listener = this;
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)NaClListener::~NaClListener() {
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NOTREACHED();
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  shutdown_event_.Signal();
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_WIN)
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  g_listener = NULL;
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool NaClListener::Send(IPC::Message* msg) {
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(main_loop_ != NULL);
227a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  if (base::MessageLoop::current() == main_loop_) {
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // This thread owns the channel.
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return channel_->Send(msg);
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // This thread does not own the channel.
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return filter_->Send(msg);
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void NaClListener::Listen() {
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string channel_name =
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          switches::kProcessChannelID);
2407d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  channel_.reset(new IPC::SyncChannel(
2417d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      this, io_thread_.message_loop_proxy().get(), &shutdown_event_));
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  filter_ = new IPC::SyncMessageFilter(&shutdown_event_);
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  channel_->AddFilter(filter_.get());
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  channel_->Init(channel_name, IPC::Channel::MODE_CLIENT, true);
245a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  main_loop_ = base::MessageLoop::current();
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  main_loop_->Run();
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool NaClListener::OnMessageReceived(const IPC::Message& msg) {
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool handled = true;
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  IPC_BEGIN_MESSAGE_MAP(NaClListener, msg)
2522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      IPC_MESSAGE_HANDLER(NaClProcessMsg_Start, OnStart)
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      IPC_MESSAGE_UNHANDLED(handled = false)
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  IPC_END_MESSAGE_MAP()
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return handled;
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void NaClListener::OnStart(const nacl::NaClStartParams& params) {
2595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#if defined(OS_LINUX) || defined(OS_MACOSX)
2605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  int urandom_fd = dup(base::GetUrandomFD());
2615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (urandom_fd < 0) {
2625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    LOG(ERROR) << "Failed to dup() the urandom FD";
2635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
2645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
2655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  NaClChromeMainSetUrandomFd(urandom_fd);
2665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#endif
2675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  NaClChromeMainInit();
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  struct NaClChromeMainArgs *args = NaClChromeMainArgsCreate();
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (args == NULL) {
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "NaClChromeMainArgsCreate() failed";
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  struct NaClApp *nap = NaClAppCreate();
2765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (nap == NULL) {
2775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    LOG(ERROR) << "NaClAppCreate() failed";
2785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
2795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
2805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (params.enable_ipc_proxy) {
2825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // Create the PPAPI IPC channels between the NaCl IRT and the hosts
2835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // (browser/renderer) processes. The IRT uses these channels to communicate
2845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // with the host and to initialize the IPC dispatchers.
2855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    IPC::ChannelHandle browser_handle =
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        IPC::Channel::GenerateVerifiedChannelID("nacl");
2875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    SetUpIPCAdapter(&browser_handle, io_thread_.message_loop_proxy(),
2885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                    nap, NACL_CHROME_DESC_BASE);
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    IPC::ChannelHandle renderer_handle =
2915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        IPC::Channel::GenerateVerifiedChannelID("nacl");
2925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    SetUpIPCAdapter(&renderer_handle, io_thread_.message_loop_proxy(),
2935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                    nap, NACL_CHROME_DESC_BASE + 1);
2945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (!Send(new NaClProcessHostMsg_PpapiChannelsCreated(
2965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            browser_handle, renderer_handle)))
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      LOG(ERROR) << "Failed to send IPC channel handle to NaClProcessHost.";
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<nacl::FileDescriptor> handles = params.handles;
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_LINUX) || defined(OS_MACOSX)
303eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  args->number_of_cores = number_of_cores_;
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  args->create_memory_object_func = CreateMemoryObject;
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# if defined(OS_MACOSX)
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK(handles.size() >= 1);
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  g_shm_fd = nacl::ToNativeHandle(handles[handles.size() - 1]);
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  handles.pop_back();
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# endif
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (params.uses_irt) {
3132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    CHECK(handles.size() >= 1);
3142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    NaClHandle irt_handle = nacl::ToNativeHandle(handles[handles.size() - 1]);
3152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    handles.pop_back();
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_WIN)
3182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    args->irt_fd = _open_osfhandle(reinterpret_cast<intptr_t>(irt_handle),
3192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                   _O_RDONLY | _O_BINARY);
3202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (args->irt_fd < 0) {
3212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      LOG(ERROR) << "_open_osfhandle() failed";
3222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return;
3232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else
3252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    args->irt_fd = irt_handle;
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
3272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else {
3282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Otherwise, the IRT handle is not even sent.
3292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    args->irt_fd = -1;
3302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (params.validation_cache_enabled) {
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // SHA256 block size.
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CHECK_EQ(params.validation_cache_key.length(), (size_t) 64);
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The cache structure is not freed and exists until the NaCl process exits.
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    args->validation_cache = CreateValidationCache(
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        new BrowserValidationDBProxy(this), params.validation_cache_key,
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        params.version);
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK(handles.size() == 1);
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  args->imc_bootstrap_handle = nacl::ToNativeHandle(handles[0]);
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  args->enable_exception_handling = params.enable_exception_handling;
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  args->enable_debug_stub = params.enable_debug_stub;
345c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  args->enable_dyncode_syscalls = params.enable_dyncode_syscalls;
346ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (!params.enable_dyncode_syscalls) {
347ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    // Bound the initial nexe's code segment size under PNaCl to
348ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    // reduce the chance of a code spraying attack succeeding (see
349ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    // https://code.google.com/p/nativeclient/issues/detail?id=3572).
350ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    // We assume that !params.enable_dyncode_syscalls is synonymous
351ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    // with PNaCl.  We can't apply this arbitrary limit outside of
352ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    // PNaCl because it might break existing NaCl apps, and this limit
353ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    // is only useful if the dyncode syscalls are disabled.
354ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    args->initial_nexe_max_code_bytes = 32 << 20;  // 32 MB
355ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  }
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_LINUX) || defined(OS_MACOSX)
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  args->debug_stub_server_bound_socket_fd = nacl::ToNativeHandle(
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      params.debug_stub_server_bound_socket);
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_WIN)
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  args->broker_duplicate_handle_func = BrokerDuplicateHandle;
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  args->attach_debug_exception_handler_func = AttachDebugExceptionHandler;
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_LINUX)
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  args->prereserved_sandbox_size = prereserved_sandbox_size_;
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
3675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#if defined(OS_LINUX)
3695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (params.enable_nonsfi_mode) {
3705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    nacl::nonsfi::MainStart(args->imc_bootstrap_handle);
3715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    NOTREACHED();
3725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
3735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
3745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#endif
3755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  NaClChromeMainStartApp(nap, args);
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NOTREACHED();
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
378