Bug 733035 - postMessage support for sandboxes. r=khuey

This commit is contained in:
Gabor Krizsanits 2012-04-05 18:33:20 -04:00
parent 477e42fd5d
commit c306ffc838
6 changed files with 85 additions and 20 deletions

View File

@ -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<nsGlobalWindow> 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<nsIURI> 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<nsIDocument> doc = do_QueryInterface(callerInnerWin->mDocument);
nsCOMPtr<nsIDocument> 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<PostMessageEvent> event =
new PostMessageEvent(nsContentUtils::IsCallerChrome()
new PostMessageEvent(nsContentUtils::IsCallerChrome() || !callerInnerWin
? nsnull
: callerInnerWin->GetOuterWindowInternal(),
origin,

View File

@ -575,6 +575,7 @@ protected:
nsresult FinalClose();
void FreeInnerObjects();
JSObject *CallerGlobal();
nsGlobalWindow *CallerInnerWindow();
nsresult InnerSetNewDocument(nsIDocument* aDocument);

View File

@ -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))

View File

@ -0,0 +1,36 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Testing postMessage from sandbox</title>
<script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
<script type="application/javascript">
SimpleTest.waitForExplicitFinish();
function doTest() {
var sandbox = Components.utils.Sandbox("http://mochi.test:8888/", { wantXrays: true });
var win = window.frames["sameDomain"];
sandbox.win = win;
sandbox.is = is;
sandbox.done = SimpleTest.finish;
result = Components.utils.evalInSandbox('var data = {some:"data"};'
+'win.addEventListener("message", receiveMessage, false);'
+'function receiveMessage(event)'
+'{'
+' is(JSON.stringify(event.data), JSON.stringify(data), "Received the expected message data");'
+' done();'
+'}'
+'win.postMessage(data, "*")'
, sandbox);
}
addLoadEvent(doTest);
</script>
</head>
<body>
<iframe src="http://mochi.test:8888/"
id="sameDomain" name="sameDomain">
</iframe>
</body>
</html>

View File

@ -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

View File

@ -45,9 +45,6 @@ class nsIPrincipal;
namespace xpc {
nsIPrincipal *
GetCompartmentPrincipal(JSCompartment *compartment);
class AccessCheck {
public:
static bool isSameOrigin(JSCompartment *a, JSCompartment *b);