0

Remove Legacy NPAPI Flash Sandbox support

BUG=153599

Review URL: https://chromiumcodereview.appspot.com/11049004

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@160310 0039d316-1c4b-4281-b951-d872f2087c98
This commit is contained in:
jschuh@chromium.org
2012-10-05 02:44:14 +00:00
parent 56b95eb48a
commit 1b89a68deb
17 changed files with 12 additions and 609 deletions

@ -310,60 +310,6 @@ bool GetBundledPepperFlash(content::PepperPluginInfo* plugin,
#endif // FLAPPER_AVAILABLE
}
#if defined(OS_WIN)
// Launches the privileged flash broker, used when flash is sandboxed.
// The broker is the same flash dll, except that it uses a different
// entrypoint (BrokerMain) and it is hosted in windows' generic surrogate
// process rundll32. After launching the broker we need to pass to
// the flash plugin the process id of the broker via the command line
// using --flash-broker=pid.
// More info about rundll32 at http://support.microsoft.com/kb/164787.
bool LoadFlashBroker(const FilePath& plugin_path, CommandLine* cmd_line) {
FilePath rundll;
if (!PathService::Get(base::DIR_SYSTEM, &rundll))
return false;
rundll = rundll.AppendASCII("rundll32.exe");
// Rundll32 cannot handle paths with spaces, so we use the short path.
wchar_t short_path[MAX_PATH];
if (0 == ::GetShortPathNameW(plugin_path.value().c_str(),
short_path, arraysize(short_path)))
return false;
// Here is the kicker, if the user has disabled 8.3 (short path) support
// on the volume GetShortPathNameW does not fail but simply returns the
// input path. In this case if the path had any spaces then rundll32 will
// incorrectly interpret its parameters. So we quote the path, even though
// the kb/164787 says you should not.
std::wstring cmd_final =
base::StringPrintf(L"%ls \"%ls\",BrokerMain browser=chrome",
rundll.value().c_str(),
short_path);
base::ProcessHandle process;
base::LaunchOptions options;
options.start_hidden = true;
if (!base::LaunchProcess(cmd_final, options, &process))
return false;
cmd_line->AppendSwitchASCII("flash-broker",
base::Int64ToString(::GetProcessId(process)));
// The flash broker, unders some circumstances can linger beyond the lifetime
// of the flash player, so we put it in a job object, when the browser
// terminates the job object is destroyed (by the OS) and the flash broker
// is terminated.
HANDLE job = ::CreateJobObjectW(NULL, NULL);
if (base::SetJobObjectAsKillOnJobClose(job)) {
::AssignProcessToJobObject(job, process);
// Yes, we are leaking the object here. Read comment above.
} else {
::CloseHandle(job);
return false;
}
::CloseHandle(process);
return true;
}
#endif // OS_WIN
} // namespace
namespace chrome {
@ -464,70 +410,6 @@ gfx::Image& ChromeContentClient::GetNativeImageNamed(int resource_id) const {
return ResourceBundle::GetSharedInstance().GetNativeImageNamed(resource_id);
}
#if defined(OS_WIN)
bool ChromeContentClient::SandboxPlugin(CommandLine* command_line,
sandbox::TargetPolicy* policy) {
std::wstring plugin_dll = command_line->
GetSwitchValueNative(switches::kPluginPath);
FilePath builtin_flash;
if (!PathService::Get(chrome::FILE_FLASH_PLUGIN_EXISTING, &builtin_flash))
return false;
FilePath plugin_path(plugin_dll);
if (plugin_path.BaseName() != builtin_flash.BaseName())
return false;
if (base::win::GetVersion() <= base::win::VERSION_XP ||
CommandLine::ForCurrentProcess()->HasSwitch(
switches::kDisableFlashSandbox)) {
return false;
}
// Add policy for the plugin proxy window pump event
// used by WebPluginDelegateProxy::HandleInputEvent().
if (policy->AddRule(sandbox::TargetPolicy::SUBSYS_HANDLES,
sandbox::TargetPolicy::HANDLES_DUP_ANY,
L"Event") != sandbox::SBOX_ALL_OK) {
NOTREACHED();
return false;
}
// Add the policy for the pipes.
if (policy->AddRule(sandbox::TargetPolicy::SUBSYS_NAMED_PIPES,
sandbox::TargetPolicy::NAMEDPIPES_ALLOW_ANY,
L"\\\\.\\pipe\\chrome.*") != sandbox::SBOX_ALL_OK) {
NOTREACHED();
return false;
}
// Spawn the flash broker and apply sandbox policy.
if (LoadFlashBroker(plugin_path, command_line)) {
// UI job restrictions break windowless Flash, so just pick up single
// process limit for now.
policy->SetJobLevel(sandbox::JOB_UNPROTECTED, 0);
policy->SetTokenLevel(sandbox::USER_RESTRICTED_SAME_ACCESS,
sandbox::USER_INTERACTIVE);
// Allow the Flash plugin to forward some messages back to Chrome.
if (base::win::GetVersion() == base::win::VERSION_VISTA) {
// Per-window message filters required on Win7 or later must be added to:
// render_widget_host_view_win.cc RenderWidgetHostViewWin::ReparentWindow
::ChangeWindowMessageFilter(WM_MOUSEWHEEL, MSGFLT_ADD);
::ChangeWindowMessageFilter(WM_APPCOMMAND, MSGFLT_ADD);
}
policy->SetIntegrityLevel(sandbox::INTEGRITY_LEVEL_LOW);
} else {
// Could not start the broker, use a very weak policy instead.
DLOG(WARNING) << "Failed to start flash broker";
policy->SetJobLevel(sandbox::JOB_UNPROTECTED, 0);
policy->SetTokenLevel(
sandbox::USER_UNPROTECTED, sandbox::USER_UNPROTECTED);
}
return true;
}
#endif
#if defined(OS_MACOSX) && !defined(OS_IOS)
bool ChromeContentClient::GetSandboxProfileForSandboxType(
int sandbox_type,

@ -38,11 +38,6 @@ class ChromeContentClient : public content::ContentClient {
ui::ScaleFactor scale_factor) const OVERRIDE;
virtual gfx::Image& GetNativeImageNamed(int resource_id) const OVERRIDE;
#if defined(OS_WIN)
virtual bool SandboxPlugin(CommandLine* command_line,
sandbox::TargetPolicy* policy) OVERRIDE;
#endif
#if defined(OS_MACOSX) && !defined(OS_IOS)
virtual bool GetSandboxProfileForSandboxType(
int sandbox_type,

@ -58,24 +58,6 @@ using content::ChildProcessHost;
#include "webkit/plugins/npapi/plugin_constants_win.h"
#include "webkit/plugins/npapi/webplugin_delegate_impl.h"
namespace {
void ReparentPluginWindowHelper(HWND window, HWND parent) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
int window_style = WS_CHILD;
if (!webkit::npapi::WebPluginDelegateImpl::IsDummyActivationWindow(window))
window_style |= WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
::SetWindowLongPtr(window, GWL_STYLE, window_style);
::SetParent(window, parent);
// Allow the Flash plugin to forward some messages back to Chrome.
if (base::win::GetVersion() >= base::win::VERSION_WIN7)
::SetPropW(parent, webkit::npapi::kNativeWindowClassFilterProp, HANDLE(-1));
}
} // namespace
void PluginProcessHost::OnPluginWindowDestroyed(HWND window, HWND parent) {
// The window is destroyed at this point, we just care about its parent, which
// is the intermediate window we created.
@ -92,25 +74,6 @@ void PluginProcessHost::AddWindow(HWND window) {
plugin_parent_windows_set_.insert(window);
}
void PluginProcessHost::OnReparentPluginWindow(HWND window, HWND parent) {
// Reparent only from the plugin process to our process.
DWORD process_id = 0;
::GetWindowThreadProcessId(window, &process_id);
if (process_id != ::GetProcessId(process_->GetHandle()))
return;
::GetWindowThreadProcessId(parent, &process_id);
if (process_id != ::GetCurrentProcessId())
return;
BrowserThread::PostTask(
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_GTK)
@ -317,10 +280,6 @@ bool PluginProcessHost::OnMessageReceived(const IPC::Message& msg) {
#if defined(OS_WIN)
IPC_MESSAGE_HANDLER(PluginProcessHostMsg_PluginWindowDestroyed,
OnPluginWindowDestroyed)
IPC_MESSAGE_HANDLER(PluginProcessHostMsg_ReparentPluginWindow,
OnReparentPluginWindow)
IPC_MESSAGE_HANDLER(PluginProcessHostMsg_ReportExecutableMemory,
OnReportExecutableMemory)
#endif
#if defined(TOOLKIT_GTK)
IPC_MESSAGE_HANDLER(PluginProcessHostMsg_MapNativeViewId,

@ -131,8 +131,6 @@ 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)

@ -147,16 +147,6 @@ HWND ReparentWindow(HWND window) {
WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
0, 0, 0, 0, orig_parent, 0, instance, 0);
ui::CheckWindowCreated(parent);
// If UIPI is enabled we need to add message filters for parents with
// children that cross process boundaries.
if (::GetPropW(orig_parent, webkit::npapi::kNativeWindowClassFilterProp)) {
// Process-wide message filters required on Vista must be added to:
// chrome_content_client.cc ChromeContentClient::SandboxPlugin
ChangeWindowMessageFilterEx(parent, WM_MOUSEWHEEL, MSGFLT_ALLOW, NULL);
ChangeWindowMessageFilterEx(parent, WM_GESTURE, MSGFLT_ALLOW, NULL);
ChangeWindowMessageFilterEx(parent, WM_APPCOMMAND, MSGFLT_ALLOW, NULL);
::RemovePropW(orig_parent, webkit::npapi::kNativeWindowClassFilterProp);
}
::SetParent(window, parent);
// How many times we try to find a PluginProcessHost whose process matches
// the HWND.

@ -92,13 +92,6 @@ IPC_MESSAGE_CONTROL1(PluginProcessHostMsg_ChannelCreated,
IPC_MESSAGE_CONTROL2(PluginProcessHostMsg_PluginWindowDestroyed,
HWND /* window */,
HWND /* parent */)
IPC_MESSAGE_CONTROL2(PluginProcessHostMsg_ReparentPluginWindow,
HWND /* window */,
HWND /* parent */)
IPC_MESSAGE_CONTROL1(PluginProcessHostMsg_ReportExecutableMemory,
uint32_t /* size */)
#endif
#if defined(USE_X11)

@ -111,16 +111,6 @@ const wchar_t* const kTroublesomeDlls[] = {
L"winstylerthemehelper.dll" // Tuneup utilities 2006.
};
// The DLLs listed here are known (or under strong suspicion) of causing crashes
// when they are loaded in the plugin process.
const wchar_t* const kTroublesomePluginDlls[] = {
L"rpmainbrowserrecordplugin.dll", // RealPlayer.
L"rpchromebrowserrecordhelper.dll", // RealPlayer.
L"rpchrome10browserrecordhelper.dll", // RealPlayer.
L"ycwebcamerasource.ax" // Cyberlink Camera helper.
L"CLRGL.ax" // Cyberlink Camera helper.
};
// The DLLs listed here are known (or under strong suspicion) of causing crashes
// when they are loaded in the GPU process.
const wchar_t* const kTroublesomeGpuDlls[] = {
@ -242,13 +232,6 @@ void AddGenericDllEvictionPolicy(sandbox::TargetPolicy* policy) {
BlacklistAddOneDll(kTroublesomeDlls[ix], true, policy);
}
// Same as AddGenericDllEvictionPolicy but specifically for plugins. In this
// case we add the blacklisted dlls even if they are not loaded in this process.
void AddPluginDllEvictionPolicy(sandbox::TargetPolicy* policy) {
for (int ix = 0; ix != arraysize(kTroublesomePluginDlls); ++ix)
BlacklistAddOneDll(kTroublesomePluginDlls[ix], false, policy);
}
// Same as AddGenericDllEvictionPolicy but specifically for the GPU process.
// In this we add the blacklisted dlls even if they are not loaded in this
// process.
@ -754,26 +737,16 @@ base::ProcessHandle StartProcessWithAccess(CommandLine* cmd_line,
// to create separate pretetch settings for browser, renderer etc.
cmd_line->AppendArg(base::StringPrintf("/prefetch:%d", type));
sandbox::ResultCode result;
base::win::ScopedProcessInformation target;
sandbox::TargetPolicy* policy = g_broker_services->CreatePolicy();
#if !defined(NACL_WIN64) // We don't need this code on win nacl64.
if (type == content::PROCESS_TYPE_PLUGIN &&
!browser_command_line.HasSwitch(switches::kNoSandbox) &&
content::GetContentClient()->SandboxPlugin(cmd_line, policy)) {
in_sandbox = true;
}
#endif
if (!in_sandbox) {
policy->Release();
base::ProcessHandle process = 0;
base::LaunchProcess(*cmd_line, base::LaunchOptions(), &process);
g_broker_services->AddTargetPeer(process);
return process;
}
base::win::ScopedProcessInformation target;
sandbox::TargetPolicy* policy = g_broker_services->CreatePolicy();
// TODO(jschuh): Make NaCl work with DEP and SEHOP. crbug.com/147752
sandbox::MitigationFlags mitigations = MITIGATION_HEAP_TERMINATE |
MITIGATION_BOTTOM_UP_ASLR |
@ -804,10 +777,7 @@ base::ProcessHandle StartProcessWithAccess(CommandLine* cmd_line,
SetJobLevel(*cmd_line, JOB_LOCKDOWN, 0, policy);
if (type == content::PROCESS_TYPE_PLUGIN) {
AddGenericDllEvictionPolicy(policy);
AddPluginDllEvictionPolicy(policy);
} else if (type == content::PROCESS_TYPE_GPU) {
if (type == content::PROCESS_TYPE_GPU) {
if (!AddPolicyForGPU(cmd_line, policy))
return 0;
} else {
@ -836,6 +806,7 @@ base::ProcessHandle StartProcessWithAccess(CommandLine* cmd_line,
}
}
sandbox::ResultCode result;
if (!exposed_dir.empty()) {
result = policy->AddRule(sandbox::TargetPolicy::SUBSYS_FILES,
sandbox::TargetPolicy::FILES_ALLOW_ANY,

@ -41,56 +41,6 @@ void InitializeChromeApplication();
void WorkaroundFlashLAHF();
#endif
#if defined(OS_WIN)
// This function is provided so that the built-in flash can lock down the
// sandbox by calling DelayedLowerToken(0).
extern "C" DWORD __declspec(dllexport) __stdcall DelayedLowerToken(void* ts) {
// s_ts is only set the first time the function is called, which happens
// in PluginMain.
static sandbox::TargetServices* s_ts =
reinterpret_cast<sandbox::TargetServices*>(ts);
if (ts)
return 0;
s_ts->LowerToken();
return 1;
};
// Returns true if the plugin to be loaded is the internal flash.
bool IsPluginBuiltInFlash(const CommandLine& cmd_line) {
FilePath path = cmd_line.GetSwitchValuePath(switches::kPluginPath);
return (path.BaseName() == FilePath(L"gcswf32.dll"));
}
// Before we lock down the flash sandbox, we need to activate the IME machinery
// and attach it to this process. (Windows attaches an IME machinery to this
// process automatically while it creates its first top-level window.) After
// lock down it seems it is unable to start. Note that we leak the IME context
// on purpose.
HWND g_ime_window = NULL;
int PreloadIMEForFlash() {
HIMC imc = ::ImmCreateContext();
if (!imc)
return 0;
if (::ImmGetOpenStatus(imc))
return 1;
if (!g_ime_window) {
g_ime_window = CreateWindowEx(WS_EX_TOOLWINDOW, L"EDIT", L"", WS_POPUP,
0, 0, 0, 0, NULL, NULL, GetModuleHandle(NULL), NULL);
SetWindowLongPtr(g_ime_window, GWL_EXSTYLE, WS_EX_NOACTIVATE);
}
return 2;
}
void DestroyIMEForFlash() {
if (g_ime_window) {
DestroyWindow(g_ime_window);
g_ime_window = NULL;
}
}
#endif
// main() routine for running as the plugin process.
int PluginMain(const content::MainFunctionParams& parameters) {
// The main thread of the plugin services UI.
@ -115,27 +65,9 @@ int PluginMain(const content::MainFunctionParams& parameters) {
#endif
#elif defined(OS_WIN)
sandbox::TargetServices* target_services =
parameters.sandbox_info->target_services;
base::win::ScopedCOMInitializer com_initializer;
DVLOG(1) << "Started plugin with "
<< parsed_command_line.GetCommandLineString();
HMODULE sandbox_test_module = NULL;
bool no_sandbox = parsed_command_line.HasSwitch(switches::kNoSandbox);
if (target_services && !no_sandbox) {
// The command line might specify a test plugin to load.
if (parsed_command_line.HasSwitch(switches::kTestSandbox)) {
std::wstring test_plugin_name =
parsed_command_line.GetSwitchValueNative(switches::kTestSandbox);
sandbox_test_module = LoadLibrary(test_plugin_name.c_str());
DCHECK(sandbox_test_module);
}
}
#endif
if (parsed_command_line.HasSwitch(switches::kPluginStartupDialog)) {
ChildProcess::WaitForDebugger("Plugin");
}
@ -143,48 +75,8 @@ int PluginMain(const content::MainFunctionParams& parameters) {
{
ChildProcess plugin_process;
plugin_process.set_main_thread(new PluginThread());
#if defined(OS_WIN)
if (!no_sandbox && target_services) {
// We are sandboxing the plugin. If it is a generic plug-in, we lock down
// the sandbox right away, but if it is the built-in flash we let flash
// start elevated and it will call DelayedLowerToken(0) when it's ready.
if (IsPluginBuiltInFlash(parsed_command_line)) {
DVLOG(1) << "Sandboxing flash";
if (!PreloadIMEForFlash())
DVLOG(1) << "IME preload failed";
DelayedLowerToken(target_services);
} else {
target_services->LowerToken();
}
}
if (sandbox_test_module) {
RunPluginTests run_security_tests =
reinterpret_cast<RunPluginTests>(GetProcAddress(sandbox_test_module,
kPluginTestCall));
DCHECK(run_security_tests);
if (run_security_tests) {
int test_count = 0;
DVLOG(1) << "Running plugin security tests";
BOOL result = run_security_tests(&test_count);
DCHECK(result) << "Test number " << test_count << " has failed.";
// If we are in release mode, crash or debug the process.
if (!result) {
__debugbreak();
_exit(1);
}
}
FreeLibrary(sandbox_test_module);
}
#endif
MessageLoop::current()->Run();
}
#if defined(OS_WIN)
DestroyIMEForFlash();
#endif
return 0;
}

@ -148,16 +148,6 @@ void WebPluginProxy::SetWindowlessPumpEvent(HANDLE pump_messages_event) {
Send(new PluginHostMsg_SetWindowlessPumpEvent(
route_id_, pump_messages_event_for_renderer));
}
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) {

@ -67,8 +67,6 @@ class WebPluginProxy : public webkit::npapi::WebPlugin {
virtual void WillDestroyWindow(gfx::PluginWindowHandle window) OVERRIDE;
#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;

@ -83,13 +83,6 @@ gfx::Image& ContentClient::GetNativeImageNamed(int resource_id) const {
return kEmptyImage;
}
#if defined(OS_WIN)
bool ContentClient::SandboxPlugin(CommandLine* command_line,
sandbox::TargetPolicy* policy) {
return false;
}
#endif
#if defined(OS_MACOSX) && !defined(OS_IOS)
bool ContentClient::GetSandboxProfileForSandboxType(
int sandbox_type,

@ -126,12 +126,6 @@ class CONTENT_EXPORT ContentClient {
// Returns a native image given its id.
virtual gfx::Image& GetNativeImageNamed(int resource_id) const;
#if defined(OS_WIN)
// Allows the embedder to sandbox a plugin, and apply a custom policy.
virtual bool SandboxPlugin(CommandLine* command_line,
sandbox::TargetPolicy* policy);
#endif
#if defined(OS_MACOSX) && !defined(OS_IOS)
// Allows the embedder to define a new |sandbox_type| by mapping it to the
// resource ID corresponding to the sandbox profile to use. The legal values

@ -9,7 +9,6 @@ namespace npapi {
const char16 kNativeWindowClassName[] = L"NativeWindowClass";
const char16 kWrapperNativeWindowClassName[] = L"WrapperNativeWindowClass";
const char16 kNativeWindowClassFilterProp[] = L"NativeWindowClassFilterProp";
const char16 kPaintMessageName[] = L"Chrome_CustomPaintil";
const char16 kRegistryMozillaPlugins[] = L"SOFTWARE\\MozillaPlugins";
const char16 kMozillaActiveXPlugin[] = L"npmozax.dll";
@ -17,7 +16,6 @@ const char16 kNewWMPPlugin[] = L"np-mswmp.dll";
const char16 kOldWMPPlugin[] = L"npdsplay.dll";
const char16 kYahooApplicationStatePlugin[] = L"npystate.dll";
const char16 kWanWangProtocolHandlerPlugin[] = L"npww.dll";
const char16 kBuiltinFlashPlugin[] = L"gcswf32.dll";
const char16 kFlashPlugin[] = L"npswf32.dll";
const char16 kAcrobatReaderPlugin[] = L"nppdf32.dll";
const char16 kRealPlayerPlugin[] = L"nppl3260.dll";

@ -18,9 +18,6 @@ namespace npapi {
// The window class name for a plugin window.
extern const char16 kNativeWindowClassName[];
// If property is non-zero window reparenting must add UIPI message filters.
WEBKIT_PLUGINS_EXPORT extern const char16 kNativeWindowClassFilterProp[];
// The name of the window class name for the wrapper HWND around the actual
// plugin window that's used when running in multi-process mode. This window
// is created on the browser UI thread.
@ -38,7 +35,6 @@ WEBKIT_PLUGINS_EXPORT extern const char16 kNewWMPPlugin[];
extern const char16 kOldWMPPlugin[];
extern const char16 kYahooApplicationStatePlugin[];
extern const char16 kWanWangProtocolHandlerPlugin[];
extern const char16 kBuiltinFlashPlugin[];
extern const char16 kFlashPlugin[];
extern const char16 kAcrobatReaderPlugin[];
extern const char16 kRealPlayerPlugin[];

@ -83,8 +83,6 @@ class WebPlugin {
// if the plugin enters a modal loop.
// 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;

@ -75,10 +75,7 @@ class WEBKIT_PLUGINS_EXPORT WebPluginDelegateImpl : public WebPluginDelegate {
PLUGIN_QUIRK_HANDLE_MOUSE_CAPTURE = 16384, // Windows
PLUGIN_QUIRK_WINDOWLESS_NO_RIGHT_CLICK = 32768, // Linux
PLUGIN_QUIRK_IGNORE_FIRST_SETWINDOW_CALL = 65536, // Windows.
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.
PLUGIN_QUIRK_EMULATE_IME = 131072, // Windows.
};
static WebPluginDelegateImpl* Create(const FilePath& filename,
@ -375,7 +372,6 @@ class WEBKIT_PLUGINS_EXPORT WebPluginDelegateImpl : public WebPluginDelegate {
// receives a WM_LBUTTONDOWN/WM_RBUTTONDOWN message via NPP_HandleEvent.
HWND dummy_window_for_activation_;
HWND parent_proxy_window_;
bool CreateDummyWindowForActivation();
// Returns true if the event passed in needs to be tracked for a potential
@ -396,18 +392,6 @@ class WEBKIT_PLUGINS_EXPORT WebPluginDelegateImpl : public WebPluginDelegate {
// SetCursor interceptor for windowless plugins.
static HCURSOR WINAPI SetCursorPatch(HCURSOR cursor);
// GetKeyStatePatch interceptor for UIPI Flash plugin.
static SHORT WINAPI GetKeyStatePatch(int vkey);
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,

@ -92,69 +92,6 @@ base::LazyInstance<base::win::IATPatchFunction> g_iat_patch_reg_enum_key_ex_w =
base::LazyInstance<base::win::IATPatchFunction> g_iat_patch_get_proc_address =
LAZY_INSTANCE_INITIALIZER;
// Helper object for patching the GetKeyState API.
base::LazyInstance<base::win::IATPatchFunction> g_iat_patch_get_key_state =
LAZY_INSTANCE_INITIALIZER;
// Saved key state globals and helper access functions.
SHORT (WINAPI *g_iat_orig_get_key_state)(int vkey);
typedef size_t SavedStateType;
const size_t kBitsPerType = sizeof(SavedStateType) * 8;
// Bit array of key state corresponding to virtual key index (0=up, 1=down).
SavedStateType g_saved_key_state[256 / kBitsPerType];
bool GetSavedKeyState(WPARAM vkey) {
CHECK_LT(vkey, kBitsPerType * sizeof(g_saved_key_state));
if (g_saved_key_state[vkey / kBitsPerType] & 1 << (vkey % kBitsPerType))
return true;
return false;
}
void SetSavedKeyState(WPARAM vkey) {
CHECK_LT(vkey, kBitsPerType * sizeof(g_saved_key_state));
// Cache the key state only for keys blocked by UIPI.
if (g_iat_orig_get_key_state(vkey) == 0)
g_saved_key_state[vkey / kBitsPerType] |= 1 << (vkey % kBitsPerType);
}
void UnsetSavedKeyState(WPARAM vkey) {
CHECK_LT(vkey, kBitsPerType * sizeof(g_saved_key_state));
g_saved_key_state[vkey / kBitsPerType] &= ~(1 << (vkey % kBitsPerType));
}
void ClearSavedKeyState() {
memset(g_saved_key_state, 0, sizeof(g_saved_key_state));
}
// Helper objects for patching VirtualQuery, VirtualProtect.
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 DWORD kExecPageMask = PAGE_EXECUTE_READ;
static volatile intptr_t g_max_exec_mem_size;
static scoped_ptr<base::Lock> g_exec_mem_lock;
void UpdateExecMemSize(intptr_t size) {
base::AutoLock locked(*g_exec_mem_lock);
static intptr_t s_exec_mem_size = 0;
// Floor to zero since shutdown may unmap pages created before our hooks.
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;
}
// http://crbug.com/16114
// Enforces providing a valid device context in NPWindow, so that NPP_SetWindow
// is never called with NPNWindoTypeDrawable and NPWindow set to NULL.
@ -337,59 +274,6 @@ LRESULT CALLBACK WebPluginDelegateImpl::MouseHookProc(
return CallNextHookEx(NULL, code, wParam, lParam);
}
// In addition to the key state we maintain, we also mask in the original
// return value. This is done because system keys (e.g. tab, enter, shift)
// and toggles (e.g. capslock, numlock) don't ever seem to be blocked.
SHORT WINAPI WebPluginDelegateImpl::GetKeyStatePatch(int vkey) {
if (GetSavedKeyState(vkey))
return g_iat_orig_get_key_state(vkey) | 0x8000;
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 VirtualProtect and VirtualFree.
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) {
UpdateExecMemSize(static_cast<intptr_t>(size));
} 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)
@ -404,7 +288,6 @@ WebPluginDelegateImpl::WebPluginDelegateImpl(
last_message_(0),
is_calling_wndproc(false),
dummy_window_for_activation_(NULL),
parent_proxy_window_(NULL),
handle_event_message_filter_hook_(NULL),
handle_event_pump_messages_event_(NULL),
user_gesture_message_posted_(false),
@ -431,12 +314,6 @@ WebPluginDelegateImpl::WebPluginDelegateImpl(
quirks_ |= PLUGIN_QUIRK_PATCH_SETCURSOR;
quirks_ |= PLUGIN_QUIRK_ALWAYS_NOTIFY_SUCCESS;
quirks_ |= PLUGIN_QUIRK_HANDLE_MOUSE_CAPTURE;
if (filename == kBuiltinFlashPlugin &&
base::win::GetVersion() >= base::win::VERSION_VISTA) {
quirks_ |= PLUGIN_QUIRK_REPARENT_IN_BROWSER |
PLUGIN_QUIRK_PATCH_GETKEYSTATE |
PLUGIN_QUIRK_PATCH_VM_API;
}
quirks_ |= PLUGIN_QUIRK_EMULATE_IME;
} else if (filename == kAcrobatReaderPlugin) {
// Check for the version number above or equal 9.
@ -493,13 +370,8 @@ WebPluginDelegateImpl::WebPluginDelegateImpl(
}
WebPluginDelegateImpl::~WebPluginDelegateImpl() {
if (::IsWindow(dummy_window_for_activation_)) {
// Sandboxed Flash stacks two dummy windows to prevent UIPI failures
if (::IsWindow(parent_proxy_window_))
::DestroyWindow(parent_proxy_window_);
else
::DestroyWindow(dummy_window_for_activation_);
}
if (::IsWindow(dummy_window_for_activation_))
::DestroyWindow(dummy_window_for_activation_);
DestroyInstance();
@ -589,37 +461,6 @@ bool WebPluginDelegateImpl::PlatformInitialize() {
GetProcAddressPatch);
}
// Under UIPI the key state does not get forwarded properly to the child
// plugin window. So, instead we track the key state manually and intercept
// GetKeyState.
if ((quirks_ & PLUGIN_QUIRK_PATCH_GETKEYSTATE) &&
!g_iat_patch_get_key_state.Pointer()->is_patched()) {
g_iat_orig_get_key_state = ::GetKeyState;
g_iat_patch_get_key_state.Pointer()->Patch(
L"gcswf32.dll", "user32.dll", "GetKeyState",
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_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;
}
@ -631,12 +472,6 @@ 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();
@ -666,9 +501,6 @@ bool WebPluginDelegateImpl::WindowedCreatePlugin() {
RegisterNativeWindowClass();
// UIPI requires reparenting in the (medium-integrity) browser process.
bool reparent_in_browser = (quirks_ & PLUGIN_QUIRK_REPARENT_IN_BROWSER) != 0;
// The window will be sized and shown later.
windowed_handle_ = CreateWindowEx(
WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR,
@ -679,16 +511,14 @@ bool WebPluginDelegateImpl::WindowedCreatePlugin() {
0,
0,
0,
reparent_in_browser ? NULL : parent_,
parent_,
0,
GetModuleHandle(NULL),
0);
if (windowed_handle_ == 0)
return false;
if (reparent_in_browser) {
plugin_->ReparentPluginWindow(windowed_handle_, parent_);
} else if (IsWindow(parent_)) {
if (IsWindow(parent_)) {
// This is a tricky workaround for Issue 2673 in chromium "Flash: IME not
// available". To use IMEs in this window, we have to make Windows attach
// IMEs to this window (i.e. load IME DLLs, attach them to this process,
@ -910,29 +740,6 @@ BOOL CALLBACK EnumFlashWindows(HWND window, LPARAM arg) {
bool WebPluginDelegateImpl::CreateDummyWindowForActivation() {
DCHECK(!dummy_window_for_activation_);
// Built-in Flash runs with UIPI, but in windowless mode Flash sometimes
// tries to attach windows to the parent (which fails under UIPI). To make
// it work we add an extra dummy parent in the low-integrity process.
if (quirks_ & PLUGIN_QUIRK_REPARENT_IN_BROWSER) {
parent_proxy_window_ = CreateWindowEx(
0,
L"Static",
kDummyActivationWindowName,
WS_POPUP,
0,
0,
0,
0,
0,
0,
GetModuleHandle(NULL),
0);
if (parent_proxy_window_ == 0)
return false;
plugin_->ReparentPluginWindow(parent_proxy_window_, parent_);
}
dummy_window_for_activation_ = CreateWindowEx(
0,
L"Static",
@ -942,7 +749,7 @@ bool WebPluginDelegateImpl::CreateDummyWindowForActivation() {
0,
0,
0,
parent_proxy_window_ ? parent_proxy_window_ : parent_,
parent_,
0,
GetModuleHandle(NULL),
0);
@ -1133,31 +940,6 @@ LRESULT CALLBACK WebPluginDelegateImpl::NativeWndProc(
return FALSE;
}
// Track the keystate to work around a UIPI issue.
if (delegate->GetQuirks() & PLUGIN_QUIRK_PATCH_GETKEYSTATE) {
switch (message) {
case WM_KEYDOWN:
SetSavedKeyState(wparam);
break;
case WM_KEYUP:
UnsetSavedKeyState(wparam);
break;
// Clear out the saved keystate whenever the Flash thread loses focus.
case WM_KILLFOCUS:
case WM_SETFOCUS:
if (::GetCurrentThreadId() != ::GetWindowThreadProcessId(
reinterpret_cast<HWND>(wparam), NULL)) {
ClearSavedKeyState();
}
break;
default:
break;
}
}
LRESULT result;
uint32 old_message = delegate->last_message_;
delegate->last_message_ = message;
@ -1324,9 +1106,6 @@ bool WebPluginDelegateImpl::PlatformSetPluginHasFocus(bool focused) {
focus_event.wParam = 0;
focus_event.lParam = 0;
if (GetQuirks() & PLUGIN_QUIRK_PATCH_GETKEYSTATE)
ClearSavedKeyState();
instance()->NPP_HandleEvent(&focus_event);
return true;
}
@ -1446,13 +1225,6 @@ bool WebPluginDelegateImpl::PlatformHandleInputEvent(
return false;
}
if (GetQuirks() & PLUGIN_QUIRK_PATCH_GETKEYSTATE) {
if (np_event.event == WM_KEYDOWN)
SetSavedKeyState(np_event.wParam);
else if (np_event.event == WM_KEYUP)
UnsetSavedKeyState(np_event.wParam);
}
// Allow this plug-in to access this IME emulator through IMM32 API while the
// plug-in is processing this event.
if (GetQuirks() & PLUGIN_QUIRK_EMULATE_IME) {