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