blob: e0041901c85ee34dbb3f4a0c8510b3d72f62877b [file] [log] [blame]
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/nacl/loader/nonsfi/nonsfi_listener.h"
#include <memory>
#include <utility>
#include "base/command_line.h"
#include "base/file_descriptor_posix.h"
#include "base/logging.h"
#include "base/message_loop/message_pump_type.h"
#include "base/rand_util.h"
#include "base/run_loop.h"
#include "build/build_config.h"
#include "components/nacl/common/nacl.mojom.h"
#include "components/nacl/common/nacl_messages.h"
#include "components/nacl/common/nacl_service.h"
#include "components/nacl/common/nacl_types.h"
#include "components/nacl/loader/nacl_trusted_listener.h"
#include "components/nacl/loader/nonsfi/nonsfi_main.h"
#include "content/public/common/content_descriptors.h"
#include "ipc/ipc_channel.h"
#include "ipc/ipc_channel_handle.h"
#include "ipc/ipc_sync_channel.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "native_client/src/public/nonsfi/irt_random.h"
#include "ppapi/nacl_irt/irt_manifest.h"
#include "ppapi/nacl_irt/plugin_startup.h"
#if !defined(OS_NACL_NONSFI)
#error "This file must be built for nacl_helper_nonsfi."
#endif
namespace nacl {
namespace nonsfi {
NonSfiListener::NonSfiListener()
: io_thread_("NaCl_IOThread"),
shutdown_event_(base::WaitableEvent::ResetPolicy::MANUAL,
base::WaitableEvent::InitialState::NOT_SIGNALED),
key_fd_map_(new std::map<std::string, int>) {
io_thread_.StartWithOptions(
base::Thread::Options(base::MessagePumpType::IO, 0));
}
NonSfiListener::~NonSfiListener() {
}
void NonSfiListener::Listen() {
mojo::ScopedMessagePipeHandle channel_handle;
auto service = CreateNaClService(io_thread_.task_runner(), &channel_handle);
channel_ = IPC::SyncChannel::Create(
channel_handle.release(), IPC::Channel::MODE_CLIENT,
this, // As a Listener.
io_thread_.task_runner(), base::ThreadTaskRunnerHandle::Get(),
true, // Create pipe now.
&shutdown_event_);
base::RunLoop().Run();
}
bool NonSfiListener::OnMessageReceived(const IPC::Message& msg) {
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(NonSfiListener, msg)
IPC_MESSAGE_HANDLER(NaClProcessMsg_AddPrefetchedResource,
OnAddPrefetchedResource)
IPC_MESSAGE_HANDLER(NaClProcessMsg_Start, OnStart)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
return handled;
}
void NonSfiListener::OnAddPrefetchedResource(
const nacl::NaClResourcePrefetchResult& prefetched_resource_file) {
CHECK(prefetched_resource_file.file_path_metadata.empty());
bool result = key_fd_map_->insert(std::make_pair(
prefetched_resource_file.file_key,
IPC::PlatformFileForTransitToPlatformFile(
prefetched_resource_file.file))).second;
if (!result) {
LOG(FATAL) << "Duplicated open_resource key: "
<< prefetched_resource_file.file_key;
}
}
void NonSfiListener::OnStart(const nacl::NaClStartParams& params) {
// Random number source initialization.
nonsfi_set_urandom_fd(base::GetUrandomFD());
// In Non-SFI mode, we neither intercept nor rewrite the message using
// NaClIPCAdapter, and the channels are connected between the plugin and
// the hosts directly. So, the IPC::Channel instances will be created in
// the plugin side, because the IPC::Listener needs to live on the
// plugin's main thread. We just pass the FDs to plugin side.
// The FDs are created in the browser process. Following check can fail
// if the preparation for sending NaClProcessMsg_Start were incomplete.
CHECK(params.ppapi_browser_channel_handle.is_mojo_channel_handle());
CHECK(params.ppapi_renderer_channel_handle.is_mojo_channel_handle());
CHECK(params.trusted_service_channel_handle.is_mojo_channel_handle());
CHECK(params.manifest_service_channel_handle.is_mojo_channel_handle());
ppapi::SetIPCChannelHandles(
params.ppapi_browser_channel_handle,
params.ppapi_renderer_channel_handle,
params.manifest_service_channel_handle);
ppapi::StartUpPlugin();
trusted_listener_ = std::make_unique<NaClTrustedListener>(
mojo::PendingRemote<nacl::mojom::NaClRendererHost>(
mojo::ScopedMessagePipeHandle(
params.trusted_service_channel_handle.mojo_handle),
nacl::mojom::NaClRendererHost::Version_),
io_thread_.task_runner().get());
// Ensure that the validation cache key (used as an extra input to the
// validation cache's hashing) isn't exposed accidentally.
CHECK(!params.validation_cache_enabled);
CHECK(params.validation_cache_key.size() == 0);
CHECK(params.version.size() == 0);
// Ensure that a debug stub FD isn't passed through accidentally.
CHECK(!params.enable_debug_stub);
CHECK(params.debug_stub_server_bound_socket.fd == -1);
CHECK(params.irt_handle == IPC::InvalidPlatformFileForTransit());
CHECK(params.debug_stub_server_bound_socket ==
IPC::InvalidPlatformFileForTransit());
// We are only expecting non-SFI mode to be used with NaCl for now,
// not PNaCl processes.
CHECK(params.process_type == kNativeNaClProcessType);
CHECK(params.nexe_file != IPC::InvalidPlatformFileForTransit());
CHECK(params.nexe_file_path_metadata.empty());
ppapi::RegisterPreopenedDescriptorsNonSfi(key_fd_map_.release());
MainStart(IPC::PlatformFileForTransitToPlatformFile(params.nexe_file));
}
} // namespace nonsfi
} // namespace nacl