| 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 |