summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjschuh@chromium.org <jschuh@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-03-01 22:54:32 +0000
committerjschuh@chromium.org <jschuh@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-03-01 22:54:32 +0000
commit11f39b3a06be5aa6e828b3e02b201639006bf3e0 (patch)
tree0e1f4e76fe60226db10f8e7eb60039967df6f986
parent48d2d88d686b6719bb3903edf5734f2d54144031 (diff)
downloadchromium_src-11f39b3a06be5aa6e828b3e02b201639006bf3e0.zip
chromium_src-11f39b3a06be5aa6e828b3e02b201639006bf3e0.tar.gz
chromium_src-11f39b3a06be5aa6e828b3e02b201639006bf3e0.tar.bz2
Merge 122109 - Track (and eventually cap) Flash JIT size
BUG=113891 Review URL: http://codereview.chromium.org/9386003 TBR=jschuh@chromium.org Review URL: https://chromiumcodereview.appspot.com/9562034 git-svn-id: svn://svn.chromium.org/chrome/branches/1025/src@124513 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--content/browser/plugin_process_host.cc8
-rw-r--r--content/browser/plugin_process_host.h3
-rw-r--r--content/common/plugin_messages.h5
-rw-r--r--content/plugin/webplugin_proxy.cc7
-rw-r--r--content/plugin/webplugin_proxy.h3
-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
9 files changed, 183 insertions, 9 deletions
diff --git a/content/browser/plugin_process_host.cc b/content/browser/plugin_process_host.cc
index ad8d074..3ce5c22 100644
--- a/content/browser/plugin_process_host.cc
+++ b/content/browser/plugin_process_host.cc
@@ -18,6 +18,7 @@
#include "base/file_path.h"
#include "base/file_util.h"
#include "base/logging.h"
+#include "base/metrics/histogram.h"
#include "base/path_service.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
@@ -103,6 +104,11 @@ void PluginProcessHost::OnReparentPluginWindow(HWND window, HWND parent) {
BrowserThread::UI, FROM_HERE,
base::Bind(ReparentPluginWindowHelper, window, parent));
}
+
+void PluginProcessHost::OnReportExecutableMemory(size_t size) {
+ // TODO(jschuh): move this into the plugin process once it supports UMA.
+ UMA_HISTOGRAM_MEMORY_KB("Plugin.ExecPageSizeKB", size / 1024);
+}
#endif // defined(OS_WIN)
#if defined(TOOLKIT_USES_GTK)
@@ -302,6 +308,8 @@ bool PluginProcessHost::OnMessageReceived(const IPC::Message& msg) {
OnPluginWindowDestroyed)
IPC_MESSAGE_HANDLER(PluginProcessHostMsg_ReparentPluginWindow,
OnReparentPluginWindow)
+ IPC_MESSAGE_HANDLER(PluginProcessHostMsg_ReportExecutableMemory,
+ OnReportExecutableMemory)
#endif
#if defined(TOOLKIT_USES_GTK)
IPC_MESSAGE_HANDLER(PluginProcessHostMsg_MapNativeViewId,
diff --git a/content/browser/plugin_process_host.h b/content/browser/plugin_process_host.h
index d1b1171..236d1f1db 100644
--- a/content/browser/plugin_process_host.h
+++ b/content/browser/plugin_process_host.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.
@@ -133,6 +133,7 @@ class CONTENT_EXPORT PluginProcessHost
#if defined(OS_WIN)
void OnPluginWindowDestroyed(HWND window, HWND parent);
void OnReparentPluginWindow(HWND window, HWND parent);
+ void OnReportExecutableMemory(size_t size);
#endif
#if defined(USE_X11)
diff --git a/content/common/plugin_messages.h b/content/common/plugin_messages.h
index 8ede47c..bffd992 100644
--- a/content/common/plugin_messages.h
+++ b/content/common/plugin_messages.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.
//
@@ -96,6 +96,9 @@ IPC_MESSAGE_CONTROL2(PluginProcessHostMsg_PluginWindowDestroyed,
IPC_MESSAGE_CONTROL2(PluginProcessHostMsg_ReparentPluginWindow,
HWND /* window */,
HWND /* parent */)
+
+IPC_MESSAGE_CONTROL1(PluginProcessHostMsg_ReportExecutableMemory,
+ uint32_t /* size */)
#endif
#if defined(USE_X11)
diff --git a/content/plugin/webplugin_proxy.cc b/content/plugin/webplugin_proxy.cc
index 5b0ac6d..d664c5c 100644
--- a/content/plugin/webplugin_proxy.cc
+++ b/content/plugin/webplugin_proxy.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.
@@ -142,6 +142,11 @@ void WebPluginProxy::ReparentPluginWindow(HWND window, HWND parent) {
PluginThread::current()->Send(
new PluginProcessHostMsg_ReparentPluginWindow(window, parent));
}
+
+void WebPluginProxy::ReportExecutableMemory(size_t size) {
+ PluginThread::current()->Send(
+ new PluginProcessHostMsg_ReportExecutableMemory(size));
+}
#endif
void WebPluginProxy::CancelResource(unsigned long id) {
diff --git a/content/plugin/webplugin_proxy.h b/content/plugin/webplugin_proxy.h
index 33b404d..cbf305a 100644
--- a/content/plugin/webplugin_proxy.h
+++ b/content/plugin/webplugin_proxy.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.
@@ -68,6 +68,7 @@ class WebPluginProxy : public webkit::npapi::WebPlugin {
#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;
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;