From c306ffc838065dd596d0ef1f79bec77cecf34d16 Mon Sep 17 00:00:00 2001 From: Gabor Krizsanits Date: Thu, 5 Apr 2012 18:33:20 -0400 Subject: [PATCH] Bug 733035 - postMessage support for sandboxes. r=khuey --- dom/base/nsGlobalWindow.cpp | 62 ++++++++++++++----- dom/base/nsGlobalWindow.h | 1 + dom/tests/mochitest/chrome/Makefile.in | 1 + .../chrome/test_sandbox_postMessage.html | 36 +++++++++++ js/xpconnect/src/xpcpublic.h | 2 + js/xpconnect/wrappers/AccessCheck.h | 3 - 6 files changed, 85 insertions(+), 20 deletions(-) create mode 100644 dom/tests/mochitest/chrome/test_sandbox_postMessage.html diff --git a/dom/base/nsGlobalWindow.cpp b/dom/base/nsGlobalWindow.cpp index d5cb2c0e2ee..b32be1cb316 100644 --- a/dom/base/nsGlobalWindow.cpp +++ b/dom/base/nsGlobalWindow.cpp @@ -5962,8 +5962,7 @@ nsGlobalWindow::GetFrames(nsIDOMWindow** aFrames) return NS_OK; } -nsGlobalWindow* -nsGlobalWindow::CallerInnerWindow() +JSObject* nsGlobalWindow::CallerGlobal() { JSContext *cx = nsContentUtils::GetCurrentJSContext(); if (!cx) { @@ -5988,6 +5987,21 @@ nsGlobalWindow::CallerInnerWindow() if (!scope) scope = JS_GetGlobalForScopeChain(cx); + return scope; +} + +nsGlobalWindow* +nsGlobalWindow::CallerInnerWindow() +{ + JSContext *cx = nsContentUtils::GetCurrentJSContext(); + if (!cx) { + NS_ERROR("Please don't call this method from C++!"); + + return nsnull; + } + + JSObject *scope = CallerGlobal(); + JSAutoEnterCompartment ac; if (!ac.enter(cx, scope)) return nsnull; @@ -6310,21 +6324,30 @@ nsGlobalWindow::PostMessageMoz(const jsval& aMessage, // First, get the caller's window nsRefPtr callerInnerWin = CallerInnerWindow(); - if (!callerInnerWin) - return NS_OK; - NS_ABORT_IF_FALSE(callerInnerWin->IsInnerWindow(), - "should have gotten an inner window here"); + nsIPrincipal* callerPrin; + if (callerInnerWin) { + NS_ABORT_IF_FALSE(callerInnerWin->IsInnerWindow(), + "should have gotten an inner window here"); - // Compute the caller's origin either from its principal or, in the case the - // principal doesn't carry a URI (e.g. the system principal), the caller's - // document. We must get this now instead of when the event is created and - // dispatched, because ultimately it is the identity of the calling window - // *now* that determines who sent the message (and not an identity which might - // have changed due to intervening navigations). - nsIPrincipal* callerPrin = callerInnerWin->GetPrincipal(); + // Compute the caller's origin either from its principal or, in the case the + // principal doesn't carry a URI (e.g. the system principal), the caller's + // document. We must get this now instead of when the event is created and + // dispatched, because ultimately it is the identity of the calling window + // *now* that determines who sent the message (and not an identity which might + // have changed due to intervening navigations). + callerPrin = callerInnerWin->GetPrincipal(); + } + else { + // In case the global is not a window, it can be a sandbox, and the sandbox's + // principal can be used for the security check. + JSObject *global = CallerGlobal(); + NS_ASSERTION(global, "Why is there no global object?"); + JSCompartment *compartment = js::GetObjectCompartment(global); + callerPrin = xpc::GetCompartmentPrincipal(compartment); + } if (!callerPrin) return NS_OK; - + nsCOMPtr callerOuterURI; if (NS_FAILED(callerPrin->GetURI(getter_AddRefs(callerOuterURI)))) return NS_OK; @@ -6334,15 +6357,20 @@ nsGlobalWindow::PostMessageMoz(const jsval& aMessage, // if the principal has a URI, use that to generate the origin nsContentUtils::GetUTFOrigin(callerPrin, origin); } - else { + else if (callerInnerWin) { // otherwise use the URI of the document to generate origin - nsCOMPtr doc = do_QueryInterface(callerInnerWin->mDocument); + nsCOMPtr doc = do_QueryInterface(callerInnerWin->GetExtantDocument()); if (!doc) return NS_OK; callerOuterURI = doc->GetDocumentURI(); // if the principal has a URI, use that to generate the origin nsContentUtils::GetUTFOrigin(callerOuterURI, origin); } + else { + // in case of a sandbox with a system principal origin can be empty + if (!nsContentUtils::IsSystemPrincipal(callerPrin)) + return NS_OK; + } // Convert the provided origin string into a URI for comparison purposes. // "*" indicates no specific origin is required. @@ -6358,7 +6386,7 @@ nsGlobalWindow::PostMessageMoz(const jsval& aMessage, // Create and asynchronously dispatch a runnable which will handle actual DOM // event creation and dispatch. nsRefPtr event = - new PostMessageEvent(nsContentUtils::IsCallerChrome() + new PostMessageEvent(nsContentUtils::IsCallerChrome() || !callerInnerWin ? nsnull : callerInnerWin->GetOuterWindowInternal(), origin, diff --git a/dom/base/nsGlobalWindow.h b/dom/base/nsGlobalWindow.h index 4015d96bafc..24c975cd333 100644 --- a/dom/base/nsGlobalWindow.h +++ b/dom/base/nsGlobalWindow.h @@ -575,6 +575,7 @@ protected: nsresult FinalClose(); void FreeInnerObjects(); + JSObject *CallerGlobal(); nsGlobalWindow *CallerInnerWindow(); nsresult InnerSetNewDocument(nsIDocument* aDocument); diff --git a/dom/tests/mochitest/chrome/Makefile.in b/dom/tests/mochitest/chrome/Makefile.in index 7d503e8bf42..79e53e1fafc 100644 --- a/dom/tests/mochitest/chrome/Makefile.in +++ b/dom/tests/mochitest/chrome/Makefile.in @@ -77,6 +77,7 @@ _TEST_FILES = \ test_moving_nodeList.xul \ test_callback_wrapping.xul \ window_callback_wrapping.xul \ + test_sandbox_postMessage.html \ $(NULL) ifeq (WINNT,$(OS_ARCH)) diff --git a/dom/tests/mochitest/chrome/test_sandbox_postMessage.html b/dom/tests/mochitest/chrome/test_sandbox_postMessage.html new file mode 100644 index 00000000000..46164a18132 --- /dev/null +++ b/dom/tests/mochitest/chrome/test_sandbox_postMessage.html @@ -0,0 +1,36 @@ + + + + Testing postMessage from sandbox + + + + + + + + + diff --git a/js/xpconnect/src/xpcpublic.h b/js/xpconnect/src/xpcpublic.h index 1b9269b2901..4ef78ba644e 100644 --- a/js/xpconnect/src/xpcpublic.h +++ b/js/xpconnect/src/xpcpublic.h @@ -223,6 +223,8 @@ bool Base64Decode(JSContext *cx, JS::Value val, JS::Value *out); bool StringToJsval(JSContext *cx, nsAString &str, JS::Value *rval); bool NonVoidStringToJsval(JSContext *cx, nsAString &str, JS::Value *rval); +nsIPrincipal *GetCompartmentPrincipal(JSCompartment *compartment); + #ifdef DEBUG void DumpJSHeap(FILE* file); #endif diff --git a/js/xpconnect/wrappers/AccessCheck.h b/js/xpconnect/wrappers/AccessCheck.h index 43e8d3f5c7c..aec1bee51ab 100644 --- a/js/xpconnect/wrappers/AccessCheck.h +++ b/js/xpconnect/wrappers/AccessCheck.h @@ -45,9 +45,6 @@ class nsIPrincipal; namespace xpc { -nsIPrincipal * -GetCompartmentPrincipal(JSCompartment *compartment); - class AccessCheck { public: static bool isSameOrigin(JSCompartment *a, JSCompartment *b);