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 |