mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-12 02:31:41 +00:00
Bug 1017310 - Associate JS compartments with add-on chrome XBL (r=bholley)
This commit is contained in:
parent
f0e84d2f79
commit
64b94c4b6d
@ -1404,7 +1404,8 @@ WrapNativeParent(JSContext* cx, T* p, nsWrapperCache* cache,
|
||||
}
|
||||
|
||||
// If useXBLScope is true, it means that the canonical reflector for this
|
||||
// native object should live in the XBL scope.
|
||||
// native object should live in the content XBL scope. Note that we never put
|
||||
// anonymous content inside an add-on scope.
|
||||
if (xpc::IsInContentXBLScope(parent)) {
|
||||
return parent;
|
||||
}
|
||||
|
@ -639,7 +639,8 @@ nsBindingManager::GetBindingImplementation(nsIContent* aContent, REFNSIID aIID,
|
||||
// If we're using an XBL scope, we need to use the Xray view to the bound
|
||||
// content in order to view the full array of methods defined in the
|
||||
// binding, some of which may not be exposed on the prototype of
|
||||
// untrusted content.
|
||||
// untrusted content. We don't need to consider add-on scopes here
|
||||
// because they're chrome-only and no Xrays are involved.
|
||||
//
|
||||
// If there's no separate XBL scope, or if the reflector itself lives in
|
||||
// the XBL scope, we'll end up with the global of the reflector, and this
|
||||
|
@ -924,7 +924,8 @@ GetOrCreateMapEntryForPrototype(JSContext *cx, JS::Handle<JSObject*> proto)
|
||||
: "__XBLClassObjectMap__";
|
||||
|
||||
// Now, enter the XBL scope, since that's where we need to operate, and wrap
|
||||
// the proto accordingly.
|
||||
// the proto accordingly. We hang the map off of the content XBL scope for
|
||||
// content, and the Window for chrome (whether add-ons are involved or not).
|
||||
JS::Rooted<JSObject*> scope(cx, xpc::GetXBLScopeOrGlobal(cx, proto));
|
||||
JS::Rooted<JSObject*> wrappedProto(cx, proto);
|
||||
JSAutoCompartment ac(cx, scope);
|
||||
@ -980,6 +981,8 @@ nsXBLBinding::DoInitJSClass(JSContext *cx,
|
||||
// but we need to make sure never to assume that the the reflector and
|
||||
// prototype are same-compartment with the bound document.
|
||||
JS::Rooted<JSObject*> global(cx, js::GetGlobalForObjectCrossCompartment(obj));
|
||||
|
||||
// We never store class objects in add-on scopes.
|
||||
JS::Rooted<JSObject*> xblScope(cx, xpc::GetXBLScopeOrGlobal(cx, global));
|
||||
|
||||
JS::Rooted<JSObject*> parent_proto(cx);
|
||||
@ -1117,8 +1120,12 @@ nsXBLBinding::LookupMember(JSContext* aCx, JS::Handle<jsid> aId,
|
||||
// never get here. But on the off-chance that someone adds new callsites to
|
||||
// LookupMember, we do a release-mode assertion as belt-and-braces.
|
||||
// We do a release-mode assertion here to be extra safe.
|
||||
//
|
||||
// This code is only called for content XBL, so we don't have to worry about
|
||||
// add-on scopes here.
|
||||
JS::Rooted<JSObject*> boundScope(aCx,
|
||||
js::GetGlobalForObjectCrossCompartment(mBoundElement->GetWrapper()));
|
||||
MOZ_RELEASE_ASSERT(!xpc::IsInAddonScope(boundScope));
|
||||
MOZ_RELEASE_ASSERT(!xpc::IsInContentXBLScope(boundScope));
|
||||
JS::Rooted<JSObject*> xblScope(aCx, xpc::GetXBLScope(aCx, boundScope));
|
||||
NS_ENSURE_TRUE(xblScope, false);
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include "nsXBLPrototypeBinding.h"
|
||||
#include "nsXBLProtoImplProperty.h"
|
||||
#include "nsIURI.h"
|
||||
#include "mozilla/AddonPathService.h"
|
||||
#include "mozilla/dom/XULElementBinding.h"
|
||||
#include "xpcpublic.h"
|
||||
#include "js/CharacterEncoding.h"
|
||||
@ -75,9 +76,10 @@ nsXBLProtoImpl::InstallImplementation(nsXBLPrototypeBinding* aPrototypeBinding,
|
||||
|
||||
// First, start by entering the compartment of the XBL scope. This may or may
|
||||
// not be the same compartment as globalObject.
|
||||
JSAddonId* addonId = MapURIToAddonID(aPrototypeBinding->BindingURI());
|
||||
JS::Rooted<JSObject*> globalObject(cx,
|
||||
GetGlobalForObjectCrossCompartment(targetClassObject));
|
||||
JS::Rooted<JSObject*> scopeObject(cx, xpc::GetXBLScopeOrGlobal(cx, globalObject));
|
||||
JS::Rooted<JSObject*> scopeObject(cx, xpc::GetScopeForXBLExecution(cx, globalObject, addonId));
|
||||
NS_ENSURE_TRUE(scopeObject, NS_ERROR_OUT_OF_MEMORY);
|
||||
JSAutoCompartment ac(cx, scopeObject);
|
||||
|
||||
@ -132,13 +134,25 @@ nsXBLProtoImpl::InstallImplementation(nsXBLPrototypeBinding* aPrototypeBinding,
|
||||
if (propertyHolder != targetClassObject) {
|
||||
AssertSameCompartment(propertyHolder, scopeObject);
|
||||
AssertSameCompartment(targetClassObject, globalObject);
|
||||
bool inContentXBLScope = xpc::IsInContentXBLScope(scopeObject);
|
||||
for (nsXBLProtoImplMember* curr = mMembers; curr; curr = curr->GetNext()) {
|
||||
if (curr->ShouldExposeToUntrustedContent()) {
|
||||
if (!inContentXBLScope || curr->ShouldExposeToUntrustedContent()) {
|
||||
JS::Rooted<jsid> id(cx);
|
||||
JS::TwoByteChars chars(curr->GetName(), NS_strlen(curr->GetName()));
|
||||
bool ok = JS_CharsToId(cx, chars, &id);
|
||||
NS_ENSURE_TRUE(ok, NS_ERROR_UNEXPECTED);
|
||||
JS_CopyPropertyFrom(cx, id, targetClassObject, propertyHolder);
|
||||
|
||||
bool found;
|
||||
ok = JS_HasPropertyById(cx, propertyHolder, id, &found);
|
||||
NS_ENSURE_TRUE(ok, NS_ERROR_UNEXPECTED);
|
||||
if (!found) {
|
||||
// Some members don't install anything in InstallMember (e.g.,
|
||||
// nsXBLProtoImplAnonymousMethod). We need to skip copying in
|
||||
// those cases.
|
||||
continue;
|
||||
}
|
||||
|
||||
ok = JS_CopyPropertyFrom(cx, id, targetClassObject, propertyHolder);
|
||||
NS_ENSURE_TRUE(ok, NS_ERROR_UNEXPECTED);
|
||||
}
|
||||
}
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include "nsIURI.h"
|
||||
#include "nsXBLSerialize.h"
|
||||
#include "nsXBLPrototypeBinding.h"
|
||||
#include "mozilla/AddonPathService.h"
|
||||
#include "mozilla/dom/BindingUtils.h"
|
||||
#include "mozilla/dom/ScriptSettings.h"
|
||||
#include "nsGlobalWindow.h"
|
||||
@ -411,9 +412,11 @@ nsXBLProtoImplField::InstallField(JS::Handle<JSObject*> aBoundNode,
|
||||
NS_ASSERTION(!::JS_IsExceptionPending(cx),
|
||||
"Shouldn't get here when an exception is pending!");
|
||||
|
||||
JSAddonId* addonId = MapURIToAddonID(aBindingDocURI);
|
||||
|
||||
// First, enter the xbl scope, wrap the node, and use that as the scope for
|
||||
// the evaluation.
|
||||
JS::Rooted<JSObject*> scopeObject(cx, xpc::GetXBLScopeOrGlobal(cx, aBoundNode));
|
||||
JS::Rooted<JSObject*> scopeObject(cx, xpc::GetScopeForXBLExecution(cx, aBoundNode, addonId));
|
||||
NS_ENSURE_TRUE(scopeObject, NS_ERROR_OUT_OF_MEMORY);
|
||||
JSAutoCompartment ac(cx, scopeObject);
|
||||
|
||||
|
@ -105,6 +105,7 @@ nsXBLProtoImplMethod::InstallMember(JSContext* aCx,
|
||||
|
||||
JS::Rooted<JSObject*> globalObject(aCx, JS_GetGlobalForObject(aCx, aTargetClassObject));
|
||||
MOZ_ASSERT(xpc::IsInContentXBLScope(globalObject) ||
|
||||
xpc::IsInAddonScope(globalObject) ||
|
||||
globalObject == xpc::GetXBLScope(aCx, globalObject));
|
||||
|
||||
JS::Rooted<JSObject*> jsMethodObject(aCx, GetCompiledMethod());
|
||||
@ -264,7 +265,7 @@ nsXBLProtoImplMethod::Write(nsIObjectOutputStream* aStream)
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsXBLProtoImplAnonymousMethod::Execute(nsIContent* aBoundElement)
|
||||
nsXBLProtoImplAnonymousMethod::Execute(nsIContent* aBoundElement, JSAddonId* aAddonId)
|
||||
{
|
||||
NS_PRECONDITION(IsCompiled(), "Can't execute uncompiled method");
|
||||
|
||||
@ -308,7 +309,7 @@ nsXBLProtoImplAnonymousMethod::Execute(nsIContent* aBoundElement)
|
||||
MOZ_ASSERT(cx == nsContentUtils::GetCurrentJSContext());
|
||||
|
||||
JS::Rooted<JSObject*> thisObject(cx, &v.toObject());
|
||||
JS::Rooted<JSObject*> scopeObject(cx, xpc::GetXBLScopeOrGlobal(cx, globalObject));
|
||||
JS::Rooted<JSObject*> scopeObject(cx, xpc::GetScopeForXBLExecution(cx, globalObject, aAddonId));
|
||||
NS_ENSURE_TRUE(scopeObject, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
JSAutoCompartment ac(cx, scopeObject);
|
||||
|
@ -139,7 +139,7 @@ public:
|
||||
nsXBLProtoImplMethod(aName)
|
||||
{}
|
||||
|
||||
nsresult Execute(nsIContent* aBoundElement);
|
||||
nsresult Execute(nsIContent* aBoundElement, JSAddonId* aAddonId);
|
||||
|
||||
// Override InstallMember; these methods never get installed as members on
|
||||
// binding instantiations (though they may hang out in mMembers on the
|
||||
|
@ -130,6 +130,7 @@ nsXBLProtoImplProperty::InstallMember(JSContext *aCx,
|
||||
MOZ_ASSERT(js::IsObjectInContextCompartment(aTargetClassObject, aCx));
|
||||
JS::Rooted<JSObject*> globalObject(aCx, JS_GetGlobalForObject(aCx, aTargetClassObject));
|
||||
MOZ_ASSERT(xpc::IsInContentXBLScope(globalObject) ||
|
||||
xpc::IsInAddonScope(globalObject) ||
|
||||
globalObject == xpc::GetXBLScope(aCx, globalObject));
|
||||
|
||||
JS::Rooted<JSObject*> getter(aCx, mGetter.GetJSFunction());
|
||||
|
@ -39,6 +39,7 @@
|
||||
|
||||
#include "nsCSSRuleProcessor.h"
|
||||
#include "nsXBLResourceLoader.h"
|
||||
#include "mozilla/AddonPathService.h"
|
||||
#include "mozilla/dom/CDATASection.h"
|
||||
#include "mozilla/dom/Comment.h"
|
||||
#include "mozilla/dom/Element.h"
|
||||
@ -249,7 +250,7 @@ nsXBLPrototypeBinding::BindingAttached(nsIContent* aBoundElement)
|
||||
{
|
||||
if (mImplementation && mImplementation->CompiledMembers() &&
|
||||
mImplementation->mConstructor)
|
||||
return mImplementation->mConstructor->Execute(aBoundElement);
|
||||
return mImplementation->mConstructor->Execute(aBoundElement, MapURIToAddonID(mBindingURI));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -258,7 +259,7 @@ nsXBLPrototypeBinding::BindingDetached(nsIContent* aBoundElement)
|
||||
{
|
||||
if (mImplementation && mImplementation->CompiledMembers() &&
|
||||
mImplementation->mDestructor)
|
||||
return mImplementation->mDestructor->Execute(aBoundElement);
|
||||
return mImplementation->mDestructor->Execute(aBoundElement, MapURIToAddonID(mBindingURI));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -35,6 +35,7 @@
|
||||
#include "nsGkAtoms.h"
|
||||
#include "nsIXPConnect.h"
|
||||
#include "nsIDOMScriptObjectFactory.h"
|
||||
#include "mozilla/AddonPathService.h"
|
||||
#include "nsDOMCID.h"
|
||||
#include "nsUnicharUtils.h"
|
||||
#include "nsCRT.h"
|
||||
@ -282,8 +283,10 @@ nsXBLPrototypeHandler::ExecuteHandler(EventTarget* aTarget,
|
||||
rv = EnsureEventHandler(boundGlobal, boundContext, onEventAtom, &handler);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
JSAddonId* addonId = MapURIToAddonID(mPrototypeBinding->DocURI());
|
||||
|
||||
JS::Rooted<JSObject*> globalObject(cx, boundGlobal->GetGlobalJSObject());
|
||||
JS::Rooted<JSObject*> scopeObject(cx, xpc::GetXBLScopeOrGlobal(cx, globalObject));
|
||||
JS::Rooted<JSObject*> scopeObject(cx, xpc::GetScopeForXBLExecution(cx, globalObject, addonId));
|
||||
NS_ENSURE_TRUE(scopeObject, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
// Bind it to the bound element. Note that if we're using a separate XBL scope,
|
||||
@ -358,8 +361,10 @@ nsXBLPrototypeHandler::EnsureEventHandler(nsIScriptGlobalObject* aGlobal,
|
||||
nsDependentString handlerText(mHandlerText);
|
||||
NS_ENSURE_TRUE(!handlerText.IsEmpty(), NS_ERROR_FAILURE);
|
||||
|
||||
JSAddonId* addonId = MapURIToAddonID(mPrototypeBinding->DocURI());
|
||||
|
||||
JS::Rooted<JSObject*> globalObject(cx, aGlobal->GetGlobalJSObject());
|
||||
JS::Rooted<JSObject*> scopeObject(cx, xpc::GetXBLScopeOrGlobal(cx, globalObject));
|
||||
JS::Rooted<JSObject*> scopeObject(cx, xpc::GetScopeForXBLExecution(cx, globalObject, addonId));
|
||||
NS_ENSURE_TRUE(scopeObject, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
nsAutoCString bindingURI;
|
||||
|
@ -262,7 +262,8 @@ XPCWrappedNativeScope::AllowContentXBLScope()
|
||||
}
|
||||
|
||||
namespace xpc {
|
||||
JSObject *GetXBLScope(JSContext *cx, JSObject *contentScopeArg)
|
||||
JSObject *
|
||||
GetXBLScope(JSContext *cx, JSObject *contentScopeArg)
|
||||
{
|
||||
MOZ_ASSERT(!IsInAddonScope(contentScopeArg));
|
||||
|
||||
@ -275,6 +276,32 @@ JSObject *GetXBLScope(JSContext *cx, JSObject *contentScopeArg)
|
||||
return scope;
|
||||
}
|
||||
|
||||
JSObject *
|
||||
GetScopeForXBLExecution(JSContext *cx, HandleObject contentScope, JSAddonId *addonId)
|
||||
{
|
||||
MOZ_RELEASE_ASSERT(!IsInAddonScope(contentScope));
|
||||
|
||||
RootedObject global(cx, js::GetGlobalForObjectCrossCompartment(contentScope));
|
||||
if (IsInContentXBLScope(contentScope))
|
||||
return global;
|
||||
|
||||
JSAutoCompartment ac(cx, contentScope);
|
||||
XPCWrappedNativeScope *nativeScope = EnsureCompartmentPrivate(contentScope)->scope;
|
||||
|
||||
RootedObject scope(cx);
|
||||
if (nativeScope->UseContentXBLScope())
|
||||
scope = nativeScope->EnsureContentXBLScope(cx);
|
||||
else if (addonId && CompartmentPerAddon())
|
||||
scope = nativeScope->EnsureAddonScope(cx, addonId);
|
||||
else
|
||||
scope = global;
|
||||
|
||||
NS_ENSURE_TRUE(scope, nullptr); // See bug 858642.
|
||||
scope = js::UncheckedUnwrap(scope);
|
||||
JS::ExposeObjectToActiveJS(scope);
|
||||
return scope;
|
||||
}
|
||||
|
||||
bool
|
||||
AllowContentXBLScope(JSCompartment *c)
|
||||
{
|
||||
|
@ -97,6 +97,13 @@ GetXBLScopeOrGlobal(JSContext *cx, JSObject *obj)
|
||||
return GetXBLScope(cx, obj);
|
||||
}
|
||||
|
||||
// This function is similar to GetXBLScopeOrGlobal. However, if |obj| is a
|
||||
// chrome scope, then it will return an add-on scope if addonId is non-null.
|
||||
// Like GetXBLScopeOrGlobal, it returns the scope of |obj| if it's already a
|
||||
// content XBL scope. But it asserts that |obj| is not an add-on scope.
|
||||
JSObject *
|
||||
GetScopeForXBLExecution(JSContext *cx, JS::HandleObject obj, JSAddonId *addonId);
|
||||
|
||||
// Returns whether XBL scopes have been explicitly disabled for code running
|
||||
// in this compartment. See the comment around mAllowContentXBLScope.
|
||||
bool
|
||||
|
Loading…
x
Reference in New Issue
Block a user