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