summaryrefslogtreecommitdiffstats
path: root/webkit/plugins
diff options
context:
space:
mode:
authorjschuh@chromium.org <jschuh@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-02-15 18:09:17 +0000
committerjschuh@chromium.org <jschuh@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-02-15 18:09:17 +0000
commita5f73fea37577eb8a796ca2fb3bc3e5a415ae8f2 (patch)
treeaaa4131e03ff7b0c4ecbaaf41ac75c556d0f6fd9 /webkit/plugins
parentc2bc226b65ccdb195cb0646ee8baac68f3264a21 (diff)
downloadchromium_src-a5f73fea37577eb8a796ca2fb3bc3e5a415ae8f2.zip
chromium_src-a5f73fea37577eb8a796ca2fb3bc3e5a415ae8f2.tar.gz
chromium_src-a5f73fea37577eb8a796ca2fb3bc3e5a415ae8f2.tar.bz2
Track (and eventually cap) Flash JIT size
BUG=113891 Review URL: http://codereview.chromium.org/9386003 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@122109 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'webkit/plugins')
-rw-r--r--webkit/plugins/npapi/webplugin.h3
-rw-r--r--webkit/plugins/npapi/webplugin_delegate_impl.h18
-rw-r--r--webkit/plugins/npapi/webplugin_delegate_impl_win.cc142
-rw-r--r--webkit/plugins/npapi/webplugin_impl.h3
4 files changed, 161 insertions, 5 deletions
diff --git a/webkit/plugins/npapi/webplugin.h b/webkit/plugins/npapi/webplugin.h
index 1a14ed6..571b8d16 100644
--- a/webkit/plugins/npapi/webplugin.h
+++ b/webkit/plugins/npapi/webplugin.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -84,6 +84,7 @@ class WebPlugin {
// Cancels a pending request.
virtual void SetWindowlessPumpEvent(HANDLE pump_messages_event) = 0;
virtual void ReparentPluginWindow(HWND window, HWND parent) = 0;
+ virtual void ReportExecutableMemory(size_t size) = 0;
#endif
virtual void CancelResource(unsigned long id) = 0;
virtual void Invalidate() = 0;
diff --git a/webkit/plugins/npapi/webplugin_delegate_impl.h b/webkit/plugins/npapi/webplugin_delegate_impl.h
index 0a89903..00dec32 100644
--- a/webkit/plugins/npapi/webplugin_delegate_impl.h
+++ b/webkit/plugins/npapi/webplugin_delegate_impl.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -85,6 +85,7 @@ class WEBKIT_PLUGINS_EXPORT WebPluginDelegateImpl : public WebPluginDelegate {
PLUGIN_QUIRK_REPARENT_IN_BROWSER = 131072, // Windows
PLUGIN_QUIRK_PATCH_GETKEYSTATE = 262144, // Windows
PLUGIN_QUIRK_EMULATE_IME = 524288, // Windows.
+ PLUGIN_QUIRK_PATCH_VM_API = 1048576, // Windows.
};
static WebPluginDelegateImpl* Create(const FilePath& filename,
@@ -410,6 +411,21 @@ class WEBKIT_PLUGINS_EXPORT WebPluginDelegateImpl : public WebPluginDelegate {
// GetKeyStatePatch interceptor for UIPI Flash plugin.
static SHORT WINAPI GetKeyStatePatch(int vkey);
+ // Virtual* VM patches for flash JIT hardenning.
+ static LPVOID WINAPI VirtualAllocPatch(LPVOID address,
+ SIZE_T size,
+ DWORD allocation_type,
+ DWORD protect);
+
+ static BOOL WINAPI VirtualProtectPatch(LPVOID address,
+ SIZE_T size,
+ DWORD new_protect,
+ PDWORD old_protect);
+
+ static BOOL WINAPI VirtualFreePatch(LPVOID address,
+ SIZE_T size,
+ DWORD free_type);
+
// RegEnumKeyExW interceptor.
static LONG WINAPI RegEnumKeyExWPatch(
HKEY key, DWORD index, LPWSTR name, LPDWORD name_size, LPDWORD reserved,
diff --git a/webkit/plugins/npapi/webplugin_delegate_impl_win.cc b/webkit/plugins/npapi/webplugin_delegate_impl_win.cc
index 835e49e..0fdee5d 100644
--- a/webkit/plugins/npapi/webplugin_delegate_impl_win.cc
+++ b/webkit/plugins/npapi/webplugin_delegate_impl_win.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -19,6 +19,7 @@
#include "base/string_split.h"
#include "base/string_util.h"
#include "base/stringprintf.h"
+#include "base/synchronization/lock.h"
#include "base/version.h"
#include "base/win/iat_patch_function.h"
#include "base/win/registry.h"
@@ -126,6 +127,45 @@ void ClearSavedKeyState() {
memset(g_saved_key_state, 0, sizeof(g_saved_key_state));
}
+// Helper objects for patching VirtualQuery, VirtualAlloc, VirtualProtect.
+base::LazyInstance<base::win::IATPatchFunction> g_iat_patch_virtual_alloc =
+ LAZY_INSTANCE_INITIALIZER;
+LPVOID (WINAPI *g_iat_orig_virtual_alloc)(LPVOID address,
+ SIZE_T size,
+ DWORD allocation_type,
+ DWORD protect);
+
+base::LazyInstance<base::win::IATPatchFunction> g_iat_patch_virtual_protect =
+ LAZY_INSTANCE_INITIALIZER;
+BOOL (WINAPI *g_iat_orig_virtual_protect)(LPVOID address,
+ SIZE_T size,
+ DWORD new_protect,
+ PDWORD old_protect);
+
+base::LazyInstance<base::win::IATPatchFunction> g_iat_patch_virtual_free =
+ LAZY_INSTANCE_INITIALIZER;
+BOOL (WINAPI *g_iat_orig_virtual_free)(LPVOID address,
+ SIZE_T size,
+ DWORD free_type);
+
+const size_t kMaxPluginExecMemSize = 64 * 1024 * 1024; // 64mb.
+const DWORD kExecPageMask = PAGE_EXECUTE | PAGE_EXECUTE_READ |
+ PAGE_EXECUTE_READWRITE;
+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) {
+ base::AutoLock locked(*g_exec_mem_lock);
+ g_exec_mem_size += size;
+ // 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;
+
+ return g_exec_mem_size;
+}
// http://crbug.com/16114
// Enforces providing a valid device context in NPWindow, so that NPP_SetWindow
@@ -307,6 +347,71 @@ SHORT WINAPI WebPluginDelegateImpl::GetKeyStatePatch(int vkey) {
return g_iat_orig_get_key_state(vkey);
}
+// We need to track RX memory usage in plugins to prevent JIT spraying attacks.
+// This is done by hooking VirtualAlloc, VirtualProtect, and VirtualFree.
+LPVOID WINAPI WebPluginDelegateImpl::VirtualAllocPatch(LPVOID address,
+ SIZE_T size,
+ DWORD allocation_type,
+ DWORD protect) {
+ void* p = g_iat_orig_virtual_alloc(address, size, allocation_type, protect);
+ if (size && p && (protect & kExecPageMask)) {
+ bool limit_exceeded = UpdateExecMemSize(static_cast<intptr_t>(size)) >
+ kMaxPluginExecMemSize;
+#ifndef NDEBUG // TODO(jschuh): Do this in release after we get numbers.
+ if (limit_exceeded)
+ ::DebugBreak();
+#endif
+ }
+ return p;
+}
+
+BOOL WINAPI WebPluginDelegateImpl::VirtualProtectPatch(LPVOID address,
+ SIZE_T size,
+ 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);
+ if (is_exec && !was_exec) {
+ bool limit_exceeded = UpdateExecMemSize(static_cast<intptr_t>(size)) >
+ kMaxPluginExecMemSize;
+#ifndef NDEBUG // TODO(jschuh): Do this in release after we get numbers.
+ if (limit_exceeded)
+ ::DebugBreak();
+#endif
+ } else if (!is_exec && was_exec) {
+ UpdateExecMemSize(-(static_cast<intptr_t>(size)));
+ }
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+BOOL WINAPI WebPluginDelegateImpl::VirtualFreePatch(LPVOID address,
+ SIZE_T size,
+ DWORD free_type) {
+ MEMORY_BASIC_INFORMATION mem_info;
+ if (::VirtualQuery(address, &mem_info, sizeof(mem_info))) {
+ size_t exec_size = 0;
+ void* base_address = mem_info.AllocationBase;
+ do {
+ if (mem_info.Protect & kExecPageMask)
+ exec_size += mem_info.RegionSize;
+ BYTE* next = reinterpret_cast<BYTE*>(mem_info.BaseAddress) +
+ mem_info.RegionSize;
+ if (!::VirtualQuery(next, &mem_info, sizeof(mem_info)))
+ break;
+ } while (base_address == mem_info.AllocationBase);
+
+ if (exec_size)
+ UpdateExecMemSize(-(static_cast<intptr_t>(exec_size)));
+ }
+
+ return g_iat_orig_virtual_free(address, size, free_type);
+}
+
WebPluginDelegateImpl::WebPluginDelegateImpl(
gfx::PluginWindowHandle containing_view,
PluginInstance *instance)
@@ -351,7 +456,8 @@ WebPluginDelegateImpl::WebPluginDelegateImpl(
if (filename == kBuiltinFlashPlugin &&
base::win::GetVersion() >= base::win::VERSION_VISTA) {
quirks_ |= PLUGIN_QUIRK_REPARENT_IN_BROWSER |
- PLUGIN_QUIRK_PATCH_GETKEYSTATE;
+ PLUGIN_QUIRK_PATCH_GETKEYSTATE |
+ PLUGIN_QUIRK_PATCH_VM_API;
}
quirks_ |= PLUGIN_QUIRK_EMULATE_IME;
} else if (filename == kAcrobatReaderPlugin) {
@@ -516,6 +622,32 @@ bool WebPluginDelegateImpl::PlatformInitialize() {
WebPluginDelegateImpl::GetKeyStatePatch);
}
+ // Hook the VM calls so we can track the amount of executable memory being
+ // allocated by Flash (and potentially other plugins).
+ if (quirks_ & PLUGIN_QUIRK_PATCH_VM_API) {
+ if (!g_exec_mem_lock.get())
+ g_exec_mem_lock.reset(new base::Lock());
+
+ if (!g_iat_patch_virtual_alloc.Pointer()->is_patched()) {
+ g_iat_orig_virtual_alloc = ::VirtualAlloc;
+ g_iat_patch_virtual_alloc.Pointer()->Patch(
+ L"gcswf32.dll", "kernel32.dll", "VirtualAlloc",
+ WebPluginDelegateImpl::VirtualAllocPatch);
+ }
+ if (!g_iat_patch_virtual_protect.Pointer()->is_patched()) {
+ g_iat_orig_virtual_protect = ::VirtualProtect;
+ g_iat_patch_virtual_protect.Pointer()->Patch(
+ L"gcswf32.dll", "kernel32.dll", "VirtualProtect",
+ WebPluginDelegateImpl::VirtualProtectPatch);
+ }
+ if (!g_iat_patch_virtual_free.Pointer()->is_patched()) {
+ g_iat_orig_virtual_free = ::VirtualFree;
+ g_iat_patch_virtual_free.Pointer()->Patch(
+ L"gcswf32.dll", "kernel32.dll", "VirtualFree",
+ WebPluginDelegateImpl::VirtualFreePatch);
+ }
+ }
+
return true;
}
@@ -527,6 +659,12 @@ void WebPluginDelegateImpl::PlatformDestroyInstance() {
if (instance_->plugin_lib()->instance_count() != 1)
return;
+ // Pass back the stats for max executable memory.
+ if (quirks_ & PLUGIN_QUIRK_PATCH_VM_API) {
+ plugin_->ReportExecutableMemory(g_max_exec_mem_size);
+ g_max_exec_mem_size = 0;
+ }
+
if (g_iat_patch_set_cursor.Pointer()->is_patched())
g_iat_patch_set_cursor.Pointer()->Unpatch();
diff --git a/webkit/plugins/npapi/webplugin_impl.h b/webkit/plugins/npapi/webplugin_impl.h
index 843e4f1..9e9bb8f 100644
--- a/webkit/plugins/npapi/webplugin_impl.h
+++ b/webkit/plugins/npapi/webplugin_impl.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -97,6 +97,7 @@ class WEBKIT_PLUGINS_EXPORT WebPluginImpl :
#if defined(OS_WIN)
void SetWindowlessPumpEvent(HANDLE pump_messages_event) { }
void ReparentPluginWindow(HWND window, HWND parent) { }
+ void ReportExecutableMemory(size_t size) { }
#endif
virtual void CancelResource(unsigned long id) OVERRIDE;
virtual void Invalidate() OVERRIDE;