nacl_host_message_filter.cc 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365
  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
  3. // found in the LICENSE file.
  4. #include "components/nacl/browser/nacl_host_message_filter.h"
  5. #include <stddef.h>
  6. #include <stdint.h>
  7. #include <utility>
  8. #include "base/bind.h"
  9. #include "base/system/sys_info.h"
  10. #include "base/task/thread_pool.h"
  11. #include "build/build_config.h"
  12. #include "build/chromeos_buildflags.h"
  13. #include "components/nacl/browser/bad_message.h"
  14. #include "components/nacl/browser/nacl_browser.h"
  15. #include "components/nacl/browser/nacl_file_host.h"
  16. #include "components/nacl/browser/nacl_process_host.h"
  17. #include "components/nacl/browser/pnacl_host.h"
  18. #include "components/nacl/common/buildflags.h"
  19. #include "components/nacl/common/nacl_host_messages.h"
  20. #include "content/public/browser/browser_task_traits.h"
  21. #include "content/public/browser/browser_thread.h"
  22. #include "content/public/browser/plugin_service.h"
  23. #include "content/public/browser/render_process_host.h"
  24. #include "content/public/browser/web_contents.h"
  25. #include "ipc/ipc_platform_file.h"
  26. #include "ppapi/shared_impl/ppapi_permissions.h"
  27. #include "url/gurl.h"
  28. namespace nacl {
  29. namespace {
  30. // The maximum number of resource file handles the browser process accepts. Use
  31. // 200 because ARC's nmf has ~128 resource files as of May 2015. This prevents
  32. // untrusted code filling the FD/handle table.
  33. const size_t kMaxPreOpenResourceFiles = 200;
  34. ppapi::PpapiPermissions GetNaClPermissions(
  35. uint32_t permission_bits,
  36. content::BrowserContext* browser_context,
  37. const GURL& document_url) {
  38. // Default permissions keep NaCl plugins backwards-compatible, but don't
  39. // grant any other special permissions. We don't want a compromised renderer
  40. // to be able to start a NaCl plugin with Dev or Flash permissions which may
  41. // expand the surface area of the sandbox.
  42. uint32_t nacl_permissions = ppapi::PERMISSION_DEFAULT;
  43. if (content::PluginService::GetInstance()->PpapiDevChannelSupported(
  44. browser_context, document_url))
  45. nacl_permissions |= ppapi::PERMISSION_DEV_CHANNEL;
  46. return ppapi::PpapiPermissions::GetForCommandLine(nacl_permissions);
  47. }
  48. ppapi::PpapiPermissions GetPpapiPermissions(
  49. uint32_t permission_bits,
  50. content::RenderFrameHost* frame_host) {
  51. // We get the URL from WebContents from the RenderViewHost, since we don't
  52. // have a BrowserPpapiHost yet.
  53. content::RenderViewHost* view_host = frame_host->GetRenderViewHost();
  54. if (!view_host)
  55. return ppapi::PpapiPermissions();
  56. GURL document_url;
  57. content::WebContents* contents =
  58. content::WebContents::FromRenderViewHost(view_host);
  59. if (contents)
  60. document_url = contents->GetLastCommittedURL();
  61. return GetNaClPermissions(permission_bits, frame_host->GetBrowserContext(),
  62. document_url);
  63. }
  64. void CallPnaclHostRendererClosing(int render_process_id) {
  65. pnacl::PnaclHost::GetInstance()->RendererClosing(render_process_id);
  66. }
  67. } // namespace
  68. NaClHostMessageFilter::NaClHostMessageFilter(
  69. int render_process_id,
  70. bool is_off_the_record,
  71. const base::FilePath& profile_directory)
  72. : BrowserMessageFilter(NaClHostMsgStart),
  73. render_process_id_(render_process_id),
  74. off_the_record_(is_off_the_record),
  75. profile_directory_(profile_directory) {}
  76. NaClHostMessageFilter::~NaClHostMessageFilter() {
  77. }
  78. void NaClHostMessageFilter::OnChannelClosing() {
  79. content::GetUIThreadTaskRunner({})->PostTask(
  80. FROM_HERE,
  81. base::BindOnce(CallPnaclHostRendererClosing, render_process_id_));
  82. }
  83. void NaClHostMessageFilter::OverrideThreadForMessage(
  84. const IPC::Message& message,
  85. content::BrowserThread::ID* thread) {
  86. #if BUILDFLAG(ENABLE_NACL)
  87. if (message.type() == NaClHostMsg_LaunchNaCl::ID) {
  88. *thread = content::BrowserThread::UI;
  89. } else if (message.type() == NaClHostMsg_GetReadonlyPnaclFD::ID ||
  90. message.type() == NaClHostMsg_NaClCreateTemporaryFile::ID ||
  91. message.type() == NaClHostMsg_NexeTempFileRequest::ID ||
  92. message.type() == NaClHostMsg_ReportTranslationFinished::ID) {
  93. *thread = content::BrowserThread::UI;
  94. }
  95. #endif
  96. }
  97. bool NaClHostMessageFilter::OnMessageReceived(const IPC::Message& message) {
  98. bool handled = true;
  99. IPC_BEGIN_MESSAGE_MAP(NaClHostMessageFilter, message)
  100. #if BUILDFLAG(ENABLE_NACL)
  101. IPC_MESSAGE_HANDLER_DELAY_REPLY(NaClHostMsg_LaunchNaCl, OnLaunchNaCl)
  102. IPC_MESSAGE_HANDLER_DELAY_REPLY(NaClHostMsg_GetReadonlyPnaclFD,
  103. OnGetReadonlyPnaclFd)
  104. IPC_MESSAGE_HANDLER_DELAY_REPLY(NaClHostMsg_NaClCreateTemporaryFile,
  105. OnNaClCreateTemporaryFile)
  106. IPC_MESSAGE_HANDLER(NaClHostMsg_NexeTempFileRequest,
  107. OnGetNexeFd)
  108. IPC_MESSAGE_HANDLER(NaClHostMsg_ReportTranslationFinished,
  109. OnTranslationFinished)
  110. IPC_MESSAGE_HANDLER(NaClHostMsg_MissingArchError,
  111. OnMissingArchError)
  112. IPC_MESSAGE_HANDLER_DELAY_REPLY(NaClHostMsg_OpenNaClExecutable,
  113. OnOpenNaClExecutable)
  114. IPC_MESSAGE_HANDLER(NaClHostMsg_NaClGetNumProcessors,
  115. OnNaClGetNumProcessors)
  116. IPC_MESSAGE_HANDLER(NaClHostMsg_NaClDebugEnabledForURL,
  117. OnNaClDebugEnabledForURL)
  118. #endif
  119. IPC_MESSAGE_UNHANDLED(handled = false)
  120. IPC_END_MESSAGE_MAP()
  121. return handled;
  122. }
  123. void NaClHostMessageFilter::OnLaunchNaCl(
  124. const nacl::NaClLaunchParams& launch_params,
  125. IPC::Message* reply_msg) {
  126. DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
  127. auto map_url_callback =
  128. nacl::NaClBrowser::GetDelegate()->GetMapUrlToLocalFilePathCallback(
  129. profile_directory_);
  130. // If we're running llc or ld for the PNaCl translator, we don't need to look
  131. // up permissions, and we don't have the right browser state to look up some
  132. // of the allowed parameters anyway.
  133. if (launch_params.process_type == kPNaClTranslatorProcessType) {
  134. uint32_t perms = launch_params.permission_bits & ppapi::PERMISSION_DEV;
  135. LaunchNaClContinuationOnUIThread(
  136. launch_params, reply_msg, std::vector<NaClResourcePrefetchResult>(),
  137. ppapi::PpapiPermissions(perms), map_url_callback);
  138. return;
  139. }
  140. LaunchNaClContinuation(launch_params, reply_msg, map_url_callback);
  141. }
  142. void NaClHostMessageFilter::LaunchNaClContinuation(
  143. const nacl::NaClLaunchParams& launch_params,
  144. IPC::Message* reply_msg,
  145. NaClBrowserDelegate::MapUrlToLocalFilePathCallback map_url_callback) {
  146. DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
  147. content::RenderFrameHost* rfh = content::RenderFrameHost::FromID(
  148. render_process_id(), launch_params.render_frame_id);
  149. if (!rfh) {
  150. bad_message::ReceivedBadMessage(
  151. this, bad_message::NHMF_LAUNCH_CONTINUATION_BAD_ROUTING_ID);
  152. delete reply_msg;
  153. return;
  154. }
  155. ppapi::PpapiPermissions permissions =
  156. GetPpapiPermissions(launch_params.permission_bits, rfh);
  157. nacl::NaClLaunchParams safe_launch_params(launch_params);
  158. safe_launch_params.resource_prefetch_request_list.clear();
  159. // TODO(yusukes): Fix NaClProcessHost::~NaClProcessHost() and remove the
  160. // ifdef.
  161. #if !BUILDFLAG(IS_WIN)
  162. const std::vector<NaClResourcePrefetchRequest>& original_request_list =
  163. launch_params.resource_prefetch_request_list;
  164. content::SiteInstance* site_instance = rfh->GetSiteInstance();
  165. for (const auto& original_request : original_request_list) {
  166. GURL gurl(original_request.resource_url);
  167. // Important security check: Do the same check as OpenNaClExecutable()
  168. // in nacl_file_host.cc.
  169. if (!site_instance->IsSameSiteWithURL(gurl))
  170. continue;
  171. safe_launch_params.resource_prefetch_request_list.push_back(
  172. original_request);
  173. }
  174. #endif
  175. // Process a list of resource file URLs in
  176. // |launch_params.resource_files_to_prefetch|.
  177. base::ThreadPool::PostTask(
  178. FROM_HERE,
  179. {base::MayBlock(), base::TaskPriority::USER_BLOCKING,
  180. base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN},
  181. base::BindOnce(&NaClHostMessageFilter::BatchOpenResourceFiles, this,
  182. safe_launch_params, reply_msg, permissions,
  183. map_url_callback));
  184. }
  185. void NaClHostMessageFilter::BatchOpenResourceFiles(
  186. const nacl::NaClLaunchParams& launch_params,
  187. IPC::Message* reply_msg,
  188. ppapi::PpapiPermissions permissions,
  189. NaClBrowserDelegate::MapUrlToLocalFilePathCallback map_url_callback) {
  190. std::vector<NaClResourcePrefetchResult> prefetched_resource_files;
  191. const std::vector<NaClResourcePrefetchRequest>& request_list =
  192. launch_params.resource_prefetch_request_list;
  193. for (size_t i = 0; i < request_list.size(); ++i) {
  194. GURL gurl(request_list[i].resource_url);
  195. base::FilePath file_path_metadata;
  196. if (!map_url_callback.Run(gurl,
  197. true, // use_blocking_api
  198. &file_path_metadata)) {
  199. continue;
  200. }
  201. base::File file = nacl::OpenNaClReadExecImpl(
  202. file_path_metadata, true /* is_executable */);
  203. if (!file.IsValid())
  204. continue;
  205. prefetched_resource_files.push_back(NaClResourcePrefetchResult(
  206. IPC::TakePlatformFileForTransit(std::move(file)), file_path_metadata,
  207. request_list[i].file_key));
  208. if (prefetched_resource_files.size() >= kMaxPreOpenResourceFiles)
  209. break;
  210. }
  211. content::GetUIThreadTaskRunner({})->PostTask(
  212. FROM_HERE,
  213. base::BindOnce(&NaClHostMessageFilter::LaunchNaClContinuationOnUIThread,
  214. this, launch_params, reply_msg, prefetched_resource_files,
  215. permissions, map_url_callback));
  216. }
  217. void NaClHostMessageFilter::LaunchNaClContinuationOnUIThread(
  218. const nacl::NaClLaunchParams& launch_params,
  219. IPC::Message* reply_msg,
  220. const std::vector<NaClResourcePrefetchResult>& prefetched_resource_files,
  221. ppapi::PpapiPermissions permissions,
  222. NaClBrowserDelegate::MapUrlToLocalFilePathCallback map_url_callback) {
  223. DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
  224. NaClFileToken nexe_token = {
  225. launch_params.nexe_token_lo, // lo
  226. launch_params.nexe_token_hi // hi
  227. };
  228. base::PlatformFile nexe_file =
  229. IPC::PlatformFileForTransitToPlatformFile(launch_params.nexe_file);
  230. NaClProcessHost* host = new NaClProcessHost(
  231. GURL(launch_params.manifest_url), base::File(nexe_file), nexe_token,
  232. prefetched_resource_files, permissions, launch_params.permission_bits,
  233. off_the_record_, launch_params.process_type, profile_directory_);
  234. GURL manifest_url(launch_params.manifest_url);
  235. base::FilePath manifest_path;
  236. // We're calling MapUrlToLocalFilePath with the non-blocking API
  237. // because we're running in the I/O thread. Ideally we'd use the other path,
  238. // which would cover more cases.
  239. map_url_callback.Run(manifest_url, false /* use_blocking_api */,
  240. &manifest_path);
  241. host->Launch(this, reply_msg, manifest_path);
  242. }
  243. void NaClHostMessageFilter::OnGetReadonlyPnaclFd(
  244. const std::string& filename, bool is_executable, IPC::Message* reply_msg) {
  245. // This posts a task to another thread, but the renderer will
  246. // block until the reply is sent.
  247. nacl_file_host::GetReadonlyPnaclFd(this, filename, is_executable, reply_msg);
  248. // This is the first message we receive from the renderer once it knows we
  249. // want to use PNaCl, so start the translation cache initialization here.
  250. pnacl::PnaclHost::GetInstance()->Init();
  251. }
  252. // Return the temporary file via a reply to the
  253. // NaClHostMsg_NaClCreateTemporaryFile sync message.
  254. void NaClHostMessageFilter::SyncReturnTemporaryFile(
  255. IPC::Message* reply_msg,
  256. base::File file) {
  257. if (file.IsValid()) {
  258. NaClHostMsg_NaClCreateTemporaryFile::WriteReplyParams(
  259. reply_msg, IPC::TakePlatformFileForTransit(std::move(file)));
  260. } else {
  261. reply_msg->set_reply_error();
  262. }
  263. Send(reply_msg);
  264. }
  265. void NaClHostMessageFilter::OnNaClCreateTemporaryFile(
  266. IPC::Message* reply_msg) {
  267. pnacl::PnaclHost::GetInstance()->CreateTemporaryFile(base::BindRepeating(
  268. &NaClHostMessageFilter::SyncReturnTemporaryFile, this, reply_msg));
  269. }
  270. void NaClHostMessageFilter::AsyncReturnTemporaryFile(
  271. int pp_instance,
  272. const base::File& file,
  273. bool is_hit) {
  274. IPC::PlatformFileForTransit fd = IPC::InvalidPlatformFileForTransit();
  275. if (file.IsValid()) {
  276. // Don't close our copy of the handle, because PnaclHost will use it
  277. // when the translation finishes.
  278. fd = IPC::GetPlatformFileForTransit(file.GetPlatformFile(), false);
  279. }
  280. Send(new NaClViewMsg_NexeTempFileReply(pp_instance, is_hit, fd));
  281. }
  282. void NaClHostMessageFilter::OnNaClGetNumProcessors(int* num_processors) {
  283. *num_processors = base::SysInfo::NumberOfProcessors();
  284. }
  285. void NaClHostMessageFilter::OnGetNexeFd(
  286. int pp_instance,
  287. const nacl::PnaclCacheInfo& cache_info) {
  288. if (!cache_info.pexe_url.is_valid()) {
  289. LOG(ERROR) << "Bad URL received from GetNexeFd: " <<
  290. cache_info.pexe_url.possibly_invalid_spec();
  291. bad_message::ReceivedBadMessage(this,
  292. bad_message::NHMF_GET_NEXE_FD_BAD_URL);
  293. return;
  294. }
  295. pnacl::PnaclHost::GetInstance()->GetNexeFd(
  296. render_process_id_, pp_instance, off_the_record_, cache_info,
  297. base::BindRepeating(&NaClHostMessageFilter::AsyncReturnTemporaryFile,
  298. this, pp_instance));
  299. }
  300. void NaClHostMessageFilter::OnTranslationFinished(int instance, bool success) {
  301. pnacl::PnaclHost::GetInstance()->TranslationFinished(
  302. render_process_id_, instance, success);
  303. }
  304. void NaClHostMessageFilter::OnMissingArchError(int render_frame_id) {
  305. nacl::NaClBrowser::GetDelegate()->ShowMissingArchInfobar(render_process_id_,
  306. render_frame_id);
  307. }
  308. void NaClHostMessageFilter::OnOpenNaClExecutable(int render_frame_id,
  309. const GURL& file_url,
  310. IPC::Message* reply_msg) {
  311. nacl_file_host::OpenNaClExecutable(this, render_frame_id, file_url,
  312. reply_msg);
  313. }
  314. void NaClHostMessageFilter::OnNaClDebugEnabledForURL(const GURL& nmf_url,
  315. bool* should_debug) {
  316. *should_debug =
  317. nacl::NaClBrowser::GetDelegate()->URLMatchesDebugPatterns(nmf_url);
  318. }
  319. } // namespace nacl