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.
NotifyApiFunctionCalled(const std::string & extension_id,const std::string & api_name,scoped_ptr<base::ListValue> args,content::BrowserContext * browser_context)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 {
Staticextensions::__anon28bfc87d0111::Static77 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.
KillBadMessageSender(base::ProcessHandle process)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
CommonResponseCallback(IPC::Sender * ipc_sender,int routing_id,base::ProcessHandle peer_process,int request_id,ExtensionFunction::ResponseType type,const base::ListValue & results,const std::string & error)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
IOThreadResponseCallback(const base::WeakPtr<ExtensionMessageFilter> & ipc_sender,int routing_id,int request_id,ExtensionFunction::ResponseType type,const base::ListValue & results,const std::string & error)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:
UIThreadResponseCallbackWrapper(const base::WeakPtr<ExtensionFunctionDispatcher> & dispatcher,RenderViewHost * render_view_host)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
~UIThreadResponseCallbackWrapper()155 virtual ~UIThreadResponseCallbackWrapper() {
156 }
157
158 // content::WebContentsObserver overrides.
RenderViewDeleted(RenderViewHost * render_view_host)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
CreateCallback(int request_id)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:
OnExtensionFunctionCompleted(int request_id,ExtensionFunction::ResponseType type,const base::ListValue & results,const std::string & error)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*
GetExtensionWindowController() const199 ExtensionFunctionDispatcher::Delegate::GetExtensionWindowController() const {
200 return NULL;
201 }
202
203 content::WebContents*
GetAssociatedWebContents() const204 ExtensionFunctionDispatcher::Delegate::GetAssociatedWebContents() const {
205 return NULL;
206 }
207
208 content::WebContents*
GetVisibleWebContents() const209 ExtensionFunctionDispatcher::Delegate::GetVisibleWebContents() const {
210 return GetAssociatedWebContents();
211 }
212
GetAllFunctionNames(std::vector<std::string> * names)213 void ExtensionFunctionDispatcher::GetAllFunctionNames(
214 std::vector<std::string>* names) {
215 ExtensionFunctionRegistry::GetInstance()->GetAllNames(names);
216 }
217
OverrideFunction(const std::string & name,ExtensionFunctionFactory factory)218 bool ExtensionFunctionDispatcher::OverrideFunction(
219 const std::string& name, ExtensionFunctionFactory factory) {
220 return ExtensionFunctionRegistry::GetInstance()->OverrideFunction(name,
221 factory);
222 }
223
224 // static
DispatchOnIOThread(InfoMap * extension_info_map,void * profile_id,int render_process_id,base::WeakPtr<ExtensionMessageFilter> ipc_sender,int routing_id,const ExtensionHostMsg_Request_Params & params)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
ExtensionFunctionDispatcher(content::BrowserContext * browser_context,Delegate * delegate)283 ExtensionFunctionDispatcher::ExtensionFunctionDispatcher(
284 content::BrowserContext* browser_context,
285 Delegate* delegate)
286 : browser_context_(browser_context),
287 delegate_(delegate) {
288 }
289
~ExtensionFunctionDispatcher()290 ExtensionFunctionDispatcher::~ExtensionFunctionDispatcher() {
291 }
292
Dispatch(const ExtensionHostMsg_Request_Params & params,RenderViewHost * render_view_host)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
DispatchWithCallback(const ExtensionHostMsg_Request_Params & params,content::RenderFrameHost * render_frame_host,const ExtensionFunction::ResponseCallback & callback)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
DispatchWithCallbackInternal(const ExtensionHostMsg_Request_Params & params,RenderViewHost * render_view_host,content::RenderFrameHost * render_frame_host,const ExtensionFunction::ResponseCallback & 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_);
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
OnExtensionFunctionCompleted(const Extension * extension)406 void ExtensionFunctionDispatcher::OnExtensionFunctionCompleted(
407 const Extension* extension) {
408 ExtensionSystem::Get(browser_context_)->process_manager()->
409 DecrementLazyKeepaliveCount(extension);
410 }
411
412 // static
CheckPermissions(ExtensionFunction * function,const Extension * extension,const ExtensionHostMsg_Request_Params & params,const ExtensionFunction::ResponseCallback & callback)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).
AllowHostedAppAPICall(const Extension & extension,const GURL & source_url,const std::string & function_name)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
CreateExtensionFunction(const ExtensionHostMsg_Request_Params & params,const Extension * extension,int requesting_process_id,const ProcessMap & process_map,ExtensionAPI * api,void * profile_id,const ExtensionFunction::ResponseCallback & callback)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
SendAccessDenied(const ExtensionFunction::ResponseCallback & callback)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