summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--content/plugin/plugin_main.cc16
-rw-r--r--webkit/plugins/npapi/webplugin_delegate_impl_win.cc73
2 files changed, 65 insertions, 24 deletions
diff --git a/content/plugin/plugin_main.cc b/content/plugin/plugin_main.cc
index 4f4f402..2e7f4ea 100644
--- a/content/plugin/plugin_main.cc
+++ b/content/plugin/plugin_main.cc
@@ -84,10 +84,10 @@ void FreeRandomMemoryHole(void *hole) {
}
bool CreateRandomMemoryHole() {
- static const uint32_t kRandomValueMask = 0xFFF; // 4095
- static const uint32_t kRandomValueShift = 2;
- static const uint32_t kMaxWaitSeconds = 22 * 60; // 22 Minutes in seconds.
- COMPILE_ASSERT((kMaxWaitSeconds > (kRandomValueMask >> kRandomValueShift)),
+ const uint32_t kRandomValueMax = 8 * 1024; // Yields a 512mb max hole.
+ const uint32_t kRandomValueDivisor = 8;
+ const uint32_t kMaxWaitSeconds = 18 * 60; // 18 Minutes in seconds.
+ COMPILE_ASSERT((kMaxWaitSeconds > (kRandomValueMax / kRandomValueDivisor)),
kMaxWaitSeconds_value_too_small);
uint32_t rand_val;
@@ -95,14 +95,14 @@ bool CreateRandomMemoryHole() {
DVLOG(ERROR) << "rand_s() failed";
}
- rand_val &= kRandomValueMask;
- // Reserve up to 256mb (randomly selected) of address space.
+ rand_val %= kRandomValueMax;
+ // Reserve a (randomly selected) range of address space.
if (void* hole = ::VirtualAlloc(NULL, 65536 * (1 + rand_val),
MEM_RESERVE, PAGE_NOACCESS)) {
// Set up an event to remove the memory hole. Base the wait time on the
// inverse of the allocation size, meaning a bigger hole gets a shorter
- // wait (ranging from 5-22 minutes).
- const uint32_t wait = kMaxWaitSeconds - (rand_val >> kRandomValueShift);
+ // wait (ranging from 1-18 minutes).
+ const uint32_t wait = kMaxWaitSeconds - (rand_val / kRandomValueDivisor);
MessageLoop::current()->PostDelayedTask(FROM_HERE,
base::Bind(&FreeRandomMemoryHole, hole),
base::TimeDelta::FromSeconds(wait));
diff --git a/webkit/plugins/npapi/webplugin_delegate_impl_win.cc b/webkit/plugins/npapi/webplugin_delegate_impl_win.cc
index ffbc56f..d7b2bb0 100644
--- a/webkit/plugins/npapi/webplugin_delegate_impl_win.cc
+++ b/webkit/plugins/npapi/webplugin_delegate_impl_win.cc
@@ -141,29 +141,72 @@ BOOL (WINAPI *g_iat_orig_virtual_free)(LPVOID address,
SIZE_T size,
DWORD free_type);
-const size_t kMaxPluginExecMemSize = 32 * 1024 * 1024; // 32mb.
const DWORD kExecPageMask = PAGE_EXECUTE_READ;
static volatile intptr_t g_max_exec_mem_size;
-static intptr_t g_exec_mem_size = 0;
static scoped_ptr<base::Lock> g_exec_mem_lock;
-size_t UpdateExecMemSize(intptr_t size) {
+bool UpdateExecMemSize(intptr_t size) {
base::AutoLock locked(*g_exec_mem_lock);
- g_exec_mem_size += size;
+
+ const intptr_t kMaxPluginExecMemSize = 128 * 1024 * 1024; // 128mb.
+ const intptr_t kMaxPluginExecMemSizeSpike = 64 * 1024 * 1024; // 64mb.
+ const DWORD kTimeLimit = 8; // 8 minute timeout.
+
+ static intptr_t s_exec_mem_size = 0;
+ static intptr_t s_exec_mem_size_old = 0;
+ static struct {
+ intptr_t size;
+ DWORD minutes;
+ } s_exec_mem_log[kTimeLimit];
+ static size_t s_old_idx;
+ static size_t s_now_idx;
+
+ DWORD now = ::GetTickCount() / (60 * 1000);
+
+ // Keep the size change history. This is done using a ring of entries with
+ // with the size and tick count
+ if (s_exec_mem_log[s_now_idx].minutes == now) {
+ s_exec_mem_log[s_now_idx].size += size;
+ } else {
+ // Move the index forward and clear the old entry if needed.
+ s_now_idx = (s_now_idx + 1) % kTimeLimit;
+ if (s_now_idx == s_old_idx) {
+ s_exec_mem_size_old = std::max(0, s_exec_mem_log[s_old_idx].size +
+ s_exec_mem_size_old);
+ ++s_old_idx;
+ }
+ s_exec_mem_log[s_now_idx].minutes = now;
+ s_exec_mem_log[s_now_idx].size = size;
+
+ // Expire any waiting old entries.
+ for (; s_old_idx != s_now_idx; s_old_idx = (s_old_idx + 1) % kTimeLimit) {
+ DWORD minutes = s_exec_mem_log[s_old_idx].minutes;
+ if (now - minutes < kTimeLimit)
+ break;
+ s_exec_mem_size_old = std::max(0, s_exec_mem_log[s_old_idx].size +
+ s_exec_mem_size_old);
+ }
+ }
+
// Floor to zero since shutdown may unmap pages created before our hooks.
- if (g_exec_mem_size < 0)
- g_exec_mem_size = 0;
- if (g_exec_mem_size > g_max_exec_mem_size)
- g_max_exec_mem_size = g_exec_mem_size;
+ s_exec_mem_size = std::max(0, s_exec_mem_size + size);
+ if (s_exec_mem_size > g_max_exec_mem_size)
+ g_max_exec_mem_size = s_exec_mem_size;
+
+
+ if (s_exec_mem_size > kMaxPluginExecMemSize)
+ return false;
+ if ((s_exec_mem_size - s_exec_mem_size_old) > kMaxPluginExecMemSizeSpike)
+ return false;
- return g_exec_mem_size;
+ return true;
}
// Throw a unique exception when the JIT limit is hit.
inline void RaiseJITException() {
static const ULONG parameters[] = {1, 0xabad1dea /* 2880249322 */ };
::RaiseException(EXCEPTION_ACCESS_VIOLATION, EXCEPTION_NONCONTINUABLE,
- 2, parameters);
+ arraysize(parameters), parameters);
}
// http://crbug.com/16114
@@ -353,12 +396,10 @@ BOOL WINAPI WebPluginDelegateImpl::VirtualProtectPatch(LPVOID address,
DWORD new_protect,
PDWORD old_protect) {
if (g_iat_orig_virtual_protect(address, size, new_protect, old_protect)) {
- bool is_exec = !!(new_protect & kExecPageMask);
- bool was_exec = !!(*old_protect & kExecPageMask);
+ bool is_exec = new_protect == kExecPageMask;
+ bool was_exec = *old_protect == kExecPageMask;
if (is_exec && !was_exec) {
- bool limit_exceeded = UpdateExecMemSize(static_cast<intptr_t>(size)) >
- kMaxPluginExecMemSize;
- if (limit_exceeded)
+ if (!UpdateExecMemSize(static_cast<intptr_t>(size)))
RaiseJITException();
} else if (!is_exec && was_exec) {
UpdateExecMemSize(-(static_cast<intptr_t>(size)));
@@ -378,7 +419,7 @@ BOOL WINAPI WebPluginDelegateImpl::VirtualFreePatch(LPVOID address,
size_t exec_size = 0;
void* base_address = mem_info.AllocationBase;
do {
- if (mem_info.Protect & kExecPageMask)
+ if (mem_info.Protect == kExecPageMask)
exec_size += mem_info.RegionSize;
BYTE* next = reinterpret_cast<BYTE*>(mem_info.BaseAddress) +
mem_info.RegionSize;