Bug 1165903: For Windows NPAPI do window re-parenting in the chrome process to allow for sandboxing. r=jimm

This commit is contained in:
Bob Owen 2015-06-15 16:08:51 +01:00
Родитель bf0d1d0f6f
Коммит dce35c582d
14 изменённых файлов: 132 добавлений и 28 удалений

Просмотреть файл

@ -1207,6 +1207,7 @@ pref("security.sandbox.windows.log", false);
// 3 - the strongest settings we seem to be able to use without breaking
// everything, but will probably cause some functionality restrictions
pref("dom.ipc.plugins.sandbox-level.default", 0);
pref("dom.ipc.plugins.sandbox-level.flash", 0);
#if defined(MOZ_CONTENT_SANDBOX)
// This controls the strength of the Windows content process sandbox for testing

Просмотреть файл

@ -41,6 +41,12 @@ parent:
* native HWND of the plugin widget.
*/
sync GetNativePluginPort() returns (uintptr_t value);
/**
* Sends an NS_NATIVE_CHILD_WINDOW to be adopted by the widget's native window
* on the chrome side. This is only currently used on Windows.
*/
sync SetNativeChildWindow(uintptr_t childWindow);
};
}

Просмотреть файл

@ -49,7 +49,7 @@ public:
return NS_OK;
}
nsresult GetPluginWidget(nsIWidget **aWidget) {
nsresult GetPluginWidget(nsIWidget **aWidget) const {
NS_IF_ADDREF(*aWidget = mWidget);
return NS_OK;
}

Просмотреть файл

@ -68,7 +68,10 @@ intr protocol PPluginInstance
child:
intr __delete__();
intr NPP_SetWindow(NPRemoteWindow window);
// Return value is only used on Windows and only when the window needs its
// parent set to the chrome widget native window.
intr NPP_SetWindow(NPRemoteWindow window)
returns (NPRemoteWindow childWindowToBeAdopted);
intr NPP_GetValue_NPPVpluginWantsAllNetworkStreams()
returns (bool value, NPError result);

Просмотреть файл

@ -1124,7 +1124,8 @@ void PluginInstanceChild::DeleteWindow()
#endif
bool
PluginInstanceChild::AnswerNPP_SetWindow(const NPRemoteWindow& aWindow)
PluginInstanceChild::AnswerNPP_SetWindow(const NPRemoteWindow& aWindow,
NPRemoteWindow* aChildWindowToBeAdopted)
{
PLUGIN_LOG_DEBUG(("%s (aWindow=<window: 0x%lx, x: %d, y: %d, width: %d, height: %d>)",
FULLFUNCTION,
@ -1215,9 +1216,32 @@ PluginInstanceChild::AnswerNPP_SetWindow(const NPRemoteWindow& aWindow)
if (!CreatePluginWindow())
return false;
ReparentPluginWindow(reinterpret_cast<HWND>(aWindow.window));
SizePluginWindow(aWindow.width, aWindow.height);
// If the window is not our parent set the return child window so that
// it can be re-parented in the chrome process. Re-parenting now
// happens there as we might not have sufficient permission.
// Also, this needs to be after SizePluginWindow because SetWindowPos
// relies on things that it sets.
HWND parentWindow = reinterpret_cast<HWND>(aWindow.window);
if (mPluginParentHWND != parentWindow && IsWindow(parentWindow)) {
mPluginParentHWND = parentWindow;
aChildWindowToBeAdopted->window =
reinterpret_cast<uint64_t>(mPluginWindowHWND);
} else {
// Now we know that the window has the correct parent we can show
// it. The actual visibility is controlled by its parent.
// First time round, these calls are made by our caller after the
// parent is set.
ShowWindow(mPluginWindowHWND, SW_SHOWNA);
// This used to be called in SizePluginWindow, but we need to make
// sure that mPluginWindowHWND has had it's parent set correctly,
// otherwise it can cause a focus issue.
SetWindowPos(mPluginWindowHWND, nullptr, 0, 0, aWindow.width,
aWindow.height, SWP_NOZORDER | SWP_NOREPOSITION);
}
mWindow.window = (void*)mPluginWindowHWND;
mWindow.x = aWindow.x;
mWindow.y = aWindow.y;
@ -1405,25 +1429,6 @@ PluginInstanceChild::DestroyPluginWindow()
}
}
void
PluginInstanceChild::ReparentPluginWindow(HWND hWndParent)
{
if (hWndParent != mPluginParentHWND && IsWindow(hWndParent)) {
// Fix the child window's style to be a child window.
LONG_PTR style = GetWindowLongPtr(mPluginWindowHWND, GWL_STYLE);
style |= WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
style &= ~WS_POPUP;
SetWindowLongPtr(mPluginWindowHWND, GWL_STYLE, style);
// Do the reparenting.
SetParent(mPluginWindowHWND, hWndParent);
// Make sure we're visible.
ShowWindow(mPluginWindowHWND, SW_SHOWNA);
}
mPluginParentHWND = hWndParent;
}
void
PluginInstanceChild::SizePluginWindow(int width,
int height)
@ -1431,8 +1436,6 @@ PluginInstanceChild::SizePluginWindow(int width,
if (mPluginWindowHWND) {
mPluginSize.x = width;
mPluginSize.y = height;
SetWindowPos(mPluginWindowHWND, nullptr, 0, 0, width, height,
SWP_NOZORDER | SWP_NOREPOSITION);
}
}

Просмотреть файл

@ -65,7 +65,8 @@ class PluginInstanceChild : public PPluginInstanceChild
#endif
protected:
virtual bool AnswerNPP_SetWindow(const NPRemoteWindow& window) override;
bool AnswerNPP_SetWindow(const NPRemoteWindow& window,
NPRemoteWindow* aChildWindowToBeAdopted) override;
virtual bool
AnswerNPP_GetValue_NPPVpluginWantsAllNetworkStreams(bool* wantsAllStreams, NPError* rv) override;
@ -278,7 +279,6 @@ private:
static bool RegisterWindowClass();
bool CreatePluginWindow();
void DestroyPluginWindow();
void ReparentPluginWindow(HWND hWndParent);
void SizePluginWindow(int width, int height);
int16_t WinlessHandleEvent(NPEvent& event);
void CreateWinlessPopupSurrogate();

Просмотреть файл

@ -49,6 +49,8 @@
#include "mozilla/plugins/PluginSurfaceParent.h"
#include "nsClassHashtable.h"
#include "nsHashKeys.h"
#include "nsIWidget.h"
#include "nsPluginNativeWindow.h"
extern const wchar_t* kFlashFullscreenClass;
#elif defined(MOZ_WIDGET_GTK)
#include <gdk/gdk.h>
@ -1025,8 +1027,30 @@ PluginInstanceParent::NPP_SetWindow(const NPWindow* aWindow)
window.colormap = ws_info->colormap;
#endif
if (!CallNPP_SetWindow(window))
NPRemoteWindow childWindow;
if (!CallNPP_SetWindow(window, &childWindow)) {
return NPERR_GENERIC_ERROR;
}
#if defined(XP_WIN)
// If a child window is returned it means that we need to re-parent it.
if (childWindow.window) {
nsCOMPtr<nsIWidget> widget;
static_cast<const nsPluginNativeWindow*>(aWindow)->
GetPluginWidget(getter_AddRefs(widget));
if (widget) {
widget->SetNativeData(NS_NATIVE_CHILD_WINDOW,
static_cast<uintptr_t>(childWindow.window));
}
// Now it has got the correct parent, make sure it is visible.
// In subsequent calls to SetWindow these calls happen in the Child.
HWND childHWND = reinterpret_cast<HWND>(childWindow.window);
ShowWindow(childHWND, SW_SHOWNA);
SetWindowPos(childHWND, nullptr, 0, 0, window.width, window.height,
SWP_NOZORDER | SWP_NOREPOSITION);
}
#endif
return NPERR_NO_ERROR;
}

Просмотреть файл

@ -210,5 +210,20 @@ PluginWidgetParent::RecvGetNativePluginPort(uintptr_t* value)
return true;
}
bool
PluginWidgetParent::RecvSetNativeChildWindow(const uintptr_t& aChildWindow)
{
#if defined(XP_WIN)
ENSURE_CHANNEL;
PWLOG("PluginWidgetParent::RecvSetNativeChildWindow(%p)\n",
static_cast<void*>(aChildWindow));
mWidget->SetNativeData(NS_NATIVE_CHILD_WINDOW, aChildWindow);
return true;
#else
NS_NOTREACHED("PluginWidgetParent::RecvSetNativeChildWindow not implemented!");
return false;
#endif
}
} // namespace plugins
} // namespace mozilla

