Home | History | Annotate | Download | only in browser
      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.
     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 {
     77   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.
     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 
     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 
    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:
    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 
    198 WindowController*
    199 ExtensionFunctionDispatcher::Delegate::GetExtensionWindowController() const {
    200   return NULL;
    201 }
    202 
    203 content::WebContents*
    204 ExtensionFunctionDispatcher::Delegate::GetAssociatedWebContents() const {
    205   return NULL;
    206 }
    207 
    208 content::WebContents*
    209 ExtensionFunctionDispatcher::Delegate::GetVisibleWebContents() const {
    210   return GetAssociatedWebContents();
    211 }
    212 
    213 void ExtensionFunctionDispatcher::GetAllFunctionNames(
    214     std::vector<std::string>* names) {
    215   ExtensionFunctionRegistry::GetInstance()->GetAllNames(names);
    216 }
    217 
    218 bool ExtensionFunctionDispatcher::OverrideFunction(
    219     const std::string& name, ExtensionFunctionFactory factory) {
    220   return ExtensionFunctionRegistry::GetInstance()->OverrideFunction(name,
    221                                                                     factory);
    222 }
    223 
    224 // static
    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                                               &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 
    283 ExtensionFunctionDispatcher::ExtensionFunctionDispatcher(
    284     content::BrowserContext* browser_context,
    285     Delegate* delegate)
    286     : browser_context_(browser_context),
    287       delegate_(delegate) {
    288 }
    289 
    290 ExtensionFunctionDispatcher::~ExtensionFunctionDispatcher() {
    291 }
    292 
    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 
    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 
    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                                               &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 
    406 void ExtensionFunctionDispatcher::OnExtensionFunctionCompleted(
    407     const Extension* extension) {
    408   ExtensionSystem::Get(browser_context_)->process_manager()->
    409       DecrementLazyKeepaliveCount(extension);
    410 }
    411 
    412 // static
    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).
    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
    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(&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
    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