1 // Copyright 2014 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 "extensions/browser/extension_function_dispatcher.h" 6 7 #include "base/bind.h" 8 #include "base/json/json_string_value_serializer.h" 9 #include "base/lazy_instance.h" 10 #include "base/logging.h" 11 #include "base/memory/ref_counted.h" 12 #include "base/metrics/sparse_histogram.h" 13 #include "base/process/process.h" 14 #include "base/values.h" 15 #include "build/build_config.h" 16 #include "content/public/browser/browser_thread.h" 17 #include "content/public/browser/render_frame_host.h" 18 #include "content/public/browser/render_process_host.h" 19 #include "content/public/browser/render_view_host.h" 20 #include "content/public/browser/user_metrics.h" 21 #include "content/public/browser/web_contents.h" 22 #include "content/public/browser/web_contents_observer.h" 23 #include "content/public/common/result_codes.h" 24 #include "extensions/browser/api_activity_monitor.h" 25 #include "extensions/browser/extension_function_registry.h" 26 #include "extensions/browser/extension_message_filter.h" 27 #include "extensions/browser/extension_registry.h" 28 #include "extensions/browser/extension_system.h" 29 #include "extensions/browser/extensions_browser_client.h" 30 #include "extensions/browser/process_manager.h" 31 #include "extensions/browser/process_map.h" 32 #include "extensions/browser/quota_service.h" 33 #include "extensions/common/extension_api.h" 34 #include "extensions/common/extension_messages.h" 35 #include "extensions/common/extension_set.h" 36 #include "ipc/ipc_message.h" 37 #include "ipc/ipc_message_macros.h" 38 39 using content::BrowserThread; 40 using content::RenderViewHost; 41 42 namespace extensions { 43 namespace { 44 45 // Notifies the ApiActivityMonitor that an extension API function has been 46 // called. May be called from any thread. 47 void NotifyApiFunctionCalled(const std::string& extension_id, 48 const std::string& api_name, 49 scoped_ptr<base::ListValue> args, 50 content::BrowserContext* browser_context) { 51 // The ApiActivityMonitor can only be accessed from the main (UI) thread. If 52 // we're running on the wrong thread, re-dispatch from the main thread. 53 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { 54 BrowserThread::PostTask(BrowserThread::UI, 55 FROM_HERE, 56 base::Bind(&NotifyApiFunctionCalled, 57 extension_id, 58 api_name, 59 base::Passed(&args), 60 browser_context)); 61 return; 62 } 63 // The BrowserContext may become invalid after the task above is posted. 64 if (!ExtensionsBrowserClient::Get()->IsValidContext(browser_context)) 65 return; 66 67 ApiActivityMonitor* monitor = 68 ExtensionsBrowserClient::Get()->GetApiActivityMonitor(browser_context); 69 if (monitor) 70 monitor->OnApiFunctionCalled(extension_id, api_name, args.Pass()); 71 } 72 73 // Separate copy of ExtensionAPI used for IO thread extension functions. We need 74 // this because ExtensionAPI has mutable data. It should be possible to remove 75 // this once all the extension APIs are updated to the feature system. 76 struct Static { 77 Static() : api(ExtensionAPI::CreateWithDefaultConfiguration()) {} 78 scoped_ptr<ExtensionAPI> api; 79 }; 80 base::LazyInstance<Static> g_global_io_data = LAZY_INSTANCE_INITIALIZER; 81 82 // Kills the specified process because it sends us a malformed message. 83 void KillBadMessageSender(base::ProcessHandle process) { 84 NOTREACHED(); 85 content::RecordAction(base::UserMetricsAction("BadMessageTerminate_EFD")); 86 if (process) 87 base::KillProcess(process, content::RESULT_CODE_KILLED_BAD_MESSAGE, false); 88 } 89 90 void CommonResponseCallback(IPC::Sender* ipc_sender, 91 int routing_id, 92 base::ProcessHandle peer_process, 93 int request_id, 94 ExtensionFunction::ResponseType type, 95 const base::ListValue& results, 96 const std::string& error) { 97 DCHECK(ipc_sender); 98 99 if (type == ExtensionFunction::BAD_MESSAGE) { 100 // The renderer has done validation before sending extension api requests. 101 // Therefore, we should never receive a request that is invalid in a way 102 // that JSON validation in the renderer should have caught. It could be an 103 // attacker trying to exploit the browser, so we crash the renderer instead. 104 LOG(ERROR) << 105 "Terminating renderer because of malformed extension message."; 106 if (content::RenderProcessHost::run_renderer_in_process()) { 107 // In single process mode it is better if we don't suicide but just crash. 108 CHECK(false); 109 } else { 110 KillBadMessageSender(peer_process); 111 } 112 113 return; 114 } 115 116 ipc_sender->Send(new ExtensionMsg_Response( 117 routing_id, request_id, type == ExtensionFunction::SUCCEEDED, results, 118 error)); 119 } 120 121 void IOThreadResponseCallback( 122 const base::WeakPtr<ExtensionMessageFilter>& ipc_sender, 123 int routing_id, 124 int request_id, 125 ExtensionFunction::ResponseType type, 126 const base::ListValue& results, 127 const std::string& error) { 128 if (!ipc_sender.get()) 129 return; 130 131 CommonResponseCallback(ipc_sender.get(), 132 routing_id, 133 ipc_sender->PeerHandle(), 134 request_id, 135 type, 136 results, 137 error); 138 } 139 140 } // namespace 141 142 class ExtensionFunctionDispatcher::UIThreadResponseCallbackWrapper 143 : public content::WebContentsObserver { 144 public: 145 UIThreadResponseCallbackWrapper( 146 const base::WeakPtr<ExtensionFunctionDispatcher>& dispatcher, 147 RenderViewHost* render_view_host) 148 : content::WebContentsObserver( 149 content::WebContents::FromRenderViewHost(render_view_host)), 150 dispatcher_(dispatcher), 151 render_view_host_(render_view_host), 152 weak_ptr_factory_(this) { 153 } 154 155 virtual ~UIThreadResponseCallbackWrapper() { 156 } 157 158 // content::WebContentsObserver overrides. 159 virtual void RenderViewDeleted( 160 RenderViewHost* render_view_host) OVERRIDE { 161 DCHECK_CURRENTLY_ON(BrowserThread::UI); 162 if (render_view_host != render_view_host_) 163 return; 164 165 if (dispatcher_.get()) { 166 dispatcher_->ui_thread_response_callback_wrappers_ 167 .erase(render_view_host); 168 } 169 170 delete this; 171 } 172 173 ExtensionFunction::ResponseCallback CreateCallback(int request_id) { 174 return base::Bind( 175 &UIThreadResponseCallbackWrapper::OnExtensionFunctionCompleted, 176 weak_ptr_factory_.GetWeakPtr(), 177 request_id); 178 } 179 180 private: 181 void OnExtensionFunctionCompleted(int request_id, 182 ExtensionFunction::ResponseType type, 183 const base::ListValue& results, 184 const std::string& error) { 185 CommonResponseCallback( 186 render_view_host_, render_view_host_->GetRoutingID(), 187 render_view_host_->GetProcess()->GetHandle(), request_id, type, 188 results, error); 189 } 190 191 base::WeakPtr<ExtensionFunctionDispatcher> dispatcher_; 192 content::RenderViewHost* render_view_host_; 193 base::WeakPtrFactory<UIThreadResponseCallbackWrapper> weak_ptr_factory_; 194 195 DISALLOW_COPY_AND_ASSIGN(UIThreadResponseCallbackWrapper); 196 }; 197 198 WindowController* 199 ExtensionFunctionDispatcher::Delegate::GetExtensionWindowController() const { 200 return NULL; 201 } 202 203 content::WebContents* 204 ExtensionFunctionDispatcher::Delegate::GetAssociatedWebContents() const { 205 return NULL; 206 } 207 208 content::WebContents* 209 ExtensionFunctionDispatcher::Delegate::GetVisibleWebContents() const { 210 return GetAssociatedWebContents(); 211 } 212 213 void ExtensionFunctionDispatcher::GetAllFunctionNames( 214 std::vector<std::string>* names) { 215 ExtensionFunctionRegistry::GetInstance()->GetAllNames(names); 216 } 217 218 bool ExtensionFunctionDispatcher::OverrideFunction( 219 const std::string& name, ExtensionFunctionFactory factory) { 220 return ExtensionFunctionRegistry::GetInstance()->OverrideFunction(name, 221 factory); 222 } 223 224 // static 225 void ExtensionFunctionDispatcher::DispatchOnIOThread( 226 InfoMap* extension_info_map, 227 void* profile_id, 228 int render_process_id, 229 base::WeakPtr<ExtensionMessageFilter> ipc_sender, 230 int routing_id, 231 const ExtensionHostMsg_Request_Params& params) { 232 const Extension* extension = 233 extension_info_map->extensions().GetByID(params.extension_id); 234 if (!extension) 235 return; 236 237 ExtensionFunction::ResponseCallback callback( 238 base::Bind(&IOThreadResponseCallback, ipc_sender, routing_id, 239 params.request_id)); 240 241 scoped_refptr<ExtensionFunction> function( 242 CreateExtensionFunction(params, 243 extension, 244 render_process_id, 245 extension_info_map->process_map(), 246 g_global_io_data.Get().api.get(), 247 profile_id, 248 callback)); 249 if (!function.get()) 250 return; 251 252 IOThreadExtensionFunction* function_io = 253 function->AsIOThreadExtensionFunction(); 254 if (!function_io) { 255 NOTREACHED(); 256 return; 257 } 258 function_io->set_ipc_sender(ipc_sender, routing_id); 259 function_io->set_extension_info_map(extension_info_map); 260 function->set_include_incognito( 261 extension_info_map->IsIncognitoEnabled(extension->id())); 262 263 if (!CheckPermissions(function.get(), params, callback)) 264 return; 265 266 QuotaService* quota = extension_info_map->GetQuotaService(); 267 std::string violation_error = quota->Assess(extension->id(), 268 function.get(), 269 ¶ms.arguments, 270 base::TimeTicks::Now()); 271 if (violation_error.empty()) { 272 scoped_ptr<base::ListValue> args(params.arguments.DeepCopy()); 273 NotifyApiFunctionCalled(extension->id(), 274 params.name, 275 args.Pass(), 276 static_cast<content::BrowserContext*>(profile_id)); 277 UMA_HISTOGRAM_SPARSE_SLOWLY("Extensions.FunctionCalls", 278 function->histogram_value()); 279 function->Run()->Execute(); 280 } else { 281 function->OnQuotaExceeded(violation_error); 282 } 283 } 284 285 ExtensionFunctionDispatcher::ExtensionFunctionDispatcher( 286 content::BrowserContext* browser_context, 287 Delegate* delegate) 288 : browser_context_(browser_context), 289 delegate_(delegate) { 290 } 291 292 ExtensionFunctionDispatcher::~ExtensionFunctionDispatcher() { 293 } 294 295 void ExtensionFunctionDispatcher::Dispatch( 296 const ExtensionHostMsg_Request_Params& params, 297 RenderViewHost* render_view_host) { 298 UIThreadResponseCallbackWrapperMap::const_iterator 299 iter = ui_thread_response_callback_wrappers_.find(render_view_host); 300 UIThreadResponseCallbackWrapper* callback_wrapper = NULL; 301 if (iter == ui_thread_response_callback_wrappers_.end()) { 302 callback_wrapper = new UIThreadResponseCallbackWrapper(AsWeakPtr(), 303 render_view_host); 304 ui_thread_response_callback_wrappers_[render_view_host] = callback_wrapper; 305 } else { 306 callback_wrapper = iter->second; 307 } 308 309 DispatchWithCallbackInternal( 310 params, render_view_host, NULL, 311 callback_wrapper->CreateCallback(params.request_id)); 312 } 313 314 void ExtensionFunctionDispatcher::DispatchWithCallbackInternal( 315 const ExtensionHostMsg_Request_Params& params, 316 RenderViewHost* render_view_host, 317 content::RenderFrameHost* render_frame_host, 318 const ExtensionFunction::ResponseCallback& callback) { 319 DCHECK(render_view_host || render_frame_host); 320 // TODO(yzshen): There is some shared logic between this method and 321 // DispatchOnIOThread(). It is nice to deduplicate. 322 ProcessMap* process_map = ProcessMap::Get(browser_context_); 323 if (!process_map) 324 return; 325 326 ExtensionRegistry* registry = ExtensionRegistry::Get(browser_context_); 327 const Extension* extension = 328 registry->enabled_extensions().GetByID(params.extension_id); 329 if (!extension) { 330 extension = 331 registry->enabled_extensions().GetHostedAppByURL(params.source_url); 332 } 333 334 int process_id = render_view_host ? render_view_host->GetProcess()->GetID() : 335 render_frame_host->GetProcess()->GetID(); 336 scoped_refptr<ExtensionFunction> function( 337 CreateExtensionFunction(params, 338 extension, 339 process_id, 340 *process_map, 341 ExtensionAPI::GetSharedInstance(), 342 browser_context_, 343 callback)); 344 if (!function.get()) 345 return; 346 347 UIThreadExtensionFunction* function_ui = 348 function->AsUIThreadExtensionFunction(); 349 if (!function_ui) { 350 NOTREACHED(); 351 return; 352 } 353 if (render_view_host) { 354 function_ui->SetRenderViewHost(render_view_host); 355 } else { 356 function_ui->SetRenderFrameHost(render_frame_host); 357 } 358 function_ui->set_dispatcher(AsWeakPtr()); 359 function_ui->set_browser_context(browser_context_); 360 if (extension && 361 ExtensionsBrowserClient::Get()->CanExtensionCrossIncognito( 362 extension, browser_context_)) { 363 function->set_include_incognito(true); 364 } 365 366 if (!CheckPermissions(function.get(), params, callback)) 367 return; 368 369 if (!extension) { 370 // Skip all of the UMA, quota, event page, activity logging stuff if there 371 // isn't an extension, e.g. if the function call was from WebUI. 372 function->Run()->Execute(); 373 return; 374 } 375 376 ExtensionSystem* extension_system = ExtensionSystem::Get(browser_context_); 377 QuotaService* quota = extension_system->quota_service(); 378 std::string violation_error = quota->Assess(extension->id(), 379 function.get(), 380 ¶ms.arguments, 381 base::TimeTicks::Now()); 382 383 if (violation_error.empty()) { 384 scoped_ptr<base::ListValue> args(params.arguments.DeepCopy()); 385 386 // See crbug.com/39178. 387 ExtensionsBrowserClient::Get()->PermitExternalProtocolHandler(); 388 NotifyApiFunctionCalled( 389 extension->id(), params.name, args.Pass(), browser_context_); 390 UMA_HISTOGRAM_SPARSE_SLOWLY("Extensions.FunctionCalls", 391 function->histogram_value()); 392 function->Run()->Execute(); 393 } else { 394 function->OnQuotaExceeded(violation_error); 395 } 396 397 // Note: do not access |this| after this point. We may have been deleted 398 // if function->Run() ended up closing the tab that owns us. 399 400 // Check if extension was uninstalled by management.uninstall. 401 if (!registry->enabled_extensions().GetByID(params.extension_id)) 402 return; 403 404 // We only adjust the keepalive count for UIThreadExtensionFunction for 405 // now, largely for simplicity's sake. This is OK because currently, only 406 // the webRequest API uses IOThreadExtensionFunction, and that API is not 407 // compatible with lazy background pages. 408 extension_system->process_manager()->IncrementLazyKeepaliveCount(extension); 409 } 410 411 void ExtensionFunctionDispatcher::OnExtensionFunctionCompleted( 412 const Extension* extension) { 413 if (extension) { 414 ExtensionSystem::Get(browser_context_) 415 ->process_manager() 416 ->DecrementLazyKeepaliveCount(extension); 417 } 418 } 419 420 // static 421 bool ExtensionFunctionDispatcher::CheckPermissions( 422 ExtensionFunction* function, 423 const ExtensionHostMsg_Request_Params& params, 424 const ExtensionFunction::ResponseCallback& callback) { 425 if (!function->HasPermission()) { 426 LOG(ERROR) << "Permission denied for " << params.name; 427 SendAccessDenied(callback); 428 return false; 429 } 430 return true; 431 } 432 433 // static 434 ExtensionFunction* ExtensionFunctionDispatcher::CreateExtensionFunction( 435 const ExtensionHostMsg_Request_Params& params, 436 const Extension* extension, 437 int requesting_process_id, 438 const ProcessMap& process_map, 439 ExtensionAPI* api, 440 void* profile_id, 441 const ExtensionFunction::ResponseCallback& callback) { 442 ExtensionFunction* function = 443 ExtensionFunctionRegistry::GetInstance()->NewFunction(params.name); 444 if (!function) { 445 LOG(ERROR) << "Unknown Extension API - " << params.name; 446 SendAccessDenied(callback); 447 return NULL; 448 } 449 450 function->SetArgs(¶ms.arguments); 451 function->set_source_url(params.source_url); 452 function->set_request_id(params.request_id); 453 function->set_has_callback(params.has_callback); 454 function->set_user_gesture(params.user_gesture); 455 function->set_extension(extension); 456 function->set_profile_id(profile_id); 457 function->set_response_callback(callback); 458 function->set_source_tab_id(params.source_tab_id); 459 function->set_source_context_type( 460 process_map.GetMostLikelyContextType(extension, requesting_process_id)); 461 462 return function; 463 } 464 465 // static 466 void ExtensionFunctionDispatcher::SendAccessDenied( 467 const ExtensionFunction::ResponseCallback& callback) { 468 base::ListValue empty_list; 469 callback.Run(ExtensionFunction::FAILED, empty_list, 470 "Access to extension API denied."); 471 } 472 473 } // namespace extensions 474