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 235 ExtensionFunction::ResponseCallback callback( 236 base::Bind(&IOThreadResponseCallback, ipc_sender, routing_id, 237 params.request_id)); 238 239 scoped_refptr<ExtensionFunction> function( 240 CreateExtensionFunction(params, 241 extension, 242 render_process_id, 243 extension_info_map->process_map(), 244 g_global_io_data.Get().api.get(), 245 profile_id, 246 callback)); 247 if (!function.get()) 248 return; 249 250 IOThreadExtensionFunction* function_io = 251 function->AsIOThreadExtensionFunction(); 252 if (!function_io) { 253 NOTREACHED(); 254 return; 255 } 256 function_io->set_ipc_sender(ipc_sender, routing_id); 257 function_io->set_extension_info_map(extension_info_map); 258 function->set_include_incognito( 259 extension_info_map->IsIncognitoEnabled(extension->id())); 260 261 if (!CheckPermissions(function.get(), extension, params, callback)) 262 return; 263 264 QuotaService* quota = extension_info_map->GetQuotaService(); 265 std::string violation_error = quota->Assess(extension->id(), 266 function.get(), 267 ¶ms.arguments, 268 base::TimeTicks::Now()); 269 if (violation_error.empty()) { 270 scoped_ptr<base::ListValue> args(params.arguments.DeepCopy()); 271 NotifyApiFunctionCalled(extension->id(), 272 params.name, 273 args.Pass(), 274 static_cast<content::BrowserContext*>(profile_id)); 275 UMA_HISTOGRAM_SPARSE_SLOWLY("Extensions.FunctionCalls", 276 function->histogram_value()); 277 function->Run()->Execute(); 278 } else { 279 function->OnQuotaExceeded(violation_error); 280 } 281 } 282 283 ExtensionFunctionDispatcher::ExtensionFunctionDispatcher( 284 content::BrowserContext* browser_context, 285 Delegate* delegate) 286 : browser_context_(browser_context), 287 delegate_(delegate) { 288 } 289 290 ExtensionFunctionDispatcher::~ExtensionFunctionDispatcher() { 291 } 292 293 void ExtensionFunctionDispatcher::Dispatch( 294 const ExtensionHostMsg_Request_Params& params, 295 RenderViewHost* render_view_host) { 296 UIThreadResponseCallbackWrapperMap::const_iterator 297 iter = ui_thread_response_callback_wrappers_.find(render_view_host); 298 UIThreadResponseCallbackWrapper* callback_wrapper = NULL; 299 if (iter == ui_thread_response_callback_wrappers_.end()) { 300 callback_wrapper = new UIThreadResponseCallbackWrapper(AsWeakPtr(), 301 render_view_host); 302 ui_thread_response_callback_wrappers_[render_view_host] = callback_wrapper; 303 } else { 304 callback_wrapper = iter->second; 305 } 306 307 DispatchWithCallbackInternal( 308 params, render_view_host, NULL, 309 callback_wrapper->CreateCallback(params.request_id)); 310 } 311 312 void ExtensionFunctionDispatcher::DispatchWithCallback( 313 const ExtensionHostMsg_Request_Params& params, 314 content::RenderFrameHost* render_frame_host, 315 const ExtensionFunction::ResponseCallback& callback) { 316 DispatchWithCallbackInternal(params, NULL, render_frame_host, callback); 317 } 318 319 void ExtensionFunctionDispatcher::DispatchWithCallbackInternal( 320 const ExtensionHostMsg_Request_Params& params, 321 RenderViewHost* render_view_host, 322 content::RenderFrameHost* render_frame_host, 323 const ExtensionFunction::ResponseCallback& callback) { 324 DCHECK(render_view_host || render_frame_host); 325 // TODO(yzshen): There is some shared logic between this method and 326 // DispatchOnIOThread(). It is nice to deduplicate. 327 ProcessMap* process_map = ProcessMap::Get(browser_context_); 328 if (!process_map) 329 return; 330 331 ExtensionRegistry* registry = ExtensionRegistry::Get(browser_context_); 332 const Extension* extension = registry->enabled_extensions().GetByID( 333 params.extension_id); 334 if (!extension) { 335 extension = 336 registry->enabled_extensions().GetHostedAppByURL(params.source_url); 337 } 338 339 int process_id = render_view_host ? render_view_host->GetProcess()->GetID() : 340 render_frame_host->GetProcess()->GetID(); 341 scoped_refptr<ExtensionFunction> function( 342 CreateExtensionFunction(params, 343 extension, 344 process_id, 345 *process_map, 346 ExtensionAPI::GetSharedInstance(), 347 browser_context_, 348 callback)); 349 if (!function.get()) 350 return; 351 352 UIThreadExtensionFunction* function_ui = 353 function->AsUIThreadExtensionFunction(); 354 if (!function_ui) { 355 NOTREACHED(); 356 return; 357 } 358 if (render_view_host) { 359 function_ui->SetRenderViewHost(render_view_host); 360 } else { 361 function_ui->SetRenderFrameHost(render_frame_host); 362 } 363 function_ui->set_dispatcher(AsWeakPtr()); 364 function_ui->set_browser_context(browser_context_); 365 function->set_include_incognito( 366 ExtensionsBrowserClient::Get()->CanExtensionCrossIncognito( 367 extension, browser_context_)); 368 369 if (!CheckPermissions(function.get(), extension, params, callback)) 370 return; 371 372 ExtensionSystem* extension_system = ExtensionSystem::Get(browser_context_); 373 QuotaService* quota = extension_system->quota_service(); 374 std::string violation_error = quota->Assess(extension->id(), 375 function.get(), 376 ¶ms.arguments, 377 base::TimeTicks::Now()); 378 if (violation_error.empty()) { 379 scoped_ptr<base::ListValue> args(params.arguments.DeepCopy()); 380 381 // See crbug.com/39178. 382 ExtensionsBrowserClient::Get()->PermitExternalProtocolHandler(); 383 NotifyApiFunctionCalled( 384 extension->id(), params.name, args.Pass(), browser_context_); 385 UMA_HISTOGRAM_SPARSE_SLOWLY("Extensions.FunctionCalls", 386 function->histogram_value()); 387 function->Run()->Execute(); 388 } else { 389 function->OnQuotaExceeded(violation_error); 390 } 391 392 // Note: do not access |this| after this point. We may have been deleted 393 // if function->Run() ended up closing the tab that owns us. 394 395 // Check if extension was uninstalled by management.uninstall. 396 if (!registry->enabled_extensions().GetByID(params.extension_id)) 397 return; 398 399 // We only adjust the keepalive count for UIThreadExtensionFunction for 400 // now, largely for simplicity's sake. This is OK because currently, only 401 // the webRequest API uses IOThreadExtensionFunction, and that API is not 402 // compatible with lazy background pages. 403 extension_system->process_manager()->IncrementLazyKeepaliveCount(extension); 404 } 405 406 void ExtensionFunctionDispatcher::OnExtensionFunctionCompleted( 407 const Extension* extension) { 408 ExtensionSystem::Get(browser_context_)->process_manager()-> 409 DecrementLazyKeepaliveCount(extension); 410 } 411 412 // static 413 bool ExtensionFunctionDispatcher::CheckPermissions( 414 ExtensionFunction* function, 415 const Extension* extension, 416 const ExtensionHostMsg_Request_Params& params, 417 const ExtensionFunction::ResponseCallback& callback) { 418 if (!function->HasPermission()) { 419 LOG(ERROR) << "Extension " << extension->id() << " does not have " 420 << "permission to function: " << params.name; 421 SendAccessDenied(callback); 422 return false; 423 } 424 return true; 425 } 426 427 namespace { 428 429 // Only COMPONENT hosted apps may call extension APIs, and they are limited 430 // to just the permissions they explicitly request. They should not have access 431 // to extension APIs like eg chrome.runtime, chrome.windows, etc. that normally 432 // are available without permission. 433 // TODO(mpcomplete): move this to ExtensionFunction::HasPermission (or remove 434 // it altogether). 435 bool AllowHostedAppAPICall(const Extension& extension, 436 const GURL& source_url, 437 const std::string& function_name) { 438 if (extension.location() != Manifest::COMPONENT) 439 return false; 440 441 if (!extension.web_extent().MatchesURL(source_url)) 442 return false; 443 444 // Note: Not BLESSED_WEB_PAGE_CONTEXT here because these component hosted app 445 // entities have traditionally been treated as blessed extensions, for better 446 // or worse. 447 Feature::Availability availability = 448 ExtensionAPI::GetSharedInstance()->IsAvailable( 449 function_name, &extension, Feature::BLESSED_EXTENSION_CONTEXT, 450 source_url); 451 return availability.is_available(); 452 } 453 454 } // namespace 455 456 457 // static 458 ExtensionFunction* ExtensionFunctionDispatcher::CreateExtensionFunction( 459 const ExtensionHostMsg_Request_Params& params, 460 const Extension* extension, 461 int requesting_process_id, 462 const ProcessMap& process_map, 463 ExtensionAPI* api, 464 void* profile_id, 465 const ExtensionFunction::ResponseCallback& callback) { 466 if (!extension) { 467 LOG(ERROR) << "Specified extension does not exist."; 468 SendAccessDenied(callback); 469 return NULL; 470 } 471 472 // Most hosted apps can't call APIs. 473 bool allowed = true; 474 if (extension->is_hosted_app()) 475 allowed = AllowHostedAppAPICall(*extension, params.source_url, params.name); 476 477 // Privileged APIs can only be called from the process the extension 478 // is running in. 479 if (allowed && api->IsPrivileged(params.name)) 480 allowed = process_map.Contains(extension->id(), requesting_process_id); 481 482 if (!allowed) { 483 LOG(ERROR) << "Extension API call disallowed - name:" << params.name 484 << " pid:" << requesting_process_id 485 << " from URL " << params.source_url.spec(); 486 SendAccessDenied(callback); 487 return NULL; 488 } 489 490 ExtensionFunction* function = 491 ExtensionFunctionRegistry::GetInstance()->NewFunction(params.name); 492 if (!function) { 493 LOG(ERROR) << "Unknown Extension API - " << params.name; 494 SendAccessDenied(callback); 495 return NULL; 496 } 497 498 function->SetArgs(¶ms.arguments); 499 function->set_source_url(params.source_url); 500 function->set_request_id(params.request_id); 501 function->set_has_callback(params.has_callback); 502 function->set_user_gesture(params.user_gesture); 503 function->set_extension(extension); 504 function->set_profile_id(profile_id); 505 function->set_response_callback(callback); 506 function->set_source_tab_id(params.source_tab_id); 507 508 return function; 509 } 510 511 // static 512 void ExtensionFunctionDispatcher::SendAccessDenied( 513 const ExtensionFunction::ResponseCallback& callback) { 514 base::ListValue empty_list; 515 callback.Run(ExtensionFunction::FAILED, empty_list, 516 "Access to extension API denied."); 517 } 518 519 } // namespace extensions 520