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 39using content::BrowserThread; 40using content::RenderViewHost; 41 42namespace extensions { 43namespace { 44 45// Notifies the ApiActivityMonitor that an extension API function has been 46// called. May be called from any thread. 47void 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. 76struct Static { 77 Static() : api(ExtensionAPI::CreateWithDefaultConfiguration()) {} 78 scoped_ptr<ExtensionAPI> api; 79}; 80base::LazyInstance<Static> g_global_io_data = LAZY_INSTANCE_INITIALIZER; 81 82// Kills the specified process because it sends us a malformed message. 83void 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 90void 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 121void 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 142class 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 198WindowController* 199ExtensionFunctionDispatcher::Delegate::GetExtensionWindowController() const { 200 return NULL; 201} 202 203content::WebContents* 204ExtensionFunctionDispatcher::Delegate::GetAssociatedWebContents() const { 205 return NULL; 206} 207 208content::WebContents* 209ExtensionFunctionDispatcher::Delegate::GetVisibleWebContents() const { 210 return GetAssociatedWebContents(); 211} 212 213void ExtensionFunctionDispatcher::GetAllFunctionNames( 214 std::vector<std::string>* names) { 215 ExtensionFunctionRegistry::GetInstance()->GetAllNames(names); 216} 217 218bool ExtensionFunctionDispatcher::OverrideFunction( 219 const std::string& name, ExtensionFunctionFactory factory) { 220 return ExtensionFunctionRegistry::GetInstance()->OverrideFunction(name, 221 factory); 222} 223 224// static 225void 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 283ExtensionFunctionDispatcher::ExtensionFunctionDispatcher( 284 content::BrowserContext* browser_context, 285 Delegate* delegate) 286 : browser_context_(browser_context), 287 delegate_(delegate) { 288} 289 290ExtensionFunctionDispatcher::~ExtensionFunctionDispatcher() { 291} 292 293void 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 312void 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 319void 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 406void ExtensionFunctionDispatcher::OnExtensionFunctionCompleted( 407 const Extension* extension) { 408 ExtensionSystem::Get(browser_context_)->process_manager()-> 409 DecrementLazyKeepaliveCount(extension); 410} 411 412// static 413bool 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 427namespace { 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). 435bool 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 458ExtensionFunction* 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 512void 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