1 // Copyright (c) 2012 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 "chrome/browser/extensions/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/process/process.h"
13 #include "base/values.h"
14 #include "build/build_config.h"
15 #include "chrome/browser/extensions/activity_log/activity_action_constants.h"
16 #include "chrome/browser/extensions/activity_log/activity_log.h"
17 #include "chrome/browser/extensions/api/activity_log_private/activity_log_private_api.h"
18 #include "chrome/browser/extensions/extension_function_registry.h"
19 #include "chrome/browser/extensions/extension_service.h"
20 #include "chrome/browser/extensions/extension_system.h"
21 #include "chrome/browser/extensions/extension_util.h"
22 #include "chrome/browser/extensions/extension_web_ui.h"
23 #include "chrome/browser/external_protocol/external_protocol_handler.h"
24 #include "chrome/browser/renderer_host/chrome_render_message_filter.h"
25 #include "chrome/common/extensions/extension_messages.h"
26 #include "chrome/common/url_constants.h"
27 #include "content/public/browser/browser_thread.h"
28 #include "content/public/browser/render_frame_host.h"
29 #include "content/public/browser/render_process_host.h"
30 #include "content/public/browser/render_view_host.h"
31 #include "content/public/browser/user_metrics.h"
32 #include "content/public/browser/web_contents.h"
33 #include "content/public/browser/web_contents_observer.h"
34 #include "content/public/common/result_codes.h"
35 #include "extensions/browser/process_map.h"
36 #include "extensions/browser/quota_service.h"
37 #include "extensions/common/extension_api.h"
38 #include "extensions/common/extension_set.h"
39 #include "ipc/ipc_message.h"
40 #include "ipc/ipc_message_macros.h"
41 #include "webkit/common/resource_type.h"
43 using extensions::Extension
;
44 using extensions::ExtensionAPI
;
45 using extensions::ExtensionSystem
;
46 using extensions::Feature
;
47 using content::RenderViewHost
;
51 void LogSuccess(const std::string
& extension_id
,
52 const std::string
& api_name
,
53 scoped_ptr
<base::ListValue
> args
,
54 content::BrowserContext
* browser_context
) {
55 // The ActivityLog can only be accessed from the main (UI) thread. If we're
56 // running on the wrong thread, re-dispatch from the main thread.
57 if (!BrowserThread::CurrentlyOn(BrowserThread::UI
)) {
58 BrowserThread::PostTask(BrowserThread::UI
,
60 base::Bind(&LogSuccess
,
66 extensions::ActivityLog
* activity_log
=
67 extensions::ActivityLog::GetInstance(browser_context
);
68 scoped_refptr
<extensions::Action
> action
=
69 new extensions::Action(extension_id
,
71 extensions::Action::ACTION_API_CALL
,
73 action
->set_args(args
.Pass());
74 activity_log
->LogAction(action
);
78 // Separate copy of ExtensionAPI used for IO thread extension functions. We need
79 // this because ExtensionAPI has mutable data. It should be possible to remove
80 // this once all the extension APIs are updated to the feature system.
83 : api(extensions::ExtensionAPI::CreateWithDefaultConfiguration()) {
85 scoped_ptr
<extensions::ExtensionAPI
> api
;
87 base::LazyInstance
<Static
> g_global_io_data
= LAZY_INSTANCE_INITIALIZER
;
89 // Kills the specified process because it sends us a malformed message.
90 void KillBadMessageSender(base::ProcessHandle process
) {
92 content::RecordAction(base::UserMetricsAction("BadMessageTerminate_EFD"));
94 base::KillProcess(process
, content::RESULT_CODE_KILLED_BAD_MESSAGE
, false);
97 void CommonResponseCallback(IPC::Sender
* ipc_sender
,
99 base::ProcessHandle peer_process
,
101 ExtensionFunction::ResponseType type
,
102 const base::ListValue
& results
,
103 const std::string
& error
) {
106 if (type
== ExtensionFunction::BAD_MESSAGE
) {
107 // The renderer has done validation before sending extension api requests.
108 // Therefore, we should never receive a request that is invalid in a way
109 // that JSON validation in the renderer should have caught. It could be an
110 // attacker trying to exploit the browser, so we crash the renderer instead.
112 "Terminating renderer because of malformed extension message.";
113 if (content::RenderProcessHost::run_renderer_in_process()) {
114 // In single process mode it is better if we don't suicide but just crash.
117 KillBadMessageSender(peer_process
);
123 ipc_sender
->Send(new ExtensionMsg_Response(
124 routing_id
, request_id
, type
== ExtensionFunction::SUCCEEDED
, results
,
128 void IOThreadResponseCallback(
129 const base::WeakPtr
<ChromeRenderMessageFilter
>& ipc_sender
,
132 ExtensionFunction::ResponseType type
,
133 const base::ListValue
& results
,
134 const std::string
& error
) {
135 if (!ipc_sender
.get())
138 CommonResponseCallback(ipc_sender
.get(),
140 ipc_sender
->PeerHandle(),
149 class ExtensionFunctionDispatcher::UIThreadResponseCallbackWrapper
150 : public content::WebContentsObserver
{
152 UIThreadResponseCallbackWrapper(
153 const base::WeakPtr
<ExtensionFunctionDispatcher
>& dispatcher
,
154 RenderViewHost
* render_view_host
)
155 : content::WebContentsObserver(
156 content::WebContents::FromRenderViewHost(render_view_host
)),
157 dispatcher_(dispatcher
),
158 render_view_host_(render_view_host
),
159 weak_ptr_factory_(this) {
162 virtual ~UIThreadResponseCallbackWrapper() {
165 // content::WebContentsObserver overrides.
166 virtual void RenderViewDeleted(
167 RenderViewHost
* render_view_host
) OVERRIDE
{
168 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
169 if (render_view_host
!= render_view_host_
)
172 if (dispatcher_
.get()) {
173 dispatcher_
->ui_thread_response_callback_wrappers_
174 .erase(render_view_host
);
180 ExtensionFunction::ResponseCallback
CreateCallback(int request_id
) {
182 &UIThreadResponseCallbackWrapper::OnExtensionFunctionCompleted
,
183 weak_ptr_factory_
.GetWeakPtr(),
188 void OnExtensionFunctionCompleted(int request_id
,
189 ExtensionFunction::ResponseType type
,
190 const base::ListValue
& results
,
191 const std::string
& error
) {
192 CommonResponseCallback(
193 render_view_host_
, render_view_host_
->GetRoutingID(),
194 render_view_host_
->GetProcess()->GetHandle(), request_id
, type
,
198 base::WeakPtr
<ExtensionFunctionDispatcher
> dispatcher_
;
199 content::RenderViewHost
* render_view_host_
;
200 base::WeakPtrFactory
<UIThreadResponseCallbackWrapper
> weak_ptr_factory_
;
202 DISALLOW_COPY_AND_ASSIGN(UIThreadResponseCallbackWrapper
);
205 extensions::WindowController
*
206 ExtensionFunctionDispatcher::Delegate::GetExtensionWindowController()
211 content::WebContents
*
212 ExtensionFunctionDispatcher::Delegate::GetAssociatedWebContents() const {
216 content::WebContents
*
217 ExtensionFunctionDispatcher::Delegate::GetVisibleWebContents() const {
218 return GetAssociatedWebContents();
221 void ExtensionFunctionDispatcher::GetAllFunctionNames(
222 std::vector
<std::string
>* names
) {
223 ExtensionFunctionRegistry::GetInstance()->GetAllNames(names
);
226 bool ExtensionFunctionDispatcher::OverrideFunction(
227 const std::string
& name
, ExtensionFunctionFactory factory
) {
228 return ExtensionFunctionRegistry::GetInstance()->OverrideFunction(name
,
232 void ExtensionFunctionDispatcher::ResetFunctions() {
233 ExtensionFunctionRegistry::GetInstance()->ResetFunctions();
237 void ExtensionFunctionDispatcher::DispatchOnIOThread(
238 extensions::InfoMap
* extension_info_map
,
239 void* browser_context
,
240 int render_process_id
,
241 base::WeakPtr
<ChromeRenderMessageFilter
> ipc_sender
,
243 const ExtensionHostMsg_Request_Params
& params
) {
244 const Extension
* extension
=
245 extension_info_map
->extensions().GetByID(params
.extension_id
);
247 ExtensionFunction::ResponseCallback
callback(
248 base::Bind(&IOThreadResponseCallback
, ipc_sender
, routing_id
,
251 scoped_refptr
<ExtensionFunction
> function(
252 CreateExtensionFunction(params
, extension
, render_process_id
,
253 extension_info_map
->process_map(),
254 g_global_io_data
.Get().api
.get(),
255 browser_context
, callback
));
256 scoped_ptr
<base::ListValue
> args(params
.arguments
.DeepCopy());
261 IOThreadExtensionFunction
* function_io
=
262 function
->AsIOThreadExtensionFunction();
267 function_io
->set_ipc_sender(ipc_sender
, routing_id
);
268 function_io
->set_extension_info_map(extension_info_map
);
269 function
->set_include_incognito(
270 extension_info_map
->IsIncognitoEnabled(extension
->id()));
272 if (!CheckPermissions(function
.get(), extension
, params
, callback
))
275 extensions::QuotaService
* quota
= extension_info_map
->GetQuotaService();
276 std::string violation_error
= quota
->Assess(extension
->id(),
279 base::TimeTicks::Now());
280 if (violation_error
.empty()) {
281 LogSuccess(extension
->id(),
284 static_cast<content::BrowserContext
*>(browser_context
));
287 function
->OnQuotaExceeded(violation_error
);
291 ExtensionFunctionDispatcher::ExtensionFunctionDispatcher(
292 content::BrowserContext
* browser_context
,
294 : browser_context_(browser_context
),
295 delegate_(delegate
) {
298 ExtensionFunctionDispatcher::~ExtensionFunctionDispatcher() {
301 void ExtensionFunctionDispatcher::Dispatch(
302 const ExtensionHostMsg_Request_Params
& params
,
303 RenderViewHost
* render_view_host
) {
304 UIThreadResponseCallbackWrapperMap::const_iterator
305 iter
= ui_thread_response_callback_wrappers_
.find(render_view_host
);
306 UIThreadResponseCallbackWrapper
* callback_wrapper
= NULL
;
307 if (iter
== ui_thread_response_callback_wrappers_
.end()) {
308 callback_wrapper
= new UIThreadResponseCallbackWrapper(AsWeakPtr(),
310 ui_thread_response_callback_wrappers_
[render_view_host
] = callback_wrapper
;
312 callback_wrapper
= iter
->second
;
315 DispatchWithCallbackInternal(
316 params
, render_view_host
, NULL
,
317 callback_wrapper
->CreateCallback(params
.request_id
));
320 void ExtensionFunctionDispatcher::DispatchWithCallback(
321 const ExtensionHostMsg_Request_Params
& params
,
322 content::RenderFrameHost
* render_frame_host
,
323 const ExtensionFunction::ResponseCallback
& callback
) {
324 DispatchWithCallbackInternal(params
, NULL
, render_frame_host
, callback
);
327 void ExtensionFunctionDispatcher::DispatchWithCallbackInternal(
328 const ExtensionHostMsg_Request_Params
& params
,
329 RenderViewHost
* render_view_host
,
330 content::RenderFrameHost
* render_frame_host
,
331 const ExtensionFunction::ResponseCallback
& callback
) {
332 DCHECK(render_view_host
|| render_frame_host
);
333 // TODO(yzshen): There is some shared logic between this method and
334 // DispatchOnIOThread(). It is nice to deduplicate.
335 ExtensionSystem
* extension_system
=
336 ExtensionSystem::GetForBrowserContext(browser_context_
);
337 ExtensionService
* service
= extension_system
->extension_service();
338 extensions::ProcessMap
* process_map
=
339 extensions::ProcessMap::Get(browser_context_
);
343 const Extension
* extension
= service
->extensions()->GetByID(
344 params
.extension_id
);
346 extension
= service
->extensions()->GetHostedAppByURL(params
.source_url
);
348 int process_id
= render_view_host
? render_view_host
->GetProcess()->GetID() :
349 render_frame_host
->GetProcess()->GetID();
350 scoped_refptr
<ExtensionFunction
> function(
351 CreateExtensionFunction(params
,
355 extensions::ExtensionAPI::GetSharedInstance(),
358 scoped_ptr
<base::ListValue
> args(params
.arguments
.DeepCopy());
363 UIThreadExtensionFunction
* function_ui
=
364 function
->AsUIThreadExtensionFunction();
369 if (render_view_host
) {
370 function_ui
->SetRenderViewHost(render_view_host
);
372 function_ui
->SetRenderFrameHost(render_frame_host
);
374 function_ui
->set_dispatcher(AsWeakPtr());
375 function_ui
->set_context(browser_context_
);
376 function
->set_include_incognito(extension_util::CanCrossIncognito(extension
,
379 if (!CheckPermissions(function
.get(), extension
, params
, callback
))
382 extensions::QuotaService
* quota
= service
->quota_service();
383 std::string violation_error
= quota
->Assess(extension
->id(),
386 base::TimeTicks::Now());
387 if (violation_error
.empty()) {
388 // See crbug.com/39178.
389 ExternalProtocolHandler::PermitLaunchUrl();
390 LogSuccess(extension
->id(), params
.name
, args
.Pass(), browser_context_
);
393 function
->OnQuotaExceeded(violation_error
);
396 // Note: do not access |this| after this point. We may have been deleted
397 // if function->Run() ended up closing the tab that owns us.
399 // Check if extension was uninstalled by management.uninstall.
400 if (!service
->extensions()->GetByID(params
.extension_id
))
403 // We only adjust the keepalive count for UIThreadExtensionFunction for
404 // now, largely for simplicity's sake. This is OK because currently, only
405 // the webRequest API uses IOThreadExtensionFunction, and that API is not
406 // compatible with lazy background pages.
407 extension_system
->process_manager()->IncrementLazyKeepaliveCount(extension
);
410 void ExtensionFunctionDispatcher::OnExtensionFunctionCompleted(
411 const Extension
* extension
) {
412 ExtensionSystem::GetForBrowserContext(browser_context_
)->process_manager()->
413 DecrementLazyKeepaliveCount(extension
);
417 bool ExtensionFunctionDispatcher::CheckPermissions(
418 ExtensionFunction
* function
,
419 const Extension
* extension
,
420 const ExtensionHostMsg_Request_Params
& params
,
421 const ExtensionFunction::ResponseCallback
& callback
) {
422 if (!function
->HasPermission()) {
423 LOG(ERROR
) << "Extension " << extension
->id() << " does not have "
424 << "permission to function: " << params
.name
;
425 SendAccessDenied(callback
);
433 // Only COMPONENT hosted apps may call extension APIs, and they are limited
434 // to just the permissions they explicitly request. They should not have access
435 // to extension APIs like eg chrome.runtime, chrome.windows, etc. that normally
436 // are available without permission.
437 // TODO(mpcomplete): move this to ExtensionFunction::HasPermission (or remove
439 bool AllowHostedAppAPICall(const Extension
& extension
,
440 const GURL
& source_url
,
441 const std::string
& function_name
) {
442 if (extension
.location() != extensions::Manifest::COMPONENT
)
445 if (!extension
.web_extent().MatchesURL(source_url
))
448 // Note: Not BLESSED_WEB_PAGE_CONTEXT here because these component hosted app
449 // entities have traditionally been treated as blessed extensions, for better
451 Feature::Availability availability
=
452 ExtensionAPI::GetSharedInstance()->IsAvailable(
453 function_name
, &extension
, Feature::BLESSED_EXTENSION_CONTEXT
,
455 return availability
.is_available();
462 ExtensionFunction
* ExtensionFunctionDispatcher::CreateExtensionFunction(
463 const ExtensionHostMsg_Request_Params
& params
,
464 const Extension
* extension
,
465 int requesting_process_id
,
466 const extensions::ProcessMap
& process_map
,
467 extensions::ExtensionAPI
* api
,
469 const ExtensionFunction::ResponseCallback
& callback
) {
471 LOG(ERROR
) << "Specified extension does not exist.";
472 SendAccessDenied(callback
);
476 // Most hosted apps can't call APIs.
478 if (extension
->is_hosted_app())
479 allowed
= AllowHostedAppAPICall(*extension
, params
.source_url
, params
.name
);
481 // Privileged APIs can only be called from the process the extension
483 if (allowed
&& api
->IsPrivileged(params
.name
))
484 allowed
= process_map
.Contains(extension
->id(), requesting_process_id
);
487 LOG(ERROR
) << "Extension API call disallowed - name:" << params
.name
488 << " pid:" << requesting_process_id
489 << " from URL " << params
.source_url
.spec();
490 SendAccessDenied(callback
);
494 ExtensionFunction
* function
=
495 ExtensionFunctionRegistry::GetInstance()->NewFunction(params
.name
);
497 LOG(ERROR
) << "Unknown Extension API - " << params
.name
;
498 SendAccessDenied(callback
);
502 function
->SetArgs(¶ms
.arguments
);
503 function
->set_source_url(params
.source_url
);
504 function
->set_request_id(params
.request_id
);
505 function
->set_has_callback(params
.has_callback
);
506 function
->set_user_gesture(params
.user_gesture
);
507 function
->set_extension(extension
);
508 function
->set_profile_id(profile
);
509 function
->set_response_callback(callback
);
515 void ExtensionFunctionDispatcher::SendAccessDenied(
516 const ExtensionFunction::ResponseCallback
& callback
) {
517 base::ListValue empty_list
;
518 callback
.Run(ExtensionFunction::FAILED
, empty_list
,
519 "Access to extension API denied.");