Bug 820170 - Wrapping nodes into documents compartment. r=bholley

This commit is contained in:
Gabor Krizsanits 2013-04-16 11:31:26 +02:00
parent 6311c49742
commit 93fd95ba5e
4 changed files with 73 additions and 41 deletions

View File

@ -1852,6 +1852,13 @@ nsDocument::Init()
mRadioGroups.Init();
mCustomPrototypes.Init();
// If after creation the owner js global is not set for a document
// we use the default compartment for this document, instead of creating
// wrapper in some random compartment when the document is exposed to js
// via some events.
mScopeObject = do_GetWeakReference(xpc::GetNativeForGlobal(xpc::GetJunkScope()));
MOZ_ASSERT(mScopeObject);
// Force initialization.
nsINode::nsSlots* slots = Slots();

View File

@ -1517,6 +1517,29 @@ XULDocument::GetHeight(ErrorResult& aRv)
return height;
}
JSObject*
GetScopeObjectOfNode(nsIDOMNode* node)
{
MOZ_ASSERT(node, "Must not be called with null.")
// Window root occasionally keeps alive a node of a document whose
// window is already dead. If in this brief period someone calls
// GetPopupNode and we return that node, nsNodeSH::PreCreate will throw,
// because it will not know which scope this node belongs to. Returning
// an orphan node like that to JS would be a bug anyway, so to avoid
// this, let's do the same check as nsNodeSH::PreCreate does to
// determine the scope and if it fails let's just return null in
// XULDocument::GetPopupNode.
nsCOMPtr<nsINode> inode = do_QueryInterface(node);
MOZ_ASSERT(inode, "How can this happen?");
nsIDocument* doc = inode->OwnerDoc();
MOZ_ASSERT(inode, "This should never happen.");
nsIGlobalObject* global = doc->GetScopeObject();
return global ? global->GetGlobalJSObject() : nullptr;
}
//----------------------------------------------------------------------
//
// nsIDOMXULDocument interface
@ -1539,8 +1562,10 @@ XULDocument::GetPopupNode(nsIDOMNode** aNode)
}
}
if (node && nsContentUtils::CanCallerAccess(node))
node.swap(*aNode);
if (node && nsContentUtils::CanCallerAccess(node)
&& GetScopeObjectOfNode(node)) {
node.swap(*aNode);
}
return NS_OK;
}

View File

@ -5550,18 +5550,6 @@ nsNodeSH::PreCreate(nsISupports *nativeObj, JSContext *cx, JSObject *globalObj,
// See http://bugzilla.mozilla.org/show_bug.cgi?id=227417
nsIDocument* doc = node->OwnerDoc();
// If we have a document, make sure one of these is true
// (1) it has a script handling object,
// (2) has had one, or has been marked to have had one,
// (3) we are running a privileged script.
// Event handling is possible only if (1). If (2) event handling is prevented.
// If document has never had a script handling object,
// untrusted scripts (3) shouldn't touch it!
bool hasHadScriptHandlingObject = false;
NS_ENSURE_STATE(doc->GetScriptHandlingObject(hasHadScriptHandlingObject) ||
hasHadScriptHandlingObject ||
nsContentUtils::IsCallerChrome());
nsINode *native_parent;
bool nodeIsElement = node->IsElement();
@ -5610,26 +5598,17 @@ nsNodeSH::PreCreate(nsISupports *nativeObj, JSContext *cx, JSObject *globalObj,
}
} else {
// We're called for a document object; set the parent to be the
// document's global object, if there is one
// document's global object
// Get the scope object from the document.
nsISupports *scope = doc->GetScopeObject();
// Document should know its global but if the owner window of the
// document is already dead at this point, then just throw.
nsIGlobalObject* scope = doc->GetScopeObject();
NS_ENSURE_TRUE(scope, NS_ERROR_UNEXPECTED);
if (scope) {
jsval v;
nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
nsresult rv = WrapNative(cx, globalObj, scope, false, &v,
getter_AddRefs(holder));
NS_ENSURE_SUCCESS(rv, rv);
holder->GetJSObject(parentObj);
}
else {
// No global object reachable from this document, use the
// global object that was passed to this method.
*parentObj = globalObj;
}
*parentObj = scope->GetGlobalJSObject();
// Guarding against the case when the native global is still alive
// but the JS global is not.
NS_ENSURE_TRUE(*parentObj, NS_ERROR_UNEXPECTED);
// No slim wrappers for a document's scope object.
return node->ChromeOnlyAccess() ?

View File

@ -32,8 +32,17 @@ function checkResults(xhr)
return true;
}
var httpServersClosed = 0;
function finishIfDone()
{
if (++httpServersClosed == 2)
do_test_finished();
}
function run_test()
{
do_test_pending();
httpserver.registerPathHandler(testpath, serverHandler);
httpserver.start(4444);
@ -45,14 +54,6 @@ function run_test()
var res = cu.evalInSandbox('var sync = createXHR("4444/simple"); sync.send(null); sync', sb);
checkResults(res);
// Test async XHR sending
var async = cu.evalInSandbox('var async = createXHR("4444/simple", true); async', sb);
async.addEventListener("readystatechange", function(event) {
if (checkResults(async))
httpserver.stop(do_test_finished);
}, false);
async.send(null);
// negative test sync XHR sending (to ensure that the xhr do not have chrome caps, see bug 779821)
try {
cu.evalInSandbox('var createXHR = ' + createXHR.toString(), sb);
@ -61,8 +62,28 @@ function run_test()
} catch (e) {
do_check_true(true);
}
httpserver2.stop(finishIfDone);
// Test async XHR sending
sb.finish = function(){
httpserver.stop(finishIfDone);
}
sb.checkResults = checkResults;
do_test_pending();
sb.do_check_eq = do_check_eq;
function changeListener(event) {
if (checkResults(async))
finish();
}
var async = cu.evalInSandbox('var async = createXHR("4444/simple", true);' +
'async.addEventListener("readystatechange", ' +
changeListener.toString() + ', false);' +
'async', sb);
async.send(null);
}
function serverHandler(metadata, response)