Просмотреть файл

@ -31,6 +31,7 @@ public:
virtual bool RecvCreate(nsresult* aResult) override;
virtual bool RecvSetFocus(const bool& aRaise) override;
virtual bool RecvGetNativePluginPort(uintptr_t* value) override;
bool RecvSetNativeChildWindow(const uintptr_t& aChildWindow) override;
// Helper for compositor checks on the channel
bool ActorDestroyed() { return !mWidget; }

Просмотреть файл

@ -141,6 +141,29 @@ PluginWidgetProxy::GetNativeData(uint32_t aDataType)
return (void*)value;
}
#if defined(XP_WIN)
void
PluginWidgetProxy::SetNativeData(uint32_t aDataType, uintptr_t aVal)
{
if (!mActor) {
return;
}
auto tab = static_cast<mozilla::dom::TabChild*>(mActor->Manager());
if (tab && tab->IsDestroyed()) {
return;
}
switch (aDataType) {
case NS_NATIVE_CHILD_WINDOW:
mActor->SendSetNativeChildWindow(aVal);
break;
default:
NS_ERROR("SetNativeData called with unsupported data type.");
}
}
#endif
NS_IMETHODIMP
PluginWidgetProxy::SetFocus(bool aRaise)
{

Просмотреть файл

@ -43,6 +43,9 @@ public:
virtual nsIWidget* GetParent(void) override;
virtual void* GetNativeData(uint32_t aDataType) override;
#if defined(XP_WIN)
void SetNativeData(uint32_t aDataType, uintptr_t aVal) override;
#endif
virtual nsTransparencyMode GetTransparencyMode() override
{ return eTransparencyOpaque; }
virtual void GetWindowClipRegion(nsTArray<nsIntRect>* aRects) override;

Просмотреть файл

@ -109,6 +109,7 @@ typedef void* nsNativeWidget;
#define NS_NATIVE_TSF_CATEGORY_MGR 101
#define NS_NATIVE_TSF_DISPLAY_ATTR_MGR 102
#define NS_NATIVE_ICOREWINDOW 103 // winrt specific
#define NS_NATIVE_CHILD_WINDOW 104
#endif
#if defined(MOZ_WIDGET_GTK)
// set/get nsPluginNativeWindowGtk, e10s specific

Просмотреть файл

@ -2972,6 +2972,29 @@ void* nsWindow::GetNativeData(uint32_t aDataType)
return nullptr;
}
void
nsWindow::SetNativeData(uint32_t aDataType, uintptr_t aVal)
{
switch (aDataType) {
case NS_NATIVE_CHILD_WINDOW:
{
HWND childWindow = reinterpret_cast<HWND>(aVal);
// Make sure the window is styled to be a child window.
LONG_PTR style = GetWindowLongPtr(childWindow, GWL_STYLE);
style |= WS_CHILD;
style &= ~WS_POPUP;
SetWindowLongPtr(childWindow, GWL_STYLE, style);
// Do the reparenting.
::SetParent(childWindow, mWnd);
break;
}
default:
NS_ERROR("SetNativeData called with unsupported data type.");
}
}
// Free some native data according to aDataType
void nsWindow::FreeNativeData(void * data, uint32_t aDataType)
{

Просмотреть файл

@ -133,6 +133,7 @@ public:
bool aIncludeChildren = false);
NS_IMETHOD Invalidate(const nsIntRect & aRect);
virtual void* GetNativeData(uint32_t aDataType);
void SetNativeData(uint32_t aDataType, uintptr_t aVal) override;
virtual void FreeNativeData(void * data, uint32_t aDataType);
NS_IMETHOD SetTitle(const nsAString& aTitle);
NS_IMETHOD SetIcon(const nsAString& aIconSpec);