Bug 897913 part 2. Allow touching interface objects via an Xray even if the page they're in can't touch them. r=bholley,smaug

This commit is contained in:
Boris Zbarsky 2013-08-07 17:40:00 -04:00
Родитель 4b9ed29cef
Коммит ba738ed1e5
5 изменённых файлов: 66 добавлений и 48 удалений

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

@ -3540,6 +3540,14 @@ nsWindowSH::GlobalResolve(nsGlobalWindow *aWin, JSContext *cx,
JS::Rooted<JSObject*> global(cx);
bool defineOnXray = xpc::WrapperFactory::IsXrayWrapper(obj);
if (defineOnXray) {
// Check whether to define this property on the Xray first. This allows
// consumers to opt in to defining on the xray even if they don't want
// to define on the underlying global.
if (name_struct->mConstructorEnabled &&
!(*name_struct->mConstructorEnabled)(cx, obj)) {
return NS_OK;
}
global = js::CheckedUnwrap(obj, /* stopAtOuter = */ false);
if (!global) {
return NS_ERROR_DOM_SECURITY_ERR;
@ -3549,36 +3557,36 @@ nsWindowSH::GlobalResolve(nsGlobalWindow *aWin, JSContext *cx,
global = obj;
}
// Check whether our constructor is enabled after we unwrap Xrays, since
// we don't want to define an interface on the Xray if it's disabled in
// the target global, even if it's enabled in the Xray's global.
if (name_struct->mConstructorEnabled &&
!(*name_struct->mConstructorEnabled)(cx, global)) {
// Check whether to define on the global too. Note that at this point cx
// is in the compartment of global even if we were coming in via an Xray.
bool defineOnGlobal = !name_struct->mConstructorEnabled ||
(*name_struct->mConstructorEnabled)(cx, global);
if (!defineOnGlobal && !defineOnXray) {
return NS_OK;
}
bool enabled;
JS::Rooted<JSObject*> interfaceObject(cx, define(cx, global, id, &enabled));
if (enabled) {
if (!interfaceObject) {
JS::Rooted<JSObject*> interfaceObject(cx, define(cx, global, id,
defineOnGlobal));
if (!interfaceObject) {
return NS_ERROR_FAILURE;
}
if (defineOnXray) {
// This really should be handled by the Xray for the window.
ac.destroy();
if (!JS_WrapObject(cx, interfaceObject.address()) ||
!JS_DefinePropertyById(cx, obj, id,
JS::ObjectValue(*interfaceObject), JS_PropertyStub,
JS_StrictPropertyStub, 0)) {
return NS_ERROR_FAILURE;
}
if (defineOnXray) {
// This really should be handled by the Xray for the window.
ac.destroy();
if (!JS_WrapObject(cx, interfaceObject.address()) ||
!JS_DefinePropertyById(cx, obj, id,
JS::ObjectValue(*interfaceObject), JS_PropertyStub,
JS_StrictPropertyStub, 0)) {
return NS_ERROR_FAILURE;
}
}
*did_resolve = true;
return NS_OK;
}
*did_resolve = true;
return NS_OK;
}
}

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

@ -371,7 +371,7 @@ CreateInterfaceObject(JSContext* cx, JS::Handle<JSObject*> global,
JS::Handle<JSObject*> proto,
const NativeProperties* properties,
const NativeProperties* chromeOnlyProperties,
const char* name)
const char* name, bool defineOnGlobal)
{
JS::Rooted<JSObject*> constructor(cx);
if (constructorClass) {
@ -455,7 +455,7 @@ CreateInterfaceObject(JSContext* cx, JS::Handle<JSObject*> global,
return NULL;
}
if (!DefineConstructor(cx, global, name, constructor)) {
if (defineOnGlobal && !DefineConstructor(cx, global, name, constructor)) {
return nullptr;
}
@ -471,8 +471,9 @@ CreateInterfaceObject(JSContext* cx, JS::Handle<JSObject*> global,
JS::ObjectValue(*proto), JS_PropertyStub,
JS_StrictPropertyStub,
JSPROP_PERMANENT | JSPROP_READONLY) ||
!DefineConstructor(cx, global, namedConstructors->mName,
namedConstructor)) {
(defineOnGlobal &&
!DefineConstructor(cx, global, namedConstructors->mName,
namedConstructor))) {
return nullptr;
}
js::SetReservedSlot(constructor, namedConstructorSlot++,
@ -562,7 +563,7 @@ CreateInterfaceObjects(JSContext* cx, JS::Handle<JSObject*> global,
JS::Heap<JSObject*>* constructorCache, const DOMClass* domClass,
const NativeProperties* properties,
const NativeProperties* chromeOnlyProperties,
const char* name)
const char* name, bool defineOnGlobal)
{
MOZ_ASSERT(protoClass || constructorClass || constructor,
"Need at least one class or a constructor!");
@ -612,7 +613,8 @@ CreateInterfaceObjects(JSContext* cx, JS::Handle<JSObject*> global,
interface = CreateInterfaceObject(cx, global, constructorProto,
constructorClass, constructor,
ctorNargs, namedConstructors, proto,
properties, chromeOnlyProperties, name);
properties, chromeOnlyProperties, name,
defineOnGlobal);
if (!interface) {
if (protoCache) {
// If we fail we need to make sure to clear the value of protoCache we

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

@ -364,6 +364,12 @@ struct NamedConstructor
* on objects in chrome compartments. This must be null if the
* interface doesn't have any ChromeOnly properties or if the
* object is being created in non-chrome compartment.
* defineOnGlobal controls whether properties should be defined on the given
* global for the interface object (if any) and named
* constructors (if any) for this interface. This can be
* false in situations where we want the properties to only
* appear on privileged Xrays but not on the unprivileged
* underlying global.
*
* At least one of protoClass, constructorClass or constructor should be
* non-null. If constructorClass or constructor are non-null, the resulting
@ -380,7 +386,7 @@ CreateInterfaceObjects(JSContext* cx, JS::Handle<JSObject*> global,
JS::Heap<JSObject*>* constructorCache, const DOMClass* domClass,
const NativeProperties* regularProperties,
const NativeProperties* chromeOnlyProperties,
const char* name);
const char* name, bool defineOnGlobal);
/*
* Define the unforgeable attributes on an object.

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

@ -1664,7 +1664,8 @@ class CGCreateInterfaceObjectsMethod(CGAbstractMethod):
def __init__(self, descriptor, properties):
args = [Argument('JSContext*', 'aCx'),
Argument('JS::Handle<JSObject*>', 'aGlobal'),
Argument('JS::Heap<JSObject*>*', 'protoAndIfaceArray')]
Argument('JS::Heap<JSObject*>*', 'aProtoAndIfaceArray'),
Argument('bool', 'aDefineOnGlobal')]
CGAbstractMethod.__init__(self, descriptor, 'CreateInterfaceObjects', 'void', args)
self.properties = properties
def definition_body(self):
@ -1791,13 +1792,13 @@ if (!unforgeableHolder) {
if needInterfacePrototypeObject:
protoClass = "&PrototypeClass.mBase"
protoCache = "&protoAndIfaceArray[prototypes::id::%s]" % self.descriptor.name
protoCache = "&aProtoAndIfaceArray[prototypes::id::%s]" % self.descriptor.name
else:
protoClass = "nullptr"
protoCache = "nullptr"
if needInterfaceObject:
interfaceClass = "&InterfaceObjectClass.mBase"
interfaceCache = "&protoAndIfaceArray[constructors::id::%s]" % self.descriptor.name
interfaceCache = "&aProtoAndIfaceArray[constructors::id::%s]" % self.descriptor.name
else:
# We don't have slots to store the named constructors.
assert len(self.descriptor.interface.namedConstructors) == 0
@ -1828,7 +1829,7 @@ if (!unforgeableHolder) {
" %s,\n"
" %s,\n"
" %s,\n"
" %s);" % (
" %s, aDefineOnGlobal);" % (
protoClass, protoCache,
interfaceClass, constructHookHolder, constructArgs,
namedConstructors,
@ -1840,7 +1841,7 @@ if (!unforgeableHolder) {
if UseHolderForUnforgeable(self.descriptor):
assert needInterfacePrototypeObject
setUnforgeableHolder = CGGeneric(
"JSObject* proto = protoAndIfaceArray[prototypes::id::%s];\n"
"JSObject* proto = aProtoAndIfaceArray[prototypes::id::%s];\n"
"if (proto) {\n"
" js::SetReservedSlot(proto, DOM_INTERFACE_PROTO_SLOTS_BASE,\n"
" JS::ObjectValue(*unforgeableHolder));\n"
@ -1858,9 +1859,9 @@ class CGGetPerInterfaceObject(CGAbstractMethod):
A method for getting a per-interface object (a prototype object or interface
constructor object).
"""
def __init__(self, descriptor, name, idPrefix=""):
def __init__(self, descriptor, name, idPrefix="", extraArgs=[]):
args = [Argument('JSContext*', 'aCx'),
Argument('JS::Handle<JSObject*>', 'aGlobal')]
Argument('JS::Handle<JSObject*>', 'aGlobal')] + extraArgs
CGAbstractMethod.__init__(self, descriptor, name,
'JS::Handle<JSObject*>', args, inline=True)
self.id = idPrefix + "id::" + self.descriptor.name
@ -1874,7 +1875,7 @@ class CGGetPerInterfaceObject(CGAbstractMethod):
/* Check to see whether the interface objects are already installed */
JS::Heap<JSObject*>* protoAndIfaceArray = GetProtoAndIfaceArray(aGlobal);
if (!protoAndIfaceArray[%s]) {
CreateInterfaceObjects(aCx, aGlobal, protoAndIfaceArray);
CreateInterfaceObjects(aCx, aGlobal, protoAndIfaceArray, aDefineOnGlobal);
}
/*
@ -1897,15 +1898,18 @@ class CGGetProtoObjectMethod(CGGetPerInterfaceObject):
def definition_body(self):
return """
/* Get the interface prototype object for this class. This will create the
object as needed. */""" + CGGetPerInterfaceObject.definition_body(self)
object as needed. */
bool aDefineOnGlobal = true;""" + CGGetPerInterfaceObject.definition_body(self)
class CGGetConstructorObjectMethod(CGGetPerInterfaceObject):
"""
A method for getting the interface constructor object.
"""
def __init__(self, descriptor):
CGGetPerInterfaceObject.__init__(self, descriptor, "GetConstructorObject",
"constructors::")
CGGetPerInterfaceObject.__init__(
self, descriptor, "GetConstructorObject",
"constructors::",
extraArgs=[Argument("bool", "aDefineOnGlobal", "true")])
def definition_body(self):
return """
/* Get the interface object for this class. This will create the object as
@ -1920,7 +1924,7 @@ class CGDefineDOMInterfaceMethod(CGAbstractMethod):
args = [Argument('JSContext*', 'aCx'),
Argument('JS::Handle<JSObject*>', 'aGlobal'),
Argument('JS::Handle<jsid>', 'id'),
Argument('bool*', 'aEnabled')]
Argument('bool', 'aDefineOnGlobal')]
CGAbstractMethod.__init__(self, descriptor, 'DefineDOMInterface', 'JSObject*', args)
def declare(self):
@ -1935,7 +1939,7 @@ class CGDefineDOMInterfaceMethod(CGAbstractMethod):
def definition_body(self):
if len(self.descriptor.interface.namedConstructors) > 0:
getConstructor = """ JSObject* interfaceObject = GetConstructorObject(aCx, aGlobal);
getConstructor = """ JSObject* interfaceObject = GetConstructorObject(aCx, aGlobal, aDefineOnGlobal);
if (!interfaceObject) {
return nullptr;
}
@ -1947,10 +1951,8 @@ class CGDefineDOMInterfaceMethod(CGAbstractMethod):
}
return interfaceObject;"""
else:
getConstructor = " return GetConstructorObject(aCx, aGlobal);"
return (""" *aEnabled = true;
""" + getConstructor)
getConstructor = " return GetConstructorObject(aCx, aGlobal, aDefineOnGlobal);"
return getConstructor
class CGConstructorEnabledViaPrefEnabled(CGAbstractMethod):
"""

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

@ -457,7 +457,7 @@ inline bool IsDOMProxy(JSObject *obj)
typedef JSObject*
(*DefineInterface)(JSContext *cx, JS::Handle<JSObject*> global,
JS::Handle<jsid> id, bool *enabled);
JS::Handle<jsid> id, bool defineOnGlobal);
typedef JSObject*
(*ConstructNavigatorProperty)(JSContext *cx, JS::Handle<JSObject*> naviObj);