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.
5 #include "extensions/browser/extension_function_dispatcher.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"
39 using content::BrowserThread
;
40 using content::RenderViewHost
;
42 namespace extensions
{
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
,
56 base::Bind(&NotifyApiFunctionCalled
,
63 // The BrowserContext may become invalid after the task above is posted.
64 if (!ExtensionsBrowserClient::Get()->IsValidContext(browser_context
))
67 ApiActivityMonitor
* monitor
=
68 ExtensionsBrowserClient::Get()->GetApiActivityMonitor(browser_context
);
70 monitor
->OnApiFunctionCalled(extension_id
, api_name
, args
.Pass());
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.
77 Static() : api(ExtensionAPI::CreateWithDefaultConfiguration()) {}
78 scoped_ptr
<ExtensionAPI
> api
;
80 base::LazyInstance
<Static
> g_global_io_data
= LAZY_INSTANCE_INITIALIZER
;
82 // Kills the specified process because it sends us a malformed message.
83 void KillBadMessageSender(base::ProcessHandle process
) {
85 content::RecordAction(base::UserMetricsAction("BadMessageTerminate_EFD"));
87 base::KillProcess(process
, content::RESULT_CODE_KILLED_BAD_MESSAGE
, false);
90 void CommonResponseCallback(IPC::Sender
* ipc_sender
,
92 base::ProcessHandle peer_process
,
94 ExtensionFunction::ResponseType type
,
95 const base::ListValue
& results
,
96 const std::string
& error
) {
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.
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.
110 KillBadMessageSender(peer_process
);
116 ipc_sender
->Send(new ExtensionMsg_Response(
117 routing_id
, request_id
, type
== ExtensionFunction::SUCCEEDED
, results
,
121 void IOThreadResponseCallback(
122 const base::WeakPtr
<ExtensionMessageFilter
>& ipc_sender
,
125 ExtensionFunction::ResponseType type
,
126 const base::ListValue
& results
,
127 const std::string
& error
) {
128 if (!ipc_sender
.get())
131 CommonResponseCallback(ipc_sender
.get(),
133 ipc_sender
->PeerHandle(),
142 class ExtensionFunctionDispatcher::UIThreadResponseCallbackWrapper
143 : public content::WebContentsObserver
{
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) {
155 virtual ~UIThreadResponseCallbackWrapper() {
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_
)
165 if (dispatcher_
.get()) {
166 dispatcher_
->ui_thread_response_callback_wrappers_
167 .erase(render_view_host
);
173 ExtensionFunction::ResponseCallback
CreateCallback(int request_id
) {
175 &UIThreadResponseCallbackWrapper::OnExtensionFunctionCompleted
,
176 weak_ptr_factory_
.GetWeakPtr(),
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
,
191 base::WeakPtr
<ExtensionFunctionDispatcher
> dispatcher_
;
192 content::RenderViewHost
* render_view_host_
;
193 base::WeakPtrFactory
<UIThreadResponseCallbackWrapper
> weak_ptr_factory_
;
195 DISALLOW_COPY_AND_ASSIGN(UIThreadResponseCallbackWrapper
);
199 ExtensionFunctionDispatcher::Delegate::GetExtensionWindowController() const {
203 content::WebContents
*
204 ExtensionFunctionDispatcher::Delegate::GetAssociatedWebContents() const {
208 content::WebContents
*
209 ExtensionFunctionDispatcher::Delegate::GetVisibleWebContents() const {
210 return GetAssociatedWebContents();
213 void ExtensionFunctionDispatcher::GetAllFunctionNames(
214 std::vector
<std::string
>* names
) {
215 ExtensionFunctionRegistry::GetInstance()->GetAllNames(names
);
218 bool ExtensionFunctionDispatcher::OverrideFunction(
219 const std::string
& name
, ExtensionFunctionFactory factory
) {
220 return ExtensionFunctionRegistry::GetInstance()->OverrideFunction(name
,
225 void ExtensionFunctionDispatcher::DispatchOnIOThread(
226 InfoMap
* extension_info_map
,
228 int render_process_id
,
229 base::WeakPtr
<ExtensionMessageFilter
> ipc_sender
,
231 const ExtensionHostMsg_Request_Params
& params
) {
232 const Extension
* extension
=
233 extension_info_map
->extensions().GetByID(params
.extension_id
);
235 ExtensionFunction::ResponseCallback
callback(
236 base::Bind(&IOThreadResponseCallback
, ipc_sender
, routing_id
,
239 scoped_refptr
<ExtensionFunction
> function(
240 CreateExtensionFunction(params
,
243 extension_info_map
->process_map(),
244 g_global_io_data
.Get().api
.get(),
250 IOThreadExtensionFunction
* function_io
=
251 function
->AsIOThreadExtensionFunction();
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()));
261 if (!CheckPermissions(function
.get(), extension
, params
, callback
))
264 QuotaService
* quota
= extension_info_map
->GetQuotaService();
265 std::string violation_error
= quota
->Assess(extension
->id(),
268 base::TimeTicks::Now());
269 if (violation_error
.empty()) {
270 scoped_ptr
<base::ListValue
> args(params
.arguments
.DeepCopy());
271 NotifyApiFunctionCalled(extension
->id(),
274 static_cast<content::BrowserContext
*>(profile_id
));
275 UMA_HISTOGRAM_SPARSE_SLOWLY("Extensions.FunctionCalls",
276 function
->histogram_value());
277 function
->Run()->Execute();
279 function
->OnQuotaExceeded(violation_error
);
283 ExtensionFunctionDispatcher::ExtensionFunctionDispatcher(
284 content::BrowserContext
* browser_context
,
286 : browser_context_(browser_context
),
287 delegate_(delegate
) {
290 ExtensionFunctionDispatcher::~ExtensionFunctionDispatcher() {
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(),
302 ui_thread_response_callback_wrappers_
[render_view_host
] = callback_wrapper
;
304 callback_wrapper
= iter
->second
;
307 DispatchWithCallbackInternal(
308 params
, render_view_host
, NULL
,
309 callback_wrapper
->CreateCallback(params
.request_id
));
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
);
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_
);
331 ExtensionRegistry
* registry
= ExtensionRegistry::Get(browser_context_
);
332 const Extension
* extension
= registry
->enabled_extensions().GetByID(
333 params
.extension_id
);
336 registry
->enabled_extensions().GetHostedAppByURL(params
.source_url
);
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
,
346 ExtensionAPI::GetSharedInstance(),
352 UIThreadExtensionFunction
* function_ui
=
353 function
->AsUIThreadExtensionFunction();
358 if (render_view_host
) {
359 function_ui
->SetRenderViewHost(render_view_host
);
361 function_ui
->SetRenderFrameHost(render_frame_host
);
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_
));
369 if (!CheckPermissions(function
.get(), extension
, params
, callback
))
372 ExtensionSystem
* extension_system
= ExtensionSystem::Get(browser_context_
);
373 QuotaService
* quota
= extension_system
->quota_service();
374 std::string violation_error
= quota
->Assess(extension
->id(),
377 base::TimeTicks::Now());
378 if (violation_error
.empty()) {
379 scoped_ptr
<base::ListValue
> args(params
.arguments
.DeepCopy());
381 NotifyApiFunctionCalled(
382 extension
->id(), params
.name
, args
.Pass(), browser_context_
);
383 UMA_HISTOGRAM_SPARSE_SLOWLY("Extensions.FunctionCalls",
384 function
->histogram_value());
385 function
->Run()->Execute();
387 function
->OnQuotaExceeded(violation_error
);
390 // Note: do not access |this| after this point. We may have been deleted
391 // if function->Run() ended up closing the tab that owns us.
393 // Check if extension was uninstalled by management.uninstall.
394 if (!registry
->enabled_extensions().GetByID(params
.extension_id
))
397 // We only adjust the keepalive count for UIThreadExtensionFunction for
398 // now, largely for simplicity's sake. This is OK because currently, only
399 // the webRequest API uses IOThreadExtensionFunction, and that API is not
400 // compatible with lazy background pages.
401 extension_system
->process_manager()->IncrementLazyKeepaliveCount(extension
);
404 void ExtensionFunctionDispatcher::OnExtensionFunctionCompleted(
405 const Extension
* extension
) {
406 ExtensionSystem::Get(browser_context_
)->process_manager()->
407 DecrementLazyKeepaliveCount(extension
);
411 bool ExtensionFunctionDispatcher::CheckPermissions(
412 ExtensionFunction
* function
,
413 const Extension
* extension
,
414 const ExtensionHostMsg_Request_Params
& params
,
415 const ExtensionFunction::ResponseCallback
& callback
) {
416 if (!function
->HasPermission()) {
417 LOG(ERROR
) << "Extension " << extension
->id() << " does not have "
418 << "permission to function: " << params
.name
;
419 SendAccessDenied(callback
);
427 // Only COMPONENT hosted apps may call extension APIs, and they are limited
428 // to just the permissions they explicitly request. They should not have access
429 // to extension APIs like eg chrome.runtime, chrome.windows, etc. that normally
430 // are available without permission.
431 // TODO(mpcomplete): move this to ExtensionFunction::HasPermission (or remove
433 bool AllowHostedAppAPICall(const Extension
& extension
,
434 const GURL
& source_url
,
435 const std::string
& function_name
) {
436 if (extension
.location() != Manifest::COMPONENT
)
439 if (!extension
.web_extent().MatchesURL(source_url
))
442 // Note: Not BLESSED_WEB_PAGE_CONTEXT here because these component hosted app
443 // entities have traditionally been treated as blessed extensions, for better
445 Feature::Availability availability
=
446 ExtensionAPI::GetSharedInstance()->IsAvailable(
447 function_name
, &extension
, Feature::BLESSED_EXTENSION_CONTEXT
,
449 return availability
.is_available();
456 ExtensionFunction
* ExtensionFunctionDispatcher::CreateExtensionFunction(
457 const ExtensionHostMsg_Request_Params
& params
,
458 const Extension
* extension
,
459 int requesting_process_id
,
460 const ProcessMap
& process_map
,
463 const ExtensionFunction::ResponseCallback
& callback
) {
465 LOG(ERROR
) << "Specified extension does not exist.";
466 SendAccessDenied(callback
);
470 // Most hosted apps can't call APIs.
472 if (extension
->is_hosted_app())
473 allowed
= AllowHostedAppAPICall(*extension
, params
.source_url
, params
.name
);
475 // Privileged APIs can only be called from the process the extension
477 if (allowed
&& api
->IsPrivileged(params
.name
))
478 allowed
= process_map
.Contains(extension
->id(), requesting_process_id
);
481 LOG(ERROR
) << "Extension API call disallowed - name:" << params
.name
482 << " pid:" << requesting_process_id
483 << " from URL " << params
.source_url
.spec();
484 SendAccessDenied(callback
);
488 ExtensionFunction
* function
=
489 ExtensionFunctionRegistry::GetInstance()->NewFunction(params
.name
);
491 LOG(ERROR
) << "Unknown Extension API - " << params
.name
;
492 SendAccessDenied(callback
);
496 function
->SetArgs(¶ms
.arguments
);
497 function
->set_source_url(params
.source_url
);
498 function
->set_request_id(params
.request_id
);
499 function
->set_has_callback(params
.has_callback
);
500 function
->set_user_gesture(params
.user_gesture
);
501 function
->set_extension(extension
);
502 function
->set_profile_id(profile_id
);
503 function
->set_response_callback(callback
);
504 function
->set_source_tab_id(params
.source_tab_id
);
510 void ExtensionFunctionDispatcher::SendAccessDenied(
511 const ExtensionFunction::ResponseCallback
& callback
) {
512 base::ListValue empty_list
;
513 callback
.Run(ExtensionFunction::FAILED
, empty_list
,
514 "Access to extension API denied.");
517 } // namespace extensions