| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "extensions/browser/extension_function_dispatcher.h" | 5 #include "extensions/browser/extension_function_dispatcher.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/json/json_string_value_serializer.h" | 8 #include "base/json/json_string_value_serializer.h" |
| 9 #include "base/lazy_instance.h" | 9 #include "base/lazy_instance.h" |
| 10 #include "base/logging.h" | 10 #include "base/logging.h" |
| 11 #include "base/memory/ref_counted.h" | 11 #include "base/memory/ref_counted.h" |
| 12 #include "base/metrics/histogram_macros.h" |
| 12 #include "base/metrics/sparse_histogram.h" | 13 #include "base/metrics/sparse_histogram.h" |
| 13 #include "base/process/process.h" | 14 #include "base/process/process.h" |
| 14 #include "base/profiler/scoped_profile.h" | 15 #include "base/profiler/scoped_profile.h" |
| 15 #include "base/values.h" | 16 #include "base/values.h" |
| 16 #include "build/build_config.h" | 17 #include "build/build_config.h" |
| 17 #include "content/public/browser/browser_thread.h" | 18 #include "content/public/browser/browser_thread.h" |
| 18 #include "content/public/browser/render_frame_host.h" | 19 #include "content/public/browser/render_frame_host.h" |
| 19 #include "content/public/browser/render_process_host.h" | 20 #include "content/public/browser/render_process_host.h" |
| 20 #include "content/public/browser/render_view_host.h" | 21 #include "content/public/browser/render_view_host.h" |
| 21 #include "content/public/browser/user_metrics.h" | 22 #include "content/public/browser/user_metrics.h" |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 74 // Separate copy of ExtensionAPI used for IO thread extension functions. We need | 75 // Separate copy of ExtensionAPI used for IO thread extension functions. We need |
| 75 // this because ExtensionAPI has mutable data. It should be possible to remove | 76 // this because ExtensionAPI has mutable data. It should be possible to remove |
| 76 // this once all the extension APIs are updated to the feature system. | 77 // this once all the extension APIs are updated to the feature system. |
| 77 struct Static { | 78 struct Static { |
| 78 Static() : api(ExtensionAPI::CreateWithDefaultConfiguration()) {} | 79 Static() : api(ExtensionAPI::CreateWithDefaultConfiguration()) {} |
| 79 scoped_ptr<ExtensionAPI> api; | 80 scoped_ptr<ExtensionAPI> api; |
| 80 }; | 81 }; |
| 81 base::LazyInstance<Static> g_global_io_data = LAZY_INSTANCE_INITIALIZER; | 82 base::LazyInstance<Static> g_global_io_data = LAZY_INSTANCE_INITIALIZER; |
| 82 | 83 |
| 83 // Kills the specified process because it sends us a malformed message. | 84 // Kills the specified process because it sends us a malformed message. |
| 84 void KillBadMessageSender(base::ProcessHandle process) { | 85 // Track the specific function's |histogram_value|, as this may indicate a bug |
| 86 // in that API's implementation on the renderer. |
| 87 void KillBadMessageSender(base::ProcessHandle process, |
| 88 functions::HistogramValue histogram_value) { |
| 85 NOTREACHED(); | 89 NOTREACHED(); |
| 86 content::RecordAction(base::UserMetricsAction("BadMessageTerminate_EFD")); | 90 content::RecordAction(base::UserMetricsAction("BadMessageTerminate_EFD")); |
| 91 UMA_HISTOGRAM_ENUMERATION("Extensions.BadMessageFunctionName", |
| 92 histogram_value, functions::ENUM_BOUNDARY); |
| 87 if (process) | 93 if (process) |
| 88 base::KillProcess(process, content::RESULT_CODE_KILLED_BAD_MESSAGE, false); | 94 base::KillProcess(process, content::RESULT_CODE_KILLED_BAD_MESSAGE, false); |
| 89 } | 95 } |
| 90 | 96 |
| 91 void CommonResponseCallback(IPC::Sender* ipc_sender, | 97 void CommonResponseCallback(IPC::Sender* ipc_sender, |
| 92 int routing_id, | 98 int routing_id, |
| 93 base::ProcessHandle peer_process, | 99 base::ProcessHandle peer_process, |
| 94 int request_id, | 100 int request_id, |
| 95 ExtensionFunction::ResponseType type, | 101 ExtensionFunction::ResponseType type, |
| 96 const base::ListValue& results, | 102 const base::ListValue& results, |
| 97 const std::string& error) { | 103 const std::string& error, |
| 104 functions::HistogramValue histogram_value) { |
| 98 DCHECK(ipc_sender); | 105 DCHECK(ipc_sender); |
| 99 | 106 |
| 100 if (type == ExtensionFunction::BAD_MESSAGE) { | 107 if (type == ExtensionFunction::BAD_MESSAGE) { |
| 101 // The renderer has done validation before sending extension api requests. | 108 // The renderer has done validation before sending extension api requests. |
| 102 // Therefore, we should never receive a request that is invalid in a way | 109 // Therefore, we should never receive a request that is invalid in a way |
| 103 // that JSON validation in the renderer should have caught. It could be an | 110 // that JSON validation in the renderer should have caught. It could be an |
| 104 // attacker trying to exploit the browser, so we crash the renderer instead. | 111 // attacker trying to exploit the browser, so we crash the renderer instead. |
| 105 LOG(ERROR) << | 112 LOG(ERROR) << |
| 106 "Terminating renderer because of malformed extension message."; | 113 "Terminating renderer because of malformed extension message."; |
| 107 if (content::RenderProcessHost::run_renderer_in_process()) { | 114 if (content::RenderProcessHost::run_renderer_in_process()) { |
| 108 // In single process mode it is better if we don't suicide but just crash. | 115 // In single process mode it is better if we don't suicide but just crash. |
| 109 CHECK(false); | 116 CHECK(false); |
| 110 } else { | 117 } else { |
| 111 KillBadMessageSender(peer_process); | 118 KillBadMessageSender(peer_process, histogram_value); |
| 112 } | 119 } |
| 113 | |
| 114 return; | 120 return; |
| 115 } | 121 } |
| 116 | 122 |
| 117 ipc_sender->Send(new ExtensionMsg_Response( | 123 ipc_sender->Send(new ExtensionMsg_Response( |
| 118 routing_id, request_id, type == ExtensionFunction::SUCCEEDED, results, | 124 routing_id, request_id, type == ExtensionFunction::SUCCEEDED, results, |
| 119 error)); | 125 error)); |
| 120 } | 126 } |
| 121 | 127 |
| 122 void IOThreadResponseCallback( | 128 void IOThreadResponseCallback( |
| 123 const base::WeakPtr<IOThreadExtensionMessageFilter>& ipc_sender, | 129 const base::WeakPtr<IOThreadExtensionMessageFilter>& ipc_sender, |
| 124 int routing_id, | 130 int routing_id, |
| 125 int request_id, | 131 int request_id, |
| 126 ExtensionFunction::ResponseType type, | 132 ExtensionFunction::ResponseType type, |
| 127 const base::ListValue& results, | 133 const base::ListValue& results, |
| 128 const std::string& error) { | 134 const std::string& error, |
| 135 functions::HistogramValue histogram_value) { |
| 129 if (!ipc_sender.get()) | 136 if (!ipc_sender.get()) |
| 130 return; | 137 return; |
| 131 | 138 |
| 132 CommonResponseCallback(ipc_sender.get(), | 139 CommonResponseCallback(ipc_sender.get(), routing_id, ipc_sender->PeerHandle(), |
| 133 routing_id, | 140 request_id, type, results, error, histogram_value); |
| 134 ipc_sender->PeerHandle(), | |
| 135 request_id, | |
| 136 type, | |
| 137 results, | |
| 138 error); | |
| 139 } | 141 } |
| 140 | 142 |
| 141 } // namespace | 143 } // namespace |
| 142 | 144 |
| 143 class ExtensionFunctionDispatcher::UIThreadResponseCallbackWrapper | 145 class ExtensionFunctionDispatcher::UIThreadResponseCallbackWrapper |
| 144 : public content::WebContentsObserver { | 146 : public content::WebContentsObserver { |
| 145 public: | 147 public: |
| 146 UIThreadResponseCallbackWrapper( | 148 UIThreadResponseCallbackWrapper( |
| 147 const base::WeakPtr<ExtensionFunctionDispatcher>& dispatcher, | 149 const base::WeakPtr<ExtensionFunctionDispatcher>& dispatcher, |
| 148 RenderViewHost* render_view_host) | 150 RenderViewHost* render_view_host) |
| (...skipping 24 matching lines...) Expand all Loading... |
| 173 return base::Bind( | 175 return base::Bind( |
| 174 &UIThreadResponseCallbackWrapper::OnExtensionFunctionCompleted, | 176 &UIThreadResponseCallbackWrapper::OnExtensionFunctionCompleted, |
| 175 weak_ptr_factory_.GetWeakPtr(), | 177 weak_ptr_factory_.GetWeakPtr(), |
| 176 request_id); | 178 request_id); |
| 177 } | 179 } |
| 178 | 180 |
| 179 private: | 181 private: |
| 180 void OnExtensionFunctionCompleted(int request_id, | 182 void OnExtensionFunctionCompleted(int request_id, |
| 181 ExtensionFunction::ResponseType type, | 183 ExtensionFunction::ResponseType type, |
| 182 const base::ListValue& results, | 184 const base::ListValue& results, |
| 183 const std::string& error) { | 185 const std::string& error, |
| 184 CommonResponseCallback( | 186 functions::HistogramValue histogram_value) { |
| 185 render_view_host_, render_view_host_->GetRoutingID(), | 187 CommonResponseCallback(render_view_host_, render_view_host_->GetRoutingID(), |
| 186 render_view_host_->GetProcess()->GetHandle(), request_id, type, | 188 render_view_host_->GetProcess()->GetHandle(), |
| 187 results, error); | 189 request_id, type, results, error, histogram_value); |
| 188 } | 190 } |
| 189 | 191 |
| 190 base::WeakPtr<ExtensionFunctionDispatcher> dispatcher_; | 192 base::WeakPtr<ExtensionFunctionDispatcher> dispatcher_; |
| 191 content::RenderViewHost* render_view_host_; | 193 content::RenderViewHost* render_view_host_; |
| 192 base::WeakPtrFactory<UIThreadResponseCallbackWrapper> weak_ptr_factory_; | 194 base::WeakPtrFactory<UIThreadResponseCallbackWrapper> weak_ptr_factory_; |
| 193 | 195 |
| 194 DISALLOW_COPY_AND_ASSIGN(UIThreadResponseCallbackWrapper); | 196 DISALLOW_COPY_AND_ASSIGN(UIThreadResponseCallbackWrapper); |
| 195 }; | 197 }; |
| 196 | 198 |
| 197 WindowController* | 199 WindowController* |
| (...skipping 233 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 431 } | 433 } |
| 432 } | 434 } |
| 433 | 435 |
| 434 // static | 436 // static |
| 435 bool ExtensionFunctionDispatcher::CheckPermissions( | 437 bool ExtensionFunctionDispatcher::CheckPermissions( |
| 436 ExtensionFunction* function, | 438 ExtensionFunction* function, |
| 437 const ExtensionHostMsg_Request_Params& params, | 439 const ExtensionHostMsg_Request_Params& params, |
| 438 const ExtensionFunction::ResponseCallback& callback) { | 440 const ExtensionFunction::ResponseCallback& callback) { |
| 439 if (!function->HasPermission()) { | 441 if (!function->HasPermission()) { |
| 440 LOG(ERROR) << "Permission denied for " << params.name; | 442 LOG(ERROR) << "Permission denied for " << params.name; |
| 441 SendAccessDenied(callback); | 443 SendAccessDenied(callback, function->histogram_value()); |
| 442 return false; | 444 return false; |
| 443 } | 445 } |
| 444 return true; | 446 return true; |
| 445 } | 447 } |
| 446 | 448 |
| 447 // static | 449 // static |
| 448 ExtensionFunction* ExtensionFunctionDispatcher::CreateExtensionFunction( | 450 ExtensionFunction* ExtensionFunctionDispatcher::CreateExtensionFunction( |
| 449 const ExtensionHostMsg_Request_Params& params, | 451 const ExtensionHostMsg_Request_Params& params, |
| 450 const Extension* extension, | 452 const Extension* extension, |
| 451 int requesting_process_id, | 453 int requesting_process_id, |
| 452 const ProcessMap& process_map, | 454 const ProcessMap& process_map, |
| 453 ExtensionAPI* api, | 455 ExtensionAPI* api, |
| 454 void* profile_id, | 456 void* profile_id, |
| 455 const ExtensionFunction::ResponseCallback& callback) { | 457 const ExtensionFunction::ResponseCallback& callback) { |
| 456 ExtensionFunction* function = | 458 ExtensionFunction* function = |
| 457 ExtensionFunctionRegistry::GetInstance()->NewFunction(params.name); | 459 ExtensionFunctionRegistry::GetInstance()->NewFunction(params.name); |
| 458 if (!function) { | 460 if (!function) { |
| 459 LOG(ERROR) << "Unknown Extension API - " << params.name; | 461 LOG(ERROR) << "Unknown Extension API - " << params.name; |
| 460 SendAccessDenied(callback); | 462 SendAccessDenied(callback, function->histogram_value()); |
| 461 return NULL; | 463 return NULL; |
| 462 } | 464 } |
| 463 | 465 |
| 464 function->SetArgs(¶ms.arguments); | 466 function->SetArgs(¶ms.arguments); |
| 465 function->set_source_url(params.source_url); | 467 function->set_source_url(params.source_url); |
| 466 function->set_request_id(params.request_id); | 468 function->set_request_id(params.request_id); |
| 467 function->set_has_callback(params.has_callback); | 469 function->set_has_callback(params.has_callback); |
| 468 function->set_user_gesture(params.user_gesture); | 470 function->set_user_gesture(params.user_gesture); |
| 469 function->set_extension(extension); | 471 function->set_extension(extension); |
| 470 function->set_profile_id(profile_id); | 472 function->set_profile_id(profile_id); |
| 471 function->set_response_callback(callback); | 473 function->set_response_callback(callback); |
| 472 function->set_source_tab_id(params.source_tab_id); | 474 function->set_source_tab_id(params.source_tab_id); |
| 473 function->set_source_context_type( | 475 function->set_source_context_type( |
| 474 process_map.GetMostLikelyContextType(extension, requesting_process_id)); | 476 process_map.GetMostLikelyContextType(extension, requesting_process_id)); |
| 475 | 477 |
| 476 return function; | 478 return function; |
| 477 } | 479 } |
| 478 | 480 |
| 479 // static | 481 // static |
| 480 void ExtensionFunctionDispatcher::SendAccessDenied( | 482 void ExtensionFunctionDispatcher::SendAccessDenied( |
| 481 const ExtensionFunction::ResponseCallback& callback) { | 483 const ExtensionFunction::ResponseCallback& callback, |
| 484 functions::HistogramValue histogram_value) { |
| 482 base::ListValue empty_list; | 485 base::ListValue empty_list; |
| 483 callback.Run(ExtensionFunction::FAILED, empty_list, | 486 callback.Run(ExtensionFunction::FAILED, empty_list, |
| 484 "Access to extension API denied."); | 487 "Access to extension API denied.", histogram_value); |
| 485 } | 488 } |
| 486 | 489 |
| 487 } // namespace extensions | 490 } // namespace extensions |
| OLD | NEW |