OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 "webkit/plugins/npapi/webplugin_delegate_impl.h" | 5 #include "webkit/plugins/npapi/webplugin_delegate_impl.h" |
6 | 6 |
7 #include <map> | 7 #include <map> |
8 #include <string> | 8 #include <string> |
9 #include <vector> | 9 #include <vector> |
10 | 10 |
(...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
138 base::LazyInstance<base::win::IATPatchFunction> g_iat_patch_virtual_free = | 138 base::LazyInstance<base::win::IATPatchFunction> g_iat_patch_virtual_free = |
139 LAZY_INSTANCE_INITIALIZER; | 139 LAZY_INSTANCE_INITIALIZER; |
140 BOOL (WINAPI *g_iat_orig_virtual_free)(LPVOID address, | 140 BOOL (WINAPI *g_iat_orig_virtual_free)(LPVOID address, |
141 SIZE_T size, | 141 SIZE_T size, |
142 DWORD free_type); | 142 DWORD free_type); |
143 | 143 |
144 const DWORD kExecPageMask = PAGE_EXECUTE_READ; | 144 const DWORD kExecPageMask = PAGE_EXECUTE_READ; |
145 static volatile intptr_t g_max_exec_mem_size; | 145 static volatile intptr_t g_max_exec_mem_size; |
146 static scoped_ptr<base::Lock> g_exec_mem_lock; | 146 static scoped_ptr<base::Lock> g_exec_mem_lock; |
147 | 147 |
148 bool UpdateExecMemSize(intptr_t size) { | 148 void UpdateExecMemSize(intptr_t size) { |
149 base::AutoLock locked(*g_exec_mem_lock); | 149 base::AutoLock locked(*g_exec_mem_lock); |
150 | 150 |
151 const intptr_t kMaxPluginExecMemSizeSpike = 80 * 1024 * 1024; // 80mb. | |
152 const DWORD kTimeLimit = 6; // 6 minute timeout. | |
153 | |
154 static intptr_t s_exec_mem_size = 0; | 151 static intptr_t s_exec_mem_size = 0; |
155 static intptr_t s_exec_mem_size_old = 0; | |
156 static struct { | |
157 intptr_t size; | |
158 DWORD minutes; | |
159 } s_exec_mem_log[kTimeLimit]; | |
160 static size_t s_old_idx; | |
161 static size_t s_now_idx; | |
162 | |
163 DWORD now = ::GetTickCount() / (60 * 1000); | |
164 | |
165 // Keep the size change history. This is done using a ring of entries with | |
166 // with the size and tick count | |
167 if (s_exec_mem_log[s_now_idx].minutes == now) { | |
168 s_exec_mem_log[s_now_idx].size += size; | |
169 } else { | |
170 // Move the index forward and clear the old entry if needed. | |
171 s_now_idx = (s_now_idx + 1) % kTimeLimit; | |
172 if (s_now_idx == s_old_idx) { | |
173 s_exec_mem_size_old = std::max(0, s_exec_mem_log[s_old_idx].size + | |
174 s_exec_mem_size_old); | |
175 ++s_old_idx; | |
176 } | |
177 s_exec_mem_log[s_now_idx].minutes = now; | |
178 s_exec_mem_log[s_now_idx].size = size; | |
179 | |
180 // Expire any waiting old entries. | |
181 for (; s_old_idx != s_now_idx; s_old_idx = (s_old_idx + 1) % kTimeLimit) { | |
182 DWORD minutes = s_exec_mem_log[s_old_idx].minutes; | |
183 if (now - minutes < kTimeLimit) | |
184 break; | |
185 s_exec_mem_size_old = std::max(0, s_exec_mem_log[s_old_idx].size + | |
186 s_exec_mem_size_old); | |
187 } | |
188 } | |
189 | 152 |
190 // Floor to zero since shutdown may unmap pages created before our hooks. | 153 // Floor to zero since shutdown may unmap pages created before our hooks. |
191 s_exec_mem_size = std::max(0, s_exec_mem_size + size); | 154 s_exec_mem_size = std::max(0, s_exec_mem_size + size); |
192 if (s_exec_mem_size > g_max_exec_mem_size) | 155 if (s_exec_mem_size > g_max_exec_mem_size) |
193 g_max_exec_mem_size = s_exec_mem_size; | 156 g_max_exec_mem_size = s_exec_mem_size; |
194 | |
195 | |
196 if ((s_exec_mem_size - s_exec_mem_size_old) > kMaxPluginExecMemSizeSpike) | |
197 return false; | |
198 | |
199 return true; | |
200 } | |
201 | |
202 // Throw a unique exception when the JIT limit is hit. | |
203 inline void RaiseJITException() { | |
204 static const ULONG parameters[] = {1, 0xabad1dea /* 2880249322 */ }; | |
205 ::RaiseException(EXCEPTION_ACCESS_VIOLATION, EXCEPTION_NONCONTINUABLE, | |
206 arraysize(parameters), parameters); | |
207 } | 157 } |
208 | 158 |
209 // http://crbug.com/16114 | 159 // http://crbug.com/16114 |
210 // Enforces providing a valid device context in NPWindow, so that NPP_SetWindow | 160 // Enforces providing a valid device context in NPWindow, so that NPP_SetWindow |
211 // is never called with NPNWindoTypeDrawable and NPWindow set to NULL. | 161 // is never called with NPNWindoTypeDrawable and NPWindow set to NULL. |
212 // Doing so allows removing NPP_SetWindow call during painting a windowless | 162 // Doing so allows removing NPP_SetWindow call during painting a windowless |
213 // plugin, which otherwise could trigger layout change while painting by | 163 // plugin, which otherwise could trigger layout change while painting by |
214 // invoking NPN_Evaluate. Which would cause bad, bad crashes. Bad crashes. | 164 // invoking NPN_Evaluate. Which would cause bad, bad crashes. Bad crashes. |
215 // TODO(dglazkov): If this approach doesn't produce regressions, move class to | 165 // TODO(dglazkov): If this approach doesn't produce regressions, move class to |
216 // webplugin_delegate_impl.h and implement for other platforms. | 166 // webplugin_delegate_impl.h and implement for other platforms. |
(...skipping 172 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
389 // We need to track RX memory usage in plugins to prevent JIT spraying attacks. | 339 // We need to track RX memory usage in plugins to prevent JIT spraying attacks. |
390 // This is done by hooking VirtualProtect and VirtualFree. | 340 // This is done by hooking VirtualProtect and VirtualFree. |
391 BOOL WINAPI WebPluginDelegateImpl::VirtualProtectPatch(LPVOID address, | 341 BOOL WINAPI WebPluginDelegateImpl::VirtualProtectPatch(LPVOID address, |
392 SIZE_T size, | 342 SIZE_T size, |
393 DWORD new_protect, | 343 DWORD new_protect, |
394 PDWORD old_protect) { | 344 PDWORD old_protect) { |
395 if (g_iat_orig_virtual_protect(address, size, new_protect, old_protect)) { | 345 if (g_iat_orig_virtual_protect(address, size, new_protect, old_protect)) { |
396 bool is_exec = new_protect == kExecPageMask; | 346 bool is_exec = new_protect == kExecPageMask; |
397 bool was_exec = *old_protect == kExecPageMask; | 347 bool was_exec = *old_protect == kExecPageMask; |
398 if (is_exec && !was_exec) { | 348 if (is_exec && !was_exec) { |
399 if (!UpdateExecMemSize(static_cast<intptr_t>(size))) | 349 UpdateExecMemSize(static_cast<intptr_t>(size)); |
400 RaiseJITException(); | |
401 } else if (!is_exec && was_exec) { | 350 } else if (!is_exec && was_exec) { |
402 UpdateExecMemSize(-(static_cast<intptr_t>(size))); | 351 UpdateExecMemSize(-(static_cast<intptr_t>(size))); |
403 } | 352 } |
404 | 353 |
405 return TRUE; | 354 return TRUE; |
406 } | 355 } |
407 | 356 |
408 return FALSE; | 357 return FALSE; |
409 } | 358 } |
410 | 359 |
(...skipping 1304 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1715 ::ReleaseCapture(); | 1664 ::ReleaseCapture(); |
1716 break; | 1665 break; |
1717 | 1666 |
1718 default: | 1667 default: |
1719 break; | 1668 break; |
1720 } | 1669 } |
1721 } | 1670 } |
1722 | 1671 |
1723 } // namespace npapi | 1672 } // namespace npapi |
1724 } // namespace webkit | 1673 } // namespace webkit |
OLD | NEW |