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 5#include "chrome/browser/nacl_host/nacl_browser_delegate_impl.h" 6 7#include "base/path_service.h" 8#include "base/strings/string_split.h" 9#include "chrome/browser/browser_process.h" 10#include "chrome/browser/component_updater/pnacl/pnacl_component_installer.h" 11#include "chrome/browser/extensions/extension_service.h" 12#include "chrome/browser/nacl_host/nacl_infobar_delegate.h" 13#include "chrome/browser/profiles/profile.h" 14#include "chrome/browser/profiles/profile_manager.h" 15#include "chrome/browser/renderer_host/pepper/chrome_browser_pepper_host_factory.h" 16#include "chrome/common/chrome_paths.h" 17#include "chrome/common/chrome_paths_internal.h" 18#include "chrome/common/chrome_version_info.h" 19#include "chrome/common/logging_chrome.h" 20#include "chrome/common/pepper_permission_util.h" 21#include "content/public/browser/browser_thread.h" 22#include "extensions/browser/extension_system.h" 23#include "extensions/browser/info_map.h" 24#include "extensions/browser/process_manager.h" 25#include "extensions/common/constants.h" 26#include "extensions/common/extension.h" 27#include "extensions/common/url_pattern.h" 28#include "ppapi/c/private/ppb_nacl_private.h" 29#include "url/gurl.h" 30 31namespace { 32 33// These are temporarily needed for testing non-sfi mode on ChromeOS without 34// passing command-line arguments to Chrome. 35const char* const kAllowedNonSfiOrigins[] = { 36 "6EAED1924DB611B6EEF2A664BD077BE7EAD33B8F", // see http://crbug.com/355141 37 "4EB74897CB187C7633357C2FE832E0AD6A44883A" // see http://crbug.com/355141 38}; 39 40// Handles an extension's NaCl process transitioning in or out of idle state by 41// relaying the state to the extension's process manager. 42// 43// A NaCl instance, when active (making PPAPI calls or receiving callbacks), 44// sends keepalive IPCs to the browser process BrowserPpapiHost at a throttled 45// rate. The content::BrowserPpapiHost passes context information up to the 46// chrome level NaClProcessHost where we use the instance's context to find the 47// associated extension process manager. 48// 49// There is a 1:many relationship for extension:nacl-embeds, but only a 50// 1:1 relationship for NaClProcessHost:PP_Instance. The content layer doesn't 51// rely on this knowledge because it routes messages for ppapi non-nacl 52// instances as well, though they won't have callbacks set. Here the 1:1 53// assumption is made and DCHECKed. 54void OnKeepaliveOnUIThread( 55 const content::BrowserPpapiHost::OnKeepaliveInstanceData& instance_data, 56 const base::FilePath& profile_data_directory) { 57 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 58 59 // Only one instance will exist for NaCl embeds, even when more than one 60 // embed of the same plugin exists on the same page. 61 DCHECK(instance_data.size() == 1); 62 if (instance_data.size() < 1) 63 return; 64 65#if defined(ENABLE_EXTENSIONS) 66 extensions::ProcessManager::OnKeepaliveFromPlugin( 67 instance_data[0].render_process_id, 68 instance_data[0].render_frame_id, 69 instance_data[0].document_url.host()); 70#endif 71} 72 73// Calls OnKeepaliveOnUIThread on UI thread. 74void OnKeepalive( 75 const content::BrowserPpapiHost::OnKeepaliveInstanceData& instance_data, 76 const base::FilePath& profile_data_directory) { 77 DCHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 78 content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, 79 base::Bind(&OnKeepaliveOnUIThread, 80 instance_data, 81 profile_data_directory)); 82} 83 84} // namespace 85 86NaClBrowserDelegateImpl::NaClBrowserDelegateImpl( 87 ProfileManager* profile_manager) 88 : profile_manager_(profile_manager), inverse_debug_patterns_(false) { 89 DCHECK(profile_manager_); 90 for (size_t i = 0; i < arraysize(kAllowedNonSfiOrigins); ++i) { 91 allowed_nonsfi_origins_.insert(kAllowedNonSfiOrigins[i]); 92 } 93} 94 95NaClBrowserDelegateImpl::~NaClBrowserDelegateImpl() { 96} 97 98void NaClBrowserDelegateImpl::ShowMissingArchInfobar(int render_process_id, 99 int render_view_id) { 100 content::BrowserThread::PostTask( 101 content::BrowserThread::UI, FROM_HERE, 102 base::Bind(&NaClInfoBarDelegate::Create, render_process_id, 103 render_view_id)); 104} 105 106bool NaClBrowserDelegateImpl::DialogsAreSuppressed() { 107 return logging::DialogsAreSuppressed(); 108} 109 110bool NaClBrowserDelegateImpl::GetCacheDirectory(base::FilePath* cache_dir) { 111 base::FilePath user_data_dir; 112 if (!PathService::Get(chrome::DIR_USER_DATA, &user_data_dir)) 113 return false; 114 chrome::GetUserCacheDirectory(user_data_dir, cache_dir); 115 return true; 116} 117 118bool NaClBrowserDelegateImpl::GetPluginDirectory(base::FilePath* plugin_dir) { 119 return PathService::Get(chrome::DIR_INTERNAL_PLUGINS, plugin_dir); 120} 121 122bool NaClBrowserDelegateImpl::GetPnaclDirectory(base::FilePath* pnacl_dir) { 123 return PathService::Get(chrome::DIR_PNACL_COMPONENT, pnacl_dir); 124} 125 126bool NaClBrowserDelegateImpl::GetUserDirectory(base::FilePath* user_dir) { 127 return PathService::Get(chrome::DIR_USER_DATA, user_dir); 128} 129 130std::string NaClBrowserDelegateImpl::GetVersionString() const { 131 return chrome::VersionInfo().CreateVersionString(); 132} 133 134ppapi::host::HostFactory* NaClBrowserDelegateImpl::CreatePpapiHostFactory( 135 content::BrowserPpapiHost* ppapi_host) { 136 return new chrome::ChromeBrowserPepperHostFactory(ppapi_host); 137} 138 139void NaClBrowserDelegateImpl::SetDebugPatterns(std::string debug_patterns) { 140 if (!debug_patterns.empty() && debug_patterns[0] == '!') { 141 inverse_debug_patterns_ = true; 142 debug_patterns.erase(0, 1); 143 } 144 if (debug_patterns.empty()) { 145 return; 146 } 147 std::vector<std::string> patterns; 148 base::SplitString(debug_patterns, ',', &patterns); 149 for (std::vector<std::string>::iterator iter = patterns.begin(); 150 iter != patterns.end(); ++iter) { 151 // Allow chrome:// schema, which is used to filter out the internal 152 // PNaCl translator. Also allow chrome-extension:// schema (which 153 // can have NaCl modules). The default is to disallow these schema 154 // since they can be dangerous in the context of chrome extension 155 // permissions, but they are okay here, for NaCl GDB avoidance. 156 URLPattern pattern(URLPattern::SCHEME_ALL); 157 if (pattern.Parse(*iter) == URLPattern::PARSE_SUCCESS) { 158 // If URL pattern has scheme equal to *, Parse method resets valid 159 // schemes mask to http and https only, so we need to reset it after 160 // Parse to re-include chrome-extension and chrome schema. 161 pattern.SetValidSchemes(URLPattern::SCHEME_ALL); 162 debug_patterns_.push_back(pattern); 163 } 164 } 165} 166 167bool NaClBrowserDelegateImpl::URLMatchesDebugPatterns( 168 const GURL& manifest_url) { 169 // Empty patterns are forbidden so we ignore them. 170 if (debug_patterns_.empty()) { 171 return true; 172 } 173 bool matches = false; 174 for (std::vector<URLPattern>::iterator iter = debug_patterns_.begin(); 175 iter != debug_patterns_.end(); ++iter) { 176 if (iter->MatchesURL(manifest_url)) { 177 matches = true; 178 break; 179 } 180 } 181 if (inverse_debug_patterns_) { 182 return !matches; 183 } else { 184 return matches; 185 } 186} 187 188// This function is security sensitive. Be sure to check with a security 189// person before you modify it. 190bool NaClBrowserDelegateImpl::MapUrlToLocalFilePath( 191 const GURL& file_url, 192 bool use_blocking_api, 193 const base::FilePath& profile_directory, 194 base::FilePath* file_path) { 195#if defined(ENABLE_EXTENSIONS) 196 scoped_refptr<extensions::InfoMap> extension_info_map = 197 GetExtensionInfoMap(profile_directory); 198 return extension_info_map->MapUrlToLocalFilePath( 199 file_url, use_blocking_api, file_path); 200#else 201 return false; 202#endif 203} 204 205content::BrowserPpapiHost::OnKeepaliveCallback 206NaClBrowserDelegateImpl::GetOnKeepaliveCallback() { 207 return base::Bind(&OnKeepalive); 208} 209 210bool NaClBrowserDelegateImpl::IsNonSfiModeAllowed( 211 const base::FilePath& profile_directory, 212 const GURL& manifest_url) { 213#if defined(ENABLE_EXTENSIONS) 214 const extensions::ExtensionSet* extension_set = 215 &GetExtensionInfoMap(profile_directory)->extensions(); 216 return chrome::IsExtensionOrSharedModuleWhitelisted( 217 manifest_url, extension_set, allowed_nonsfi_origins_); 218#else 219 return false; 220#endif 221} 222 223#if defined(ENABLE_EXTENSIONS) 224scoped_refptr<extensions::InfoMap> NaClBrowserDelegateImpl::GetExtensionInfoMap( 225 const base::FilePath& profile_directory) { 226 // Get the profile associated with the renderer. 227 Profile* profile = profile_manager_->GetProfileByPath(profile_directory); 228 DCHECK(profile); 229 scoped_refptr<extensions::InfoMap> extension_info_map = 230 extensions::ExtensionSystem::Get(profile)->info_map(); 231 DCHECK(extension_info_map.get()); 232 return extension_info_map; 233} 234#endif 235