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                                              &params.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                                              &params.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(&params.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