123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365 |
- // Copyright 2013 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/browser/nacl_host_message_filter.h"
- #include <stddef.h>
- #include <stdint.h>
- #include <utility>
- #include "base/bind.h"
- #include "base/system/sys_info.h"
- #include "base/task/thread_pool.h"
- #include "build/build_config.h"
- #include "build/chromeos_buildflags.h"
- #include "components/nacl/browser/bad_message.h"
- #include "components/nacl/browser/nacl_browser.h"
- #include "components/nacl/browser/nacl_file_host.h"
- #include "components/nacl/browser/nacl_process_host.h"
- #include "components/nacl/browser/pnacl_host.h"
- #include "components/nacl/common/buildflags.h"
- #include "components/nacl/common/nacl_host_messages.h"
- #include "content/public/browser/browser_task_traits.h"
- #include "content/public/browser/browser_thread.h"
- #include "content/public/browser/plugin_service.h"
- #include "content/public/browser/render_process_host.h"
- #include "content/public/browser/web_contents.h"
- #include "ipc/ipc_platform_file.h"
- #include "ppapi/shared_impl/ppapi_permissions.h"
- #include "url/gurl.h"
- namespace nacl {
- namespace {
- // The maximum number of resource file handles the browser process accepts. Use
- // 200 because ARC's nmf has ~128 resource files as of May 2015. This prevents
- // untrusted code filling the FD/handle table.
- const size_t kMaxPreOpenResourceFiles = 200;
- ppapi::PpapiPermissions GetNaClPermissions(
- uint32_t permission_bits,
- content::BrowserContext* browser_context,
- const GURL& document_url) {
- // Default permissions keep NaCl plugins backwards-compatible, but don't
- // grant any other special permissions. We don't want a compromised renderer
- // to be able to start a NaCl plugin with Dev or Flash permissions which may
- // expand the surface area of the sandbox.
- uint32_t nacl_permissions = ppapi::PERMISSION_DEFAULT;
- if (content::PluginService::GetInstance()->PpapiDevChannelSupported(
- browser_context, document_url))
- nacl_permissions |= ppapi::PERMISSION_DEV_CHANNEL;
- return ppapi::PpapiPermissions::GetForCommandLine(nacl_permissions);
- }
- ppapi::PpapiPermissions GetPpapiPermissions(
- uint32_t permission_bits,
- content::RenderFrameHost* frame_host) {
- // We get the URL from WebContents from the RenderViewHost, since we don't
- // have a BrowserPpapiHost yet.
- content::RenderViewHost* view_host = frame_host->GetRenderViewHost();
- if (!view_host)
- return ppapi::PpapiPermissions();
- GURL document_url;
- content::WebContents* contents =
- content::WebContents::FromRenderViewHost(view_host);
- if (contents)
- document_url = contents->GetLastCommittedURL();
- return GetNaClPermissions(permission_bits, frame_host->GetBrowserContext(),
- document_url);
- }
- void CallPnaclHostRendererClosing(int render_process_id) {
- pnacl::PnaclHost::GetInstance()->RendererClosing(render_process_id);
- }
- } // namespace
- NaClHostMessageFilter::NaClHostMessageFilter(
- int render_process_id,
- bool is_off_the_record,
- const base::FilePath& profile_directory)
- : BrowserMessageFilter(NaClHostMsgStart),
- render_process_id_(render_process_id),
- off_the_record_(is_off_the_record),
- profile_directory_(profile_directory) {}
- NaClHostMessageFilter::~NaClHostMessageFilter() {
- }
- void NaClHostMessageFilter::OnChannelClosing() {
- content::GetUIThreadTaskRunner({})->PostTask(
- FROM_HERE,
- base::BindOnce(CallPnaclHostRendererClosing, render_process_id_));
- }
- void NaClHostMessageFilter::OverrideThreadForMessage(
- const IPC::Message& message,
- content::BrowserThread::ID* thread) {
- #if BUILDFLAG(ENABLE_NACL)
- if (message.type() == NaClHostMsg_LaunchNaCl::ID) {
- *thread = content::BrowserThread::UI;
- } else if (message.type() == NaClHostMsg_GetReadonlyPnaclFD::ID ||
- message.type() == NaClHostMsg_NaClCreateTemporaryFile::ID ||
- message.type() == NaClHostMsg_NexeTempFileRequest::ID ||
- message.type() == NaClHostMsg_ReportTranslationFinished::ID) {
- *thread = content::BrowserThread::UI;
- }
- #endif
- }
- bool NaClHostMessageFilter::OnMessageReceived(const IPC::Message& message) {
- bool handled = true;
- IPC_BEGIN_MESSAGE_MAP(NaClHostMessageFilter, message)
- #if BUILDFLAG(ENABLE_NACL)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(NaClHostMsg_LaunchNaCl, OnLaunchNaCl)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(NaClHostMsg_GetReadonlyPnaclFD,
- OnGetReadonlyPnaclFd)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(NaClHostMsg_NaClCreateTemporaryFile,
- OnNaClCreateTemporaryFile)
- IPC_MESSAGE_HANDLER(NaClHostMsg_NexeTempFileRequest,
- OnGetNexeFd)
- IPC_MESSAGE_HANDLER(NaClHostMsg_ReportTranslationFinished,
- OnTranslationFinished)
- IPC_MESSAGE_HANDLER(NaClHostMsg_MissingArchError,
- OnMissingArchError)
- IPC_MESSAGE_HANDLER_DELAY_REPLY(NaClHostMsg_OpenNaClExecutable,
- OnOpenNaClExecutable)
- IPC_MESSAGE_HANDLER(NaClHostMsg_NaClGetNumProcessors,
- OnNaClGetNumProcessors)
- IPC_MESSAGE_HANDLER(NaClHostMsg_NaClDebugEnabledForURL,
- OnNaClDebugEnabledForURL)
- #endif
- IPC_MESSAGE_UNHANDLED(handled = false)
- IPC_END_MESSAGE_MAP()
- return handled;
- }
- void NaClHostMessageFilter::OnLaunchNaCl(
- const nacl::NaClLaunchParams& launch_params,
- IPC::Message* reply_msg) {
- DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
- auto map_url_callback =
- nacl::NaClBrowser::GetDelegate()->GetMapUrlToLocalFilePathCallback(
- profile_directory_);
- // If we're running llc or ld for the PNaCl translator, we don't need to look
- // up permissions, and we don't have the right browser state to look up some
- // of the allowed parameters anyway.
- if (launch_params.process_type == kPNaClTranslatorProcessType) {
- uint32_t perms = launch_params.permission_bits & ppapi::PERMISSION_DEV;
- LaunchNaClContinuationOnUIThread(
- launch_params, reply_msg, std::vector<NaClResourcePrefetchResult>(),
- ppapi::PpapiPermissions(perms), map_url_callback);
- return;
- }
- LaunchNaClContinuation(launch_params, reply_msg, map_url_callback);
- }
- void NaClHostMessageFilter::LaunchNaClContinuation(
- const nacl::NaClLaunchParams& launch_params,
- IPC::Message* reply_msg,
- NaClBrowserDelegate::MapUrlToLocalFilePathCallback map_url_callback) {
- DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
- content::RenderFrameHost* rfh = content::RenderFrameHost::FromID(
- render_process_id(), launch_params.render_frame_id);
- if (!rfh) {
- bad_message::ReceivedBadMessage(
- this, bad_message::NHMF_LAUNCH_CONTINUATION_BAD_ROUTING_ID);
- delete reply_msg;
- return;
- }
- ppapi::PpapiPermissions permissions =
- GetPpapiPermissions(launch_params.permission_bits, rfh);
- nacl::NaClLaunchParams safe_launch_params(launch_params);
- safe_launch_params.resource_prefetch_request_list.clear();
- // TODO(yusukes): Fix NaClProcessHost::~NaClProcessHost() and remove the
- // ifdef.
- #if !BUILDFLAG(IS_WIN)
- const std::vector<NaClResourcePrefetchRequest>& original_request_list =
- launch_params.resource_prefetch_request_list;
- content::SiteInstance* site_instance = rfh->GetSiteInstance();
- for (const auto& original_request : original_request_list) {
- GURL gurl(original_request.resource_url);
- // Important security check: Do the same check as OpenNaClExecutable()
- // in nacl_file_host.cc.
- if (!site_instance->IsSameSiteWithURL(gurl))
- continue;
- safe_launch_params.resource_prefetch_request_list.push_back(
- original_request);
- }
- #endif
- // Process a list of resource file URLs in
- // |launch_params.resource_files_to_prefetch|.
- base::ThreadPool::PostTask(
- FROM_HERE,
- {base::MayBlock(), base::TaskPriority::USER_BLOCKING,
- base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN},
- base::BindOnce(&NaClHostMessageFilter::BatchOpenResourceFiles, this,
- safe_launch_params, reply_msg, permissions,
- map_url_callback));
- }
- void NaClHostMessageFilter::BatchOpenResourceFiles(
- const nacl::NaClLaunchParams& launch_params,
- IPC::Message* reply_msg,
- ppapi::PpapiPermissions permissions,
- NaClBrowserDelegate::MapUrlToLocalFilePathCallback map_url_callback) {
- std::vector<NaClResourcePrefetchResult> prefetched_resource_files;
- const std::vector<NaClResourcePrefetchRequest>& request_list =
- launch_params.resource_prefetch_request_list;
- for (size_t i = 0; i < request_list.size(); ++i) {
- GURL gurl(request_list[i].resource_url);
- base::FilePath file_path_metadata;
- if (!map_url_callback.Run(gurl,
- true, // use_blocking_api
- &file_path_metadata)) {
- continue;
- }
- base::File file = nacl::OpenNaClReadExecImpl(
- file_path_metadata, true /* is_executable */);
- if (!file.IsValid())
- continue;
- prefetched_resource_files.push_back(NaClResourcePrefetchResult(
- IPC::TakePlatformFileForTransit(std::move(file)), file_path_metadata,
- request_list[i].file_key));
- if (prefetched_resource_files.size() >= kMaxPreOpenResourceFiles)
- break;
- }
- content::GetUIThreadTaskRunner({})->PostTask(
- FROM_HERE,
- base::BindOnce(&NaClHostMessageFilter::LaunchNaClContinuationOnUIThread,
- this, launch_params, reply_msg, prefetched_resource_files,
- permissions, map_url_callback));
- }
- void NaClHostMessageFilter::LaunchNaClContinuationOnUIThread(
- const nacl::NaClLaunchParams& launch_params,
- IPC::Message* reply_msg,
- const std::vector<NaClResourcePrefetchResult>& prefetched_resource_files,
- ppapi::PpapiPermissions permissions,
- NaClBrowserDelegate::MapUrlToLocalFilePathCallback map_url_callback) {
- DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
- NaClFileToken nexe_token = {
- launch_params.nexe_token_lo, // lo
- launch_params.nexe_token_hi // hi
- };
- base::PlatformFile nexe_file =
- IPC::PlatformFileForTransitToPlatformFile(launch_params.nexe_file);
- NaClProcessHost* host = new NaClProcessHost(
- GURL(launch_params.manifest_url), base::File(nexe_file), nexe_token,
- prefetched_resource_files, permissions, launch_params.permission_bits,
- off_the_record_, launch_params.process_type, profile_directory_);
- GURL manifest_url(launch_params.manifest_url);
- base::FilePath manifest_path;
- // We're calling MapUrlToLocalFilePath with the non-blocking API
- // because we're running in the I/O thread. Ideally we'd use the other path,
- // which would cover more cases.
- map_url_callback.Run(manifest_url, false /* use_blocking_api */,
- &manifest_path);
- host->Launch(this, reply_msg, manifest_path);
- }
- void NaClHostMessageFilter::OnGetReadonlyPnaclFd(
- const std::string& filename, bool is_executable, IPC::Message* reply_msg) {
- // This posts a task to another thread, but the renderer will
- // block until the reply is sent.
- nacl_file_host::GetReadonlyPnaclFd(this, filename, is_executable, reply_msg);
- // This is the first message we receive from the renderer once it knows we
- // want to use PNaCl, so start the translation cache initialization here.
- pnacl::PnaclHost::GetInstance()->Init();
- }
- // Return the temporary file via a reply to the
- // NaClHostMsg_NaClCreateTemporaryFile sync message.
- void NaClHostMessageFilter::SyncReturnTemporaryFile(
- IPC::Message* reply_msg,
- base::File file) {
- if (file.IsValid()) {
- NaClHostMsg_NaClCreateTemporaryFile::WriteReplyParams(
- reply_msg, IPC::TakePlatformFileForTransit(std::move(file)));
- } else {
- reply_msg->set_reply_error();
- }
- Send(reply_msg);
- }
- void NaClHostMessageFilter::OnNaClCreateTemporaryFile(
- IPC::Message* reply_msg) {
- pnacl::PnaclHost::GetInstance()->CreateTemporaryFile(base::BindRepeating(
- &NaClHostMessageFilter::SyncReturnTemporaryFile, this, reply_msg));
- }
- void NaClHostMessageFilter::AsyncReturnTemporaryFile(
- int pp_instance,
- const base::File& file,
- bool is_hit) {
- IPC::PlatformFileForTransit fd = IPC::InvalidPlatformFileForTransit();
- if (file.IsValid()) {
- // Don't close our copy of the handle, because PnaclHost will use it
- // when the translation finishes.
- fd = IPC::GetPlatformFileForTransit(file.GetPlatformFile(), false);
- }
- Send(new NaClViewMsg_NexeTempFileReply(pp_instance, is_hit, fd));
- }
- void NaClHostMessageFilter::OnNaClGetNumProcessors(int* num_processors) {
- *num_processors = base::SysInfo::NumberOfProcessors();
- }
- void NaClHostMessageFilter::OnGetNexeFd(
- int pp_instance,
- const nacl::PnaclCacheInfo& cache_info) {
- if (!cache_info.pexe_url.is_valid()) {
- LOG(ERROR) << "Bad URL received from GetNexeFd: " <<
- cache_info.pexe_url.possibly_invalid_spec();
- bad_message::ReceivedBadMessage(this,
- bad_message::NHMF_GET_NEXE_FD_BAD_URL);
- return;
- }
- pnacl::PnaclHost::GetInstance()->GetNexeFd(
- render_process_id_, pp_instance, off_the_record_, cache_info,
- base::BindRepeating(&NaClHostMessageFilter::AsyncReturnTemporaryFile,
- this, pp_instance));
- }
- void NaClHostMessageFilter::OnTranslationFinished(int instance, bool success) {
- pnacl::PnaclHost::GetInstance()->TranslationFinished(
- render_process_id_, instance, success);
- }
- void NaClHostMessageFilter::OnMissingArchError(int render_frame_id) {
- nacl::NaClBrowser::GetDelegate()->ShowMissingArchInfobar(render_process_id_,
- render_frame_id);
- }
- void NaClHostMessageFilter::OnOpenNaClExecutable(int render_frame_id,
- const GURL& file_url,
- IPC::Message* reply_msg) {
- nacl_file_host::OpenNaClExecutable(this, render_frame_id, file_url,
- reply_msg);
- }
- void NaClHostMessageFilter::OnNaClDebugEnabledForURL(const GURL& nmf_url,
- bool* should_debug) {
- *should_debug =
- nacl::NaClBrowser::GetDelegate()->URLMatchesDebugPatterns(nmf_url);
- }
- } // namespace nacl
|