Bug 723111 - Add an option to js::UnwrapObject so that it doesn't stop at outer windows when unwrapping. This is useful for cases where we are trying to find the wrapped native for a security wrapper. r=bzbarsky

This commit is contained in:
Blake Kaplan 2012-01-26 14:55:27 +01:00
parent 3c8ca91d37
commit 2718588789
10 changed files with 29 additions and 12 deletions

View File

@ -216,7 +216,7 @@ JSCompartment::wrap(JSContext *cx, Value *vp)
/* Don't unwrap an outer window proxy. */
if (!obj->getClass()->ext.innerObject) {
obj = UnwrapObject(&vp->toObject(), &flags);
obj = UnwrapObject(&vp->toObject(), true, &flags);
vp->setObject(*obj);
if (obj->compartment() == this)
return true;

View File

@ -76,13 +76,13 @@ js::IsWrapper(const JSObject *wrapper)
}
JS_FRIEND_API(JSObject *)
js::UnwrapObject(JSObject *wrapped, uintN *flagsp)
js::UnwrapObject(JSObject *wrapped, bool stopAtOuter, uintN *flagsp)
{
uintN flags = 0;
while (wrapped->isWrapper()) {
flags |= static_cast<Wrapper *>(GetProxyHandler(wrapped))->flags();
wrapped = GetProxyPrivate(wrapped).toObjectOrNull();
if (wrapped->getClass()->ext.innerObject)
if (stopAtOuter && wrapped->getClass()->ext.innerObject)
break;
}
if (flagsp)

View File

@ -206,7 +206,14 @@ TransparentObjectWrapper(JSContext *cx, JSObject *obj, JSObject *wrappedProto, J
uintN flags);
JS_FRIEND_API(bool) IsWrapper(const JSObject *obj);
JS_FRIEND_API(JSObject *) UnwrapObject(JSObject *obj, uintN *flagsp = NULL);
// Given a JSObject, returns that object stripped of wrappers. If
// stopAtOuter is true, then this returns the outer window if it was
// previously wrapped. Otherwise, this returns the first object for
// which JSObject::isWrapper returns false.
JS_FRIEND_API(JSObject *) UnwrapObject(JSObject *obj, bool stopAtOuter = true,
uintN *flagsp = NULL);
bool IsCrossCompartmentWrapper(const JSObject *obj);
} /* namespace js */

View File

@ -3046,7 +3046,7 @@ EvalInContext(JSContext *cx, uintN argc, jsval *vp)
{
JSAutoEnterCompartment ac;
uintN flags;
JSObject *unwrapped = UnwrapObject(sobj, &flags);
JSObject *unwrapped = UnwrapObject(sobj, true, &flags);
if (flags & Wrapper::CROSS_COMPARTMENT) {
sobj = unwrapped;
if (!ac.enter(cx, sobj))

View File

@ -1220,7 +1220,7 @@ XPCConvert::JSObject2NativeInterface(XPCCallContext& ccx,
// we aren't, throw an exception eagerly.
JSObject* inner = nsnull;
if (XPCWrapper::IsSecurityWrapper(src)) {
inner = XPCWrapper::Unwrap(cx, src);
inner = XPCWrapper::Unwrap(cx, src, false);
if (!inner) {
if (pErr)
*pErr = NS_ERROR_XPC_SECURITY_MANAGER_VETO;

View File

@ -788,7 +788,7 @@ getWrapper(JSContext *cx,
XPCWrappedNativeTearOff **tearoff)
{
if (XPCWrapper::IsSecurityWrapper(obj) &&
!(obj = XPCWrapper::Unwrap(cx, obj))) {
!(obj = XPCWrapper::Unwrap(cx, obj, false))) {
return NS_ERROR_XPC_SECURITY_MANAGER_VETO;
}

View File

@ -123,12 +123,12 @@ AttachNewConstructorObject(XPCCallContext &ccx, JSObject *aGlobalObject)
namespace XPCWrapper {
JSObject *
Unwrap(JSContext *cx, JSObject *wrapper)
Unwrap(JSContext *cx, JSObject *wrapper, bool stopAtOuter)
{
if (js::IsWrapper(wrapper)) {
if (xpc::AccessCheck::isScriptAccessOnly(cx, wrapper))
return nsnull;
return js::UnwrapObject(wrapper);
return js::UnwrapObject(wrapper, stopAtOuter);
}
return nsnull;

View File

@ -93,7 +93,7 @@ IsSecurityWrapper(JSObject *wrapper)
* exception on |cx|.
*/
JSObject *
Unwrap(JSContext *cx, JSObject *wrapper);
Unwrap(JSContext *cx, JSObject *wrapper, bool stopAtOuter = true);
JSObject *
UnsafeUnwrapSecurityWrapper(JSObject *obj);

View File

@ -90,12 +90,22 @@ AccessCheck::isSameOrigin(JSCompartment *a, JSCompartment *b)
bool
AccessCheck::isLocationObjectSameOrigin(JSContext *cx, JSObject *wrapper)
{
// Location objects are parented to the outer window for which they
// were created. This gives us an easy way to determine whether our
// object is same origin with the current inner window:
// Grab the outer window...
JSObject *obj = js::GetObjectParent(js::UnwrapObject(wrapper));
if (!js::GetObjectClass(obj)->ext.innerObject) {
// ...which might be wrapped in a security wrapper.
obj = js::UnwrapObject(obj);
JS_ASSERT(js::GetObjectClass(obj)->ext.innerObject);
}
// Now innerize it to find the *current* inner window for our outer.
obj = JS_ObjectToInnerObject(cx, obj);
// Which lets us compare the current compartment against the old one.
return obj &&
(isSameOrigin(js::GetObjectCompartment(wrapper),
js::GetObjectCompartment(obj)) ||
@ -384,7 +394,7 @@ AccessCheck::isScriptAccessOnly(JSContext *cx, JSObject *wrapper)
JS_ASSERT(js::IsWrapper(wrapper));
uintN flags;
JSObject *obj = js::UnwrapObject(wrapper, &flags);
JSObject *obj = js::UnwrapObject(wrapper, true, &flags);
// If the wrapper indicates script-only access, we are done.
if (flags & WrapperFactory::SCRIPT_ACCESS_ONLY_FLAG) {

View File

@ -53,7 +53,7 @@ class WrapperFactory {
// Return true if any of any of the nested wrappers have the flag set.
static bool HasWrapperFlag(JSObject *wrapper, uintN flag) {
uintN flags = 0;
js::UnwrapObject(wrapper, &flags);
js::UnwrapObject(wrapper, true, &flags);
return !!(flags & flag);
}