Bug 965901 - Track and assert the policy action in AutoEnterPolicy/assertEnteredPolicy. r=gabor sr=mrbkap

This commit is contained in:
Bobby Holley 2014-02-13 10:54:07 -08:00
parent 9ab1f93eca
commit 66cc972e63
6 changed files with 92 additions and 68 deletions

View File

@ -1991,13 +1991,6 @@ class JS_FRIEND_API(AutoCTypesActivityCallback) {
}
};
#ifdef JS_DEBUG
extern JS_FRIEND_API(void)
assertEnteredPolicy(JSContext *cx, JSObject *obj, jsid id);
#else
inline void assertEnteredPolicy(JSContext *cx, JSObject *obj, jsid id) {};
#endif
typedef bool
(* ObjectMetadataCallback)(JSContext *cx, JSObject **pmetadata);

View File

@ -46,12 +46,13 @@ js::AutoEnterPolicy::reportErrorIfExceptionIsNotPending(JSContext *cx, jsid id)
#ifdef DEBUG
void
js::AutoEnterPolicy::recordEnter(JSContext *cx, HandleObject proxy, HandleId id)
js::AutoEnterPolicy::recordEnter(JSContext *cx, HandleObject proxy, HandleId id, Action act)
{
if (allowed()) {
context = cx;
enteredProxy.construct(proxy);
enteredId.construct(id);
enteredAction = act;
prev = cx->runtime()->enteredPolicy;
cx->runtime()->enteredPolicy = this;
}
@ -67,12 +68,14 @@ js::AutoEnterPolicy::recordLeave()
}
JS_FRIEND_API(void)
js::assertEnteredPolicy(JSContext *cx, JSObject *proxy, jsid id)
js::assertEnteredPolicy(JSContext *cx, JSObject *proxy, jsid id,
BaseProxyHandler::Action act)
{
MOZ_ASSERT(proxy->is<ProxyObject>());
MOZ_ASSERT(cx->runtime()->enteredPolicy);
MOZ_ASSERT(cx->runtime()->enteredPolicy->enteredProxy.ref().get() == proxy);
MOZ_ASSERT(cx->runtime()->enteredPolicy->enteredId.ref().get() == id);
MOZ_ASSERT(cx->runtime()->enteredPolicy->enteredAction & act);
}
#endif
@ -98,7 +101,7 @@ BaseProxyHandler::enter(JSContext *cx, HandleObject wrapper, HandleId id, Action
bool
BaseProxyHandler::has(JSContext *cx, HandleObject proxy, HandleId id, bool *bp)
{
assertEnteredPolicy(cx, proxy, id);
assertEnteredPolicy(cx, proxy, id, GET);
Rooted<PropertyDescriptor> desc(cx);
if (!getPropertyDescriptor(cx, proxy, id, &desc, 0))
return false;
@ -109,7 +112,9 @@ BaseProxyHandler::has(JSContext *cx, HandleObject proxy, HandleId id, bool *bp)
bool
BaseProxyHandler::hasOwn(JSContext *cx, HandleObject proxy, HandleId id, bool *bp)
{
assertEnteredPolicy(cx, proxy, id);
// Note: Proxy::set needs to invoke hasOwn to determine where the setter
// lives, so we allow SET operations to invoke us.
assertEnteredPolicy(cx, proxy, id, GET | SET);
Rooted<PropertyDescriptor> desc(cx);
if (!getOwnPropertyDescriptor(cx, proxy, id, &desc, 0))
return false;
@ -121,7 +126,7 @@ bool
BaseProxyHandler::get(JSContext *cx, HandleObject proxy, HandleObject receiver,
HandleId id, MutableHandleValue vp)
{
assertEnteredPolicy(cx, proxy, id);
assertEnteredPolicy(cx, proxy, id, GET);
Rooted<PropertyDescriptor> desc(cx);
if (!getPropertyDescriptor(cx, proxy, id, &desc, 0))
@ -155,7 +160,7 @@ bool
BaseProxyHandler::set(JSContext *cx, HandleObject proxy, HandleObject receiver,
HandleId id, bool strict, MutableHandleValue vp)
{
assertEnteredPolicy(cx, proxy, id);
assertEnteredPolicy(cx, proxy, id, SET);
Rooted<PropertyDescriptor> desc(cx);
if (!getOwnPropertyDescriptor(cx, proxy, id, &desc, JSRESOLVE_ASSIGNING))
@ -226,7 +231,7 @@ BaseProxyHandler::set(JSContext *cx, HandleObject proxy, HandleObject receiver,
bool
BaseProxyHandler::keys(JSContext *cx, HandleObject proxy, AutoIdVector &props)
{
assertEnteredPolicy(cx, proxy, JSID_VOID);
assertEnteredPolicy(cx, proxy, JSID_VOID, GET);
JS_ASSERT(props.length() == 0);
if (!getOwnPropertyNames(cx, proxy, props))
@ -239,7 +244,7 @@ BaseProxyHandler::keys(JSContext *cx, HandleObject proxy, AutoIdVector &props)
for (size_t j = 0, len = props.length(); j < len; j++) {
JS_ASSERT(i <= j);
id = props[j];
AutoWaivePolicy policy(cx, proxy, id);
AutoWaivePolicy policy(cx, proxy, id, BaseProxyHandler::GET);
if (!getOwnPropertyDescriptor(cx, proxy, id, &desc, 0))
return false;
if (desc.object() && desc.isEnumerable())
@ -255,7 +260,7 @@ BaseProxyHandler::keys(JSContext *cx, HandleObject proxy, AutoIdVector &props)
bool
BaseProxyHandler::iterate(JSContext *cx, HandleObject proxy, unsigned flags, MutableHandleValue vp)
{
assertEnteredPolicy(cx, proxy, JSID_VOID);
assertEnteredPolicy(cx, proxy, JSID_VOID, GET);
AutoIdVector props(cx);
if ((flags & JSITER_OWNONLY)
@ -319,7 +324,7 @@ BaseProxyHandler::nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl im
bool
BaseProxyHandler::hasInstance(JSContext *cx, HandleObject proxy, MutableHandleValue v, bool *bp)
{
assertEnteredPolicy(cx, proxy, JSID_VOID);
assertEnteredPolicy(cx, proxy, JSID_VOID, GET);
RootedValue val(cx, ObjectValue(*proxy.get()));
js_ReportValueError(cx, JSMSG_BAD_INSTANCEOF_RHS,
JSDVG_SEARCH_STACK, val, NullPtr());
@ -378,7 +383,7 @@ bool
BaseProxyHandler::slice(JSContext *cx, HandleObject proxy, uint32_t begin, uint32_t end,
HandleObject result)
{
assertEnteredPolicy(cx, proxy, JSID_VOID);
assertEnteredPolicy(cx, proxy, JSID_VOID, GET);
return js::SliceSlowly(cx, proxy, proxy, begin, end, result);
}
@ -387,7 +392,7 @@ bool
DirectProxyHandler::getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
MutableHandle<PropertyDescriptor> desc, unsigned flags)
{
assertEnteredPolicy(cx, proxy, id);
assertEnteredPolicy(cx, proxy, id, GET | SET);
JS_ASSERT(!hasPrototype()); // Should never be called if there's a prototype.
RootedObject target(cx, proxy->as<ProxyObject>().target());
return JS_GetPropertyDescriptorById(cx, target, id, 0, desc);
@ -414,7 +419,7 @@ DirectProxyHandler::getOwnPropertyDescriptor(JSContext *cx, HandleObject proxy,
HandleId id, MutableHandle<PropertyDescriptor> desc,
unsigned flags)
{
assertEnteredPolicy(cx, proxy, id);
assertEnteredPolicy(cx, proxy, id, GET | SET);
RootedObject target(cx, proxy->as<ProxyObject>().target());
return GetOwnPropertyDescriptor(cx, target, id, 0, desc);
}
@ -423,7 +428,7 @@ bool
DirectProxyHandler::defineProperty(JSContext *cx, HandleObject proxy, HandleId id,
MutableHandle<PropertyDescriptor> desc)
{
assertEnteredPolicy(cx, proxy, id);
assertEnteredPolicy(cx, proxy, id, SET);
RootedObject target(cx, proxy->as<ProxyObject>().target());
RootedValue v(cx, desc.value());
return CheckDefineProperty(cx, target, id, v, desc.getter(), desc.setter(), desc.attributes()) &&
@ -434,7 +439,7 @@ bool
DirectProxyHandler::getOwnPropertyNames(JSContext *cx, HandleObject proxy,
AutoIdVector &props)
{
assertEnteredPolicy(cx, proxy, JSID_VOID);
assertEnteredPolicy(cx, proxy, JSID_VOID, GET);
RootedObject target(cx, proxy->as<ProxyObject>().target());
return GetPropertyNames(cx, target, JSITER_OWNONLY | JSITER_HIDDEN, &props);
}
@ -442,7 +447,7 @@ DirectProxyHandler::getOwnPropertyNames(JSContext *cx, HandleObject proxy,
bool
DirectProxyHandler::delete_(JSContext *cx, HandleObject proxy, HandleId id, bool *bp)
{
assertEnteredPolicy(cx, proxy, id);
assertEnteredPolicy(cx, proxy, id, SET);
RootedObject target(cx, proxy->as<ProxyObject>().target());
return JS_DeletePropertyById2(cx, target, id, bp);
}
@ -451,7 +456,7 @@ bool
DirectProxyHandler::enumerate(JSContext *cx, HandleObject proxy,
AutoIdVector &props)
{
assertEnteredPolicy(cx, proxy, JSID_VOID);
assertEnteredPolicy(cx, proxy, JSID_VOID, GET);
JS_ASSERT(!hasPrototype()); // Should never be called if there's a prototype.
RootedObject target(cx, proxy->as<ProxyObject>().target());
return GetPropertyNames(cx, target, 0, &props);
@ -460,7 +465,7 @@ DirectProxyHandler::enumerate(JSContext *cx, HandleObject proxy,
bool
DirectProxyHandler::call(JSContext *cx, HandleObject proxy, const CallArgs &args)
{
assertEnteredPolicy(cx, proxy, JSID_VOID);
assertEnteredPolicy(cx, proxy, JSID_VOID, CALL);
RootedValue target(cx, proxy->as<ProxyObject>().private_());
return Invoke(cx, args.thisv(), target, args.length(), args.array(), args.rval());
}
@ -468,7 +473,7 @@ DirectProxyHandler::call(JSContext *cx, HandleObject proxy, const CallArgs &args
bool
DirectProxyHandler::construct(JSContext *cx, HandleObject proxy, const CallArgs &args)
{
assertEnteredPolicy(cx, proxy, JSID_VOID);
assertEnteredPolicy(cx, proxy, JSID_VOID, CALL);
RootedValue target(cx, proxy->as<ProxyObject>().private_());
return InvokeConstructor(cx, target, args.length(), args.array(), args.rval().address());
}
@ -490,7 +495,7 @@ bool
DirectProxyHandler::hasInstance(JSContext *cx, HandleObject proxy, MutableHandleValue v,
bool *bp)
{
assertEnteredPolicy(cx, proxy, JSID_VOID);
assertEnteredPolicy(cx, proxy, JSID_VOID, GET);
bool b;
RootedObject target(cx, proxy->as<ProxyObject>().target());
if (!HasInstance(cx, target, v, &b))
@ -524,7 +529,7 @@ DirectProxyHandler::objectClassIs(HandleObject proxy, ESClassValue classValue,
const char *
DirectProxyHandler::className(JSContext *cx, HandleObject proxy)
{
assertEnteredPolicy(cx, proxy, JSID_VOID);
assertEnteredPolicy(cx, proxy, JSID_VOID, GET);
RootedObject target(cx, proxy->as<ProxyObject>().target());
return JSObject::className(cx, target);
}
@ -533,7 +538,7 @@ JSString *
DirectProxyHandler::fun_toString(JSContext *cx, HandleObject proxy,
unsigned indent)
{
assertEnteredPolicy(cx, proxy, JSID_VOID);
assertEnteredPolicy(cx, proxy, JSID_VOID, GET);
RootedObject target(cx, proxy->as<ProxyObject>().target());
return fun_toStringHelper(cx, target, indent);
}
@ -560,7 +565,7 @@ DirectProxyHandler::DirectProxyHandler(const void *family)
bool
DirectProxyHandler::has(JSContext *cx, HandleObject proxy, HandleId id, bool *bp)
{
assertEnteredPolicy(cx, proxy, id);
assertEnteredPolicy(cx, proxy, id, GET);
JS_ASSERT(!hasPrototype()); // Should never be called if there's a prototype.
bool found;
RootedObject target(cx, proxy->as<ProxyObject>().target());
@ -573,7 +578,9 @@ DirectProxyHandler::has(JSContext *cx, HandleObject proxy, HandleId id, bool *bp
bool
DirectProxyHandler::hasOwn(JSContext *cx, HandleObject proxy, HandleId id, bool *bp)
{
assertEnteredPolicy(cx, proxy, id);
// Note: Proxy::set needs to invoke hasOwn to determine where the setter
// lives, so we allow SET operations to invoke us.
assertEnteredPolicy(cx, proxy, id, GET | SET);
RootedObject target(cx, proxy->as<ProxyObject>().target());
Rooted<PropertyDescriptor> desc(cx);
if (!JS_GetPropertyDescriptorById(cx, target, id, 0, &desc))
@ -586,7 +593,7 @@ bool
DirectProxyHandler::get(JSContext *cx, HandleObject proxy, HandleObject receiver,
HandleId id, MutableHandleValue vp)
{
assertEnteredPolicy(cx, proxy, id);
assertEnteredPolicy(cx, proxy, id, GET);
RootedObject target(cx, proxy->as<ProxyObject>().target());
return JSObject::getGeneric(cx, target, receiver, id, vp);
}
@ -595,7 +602,7 @@ bool
DirectProxyHandler::set(JSContext *cx, HandleObject proxy, HandleObject receiver,
HandleId id, bool strict, MutableHandleValue vp)
{
assertEnteredPolicy(cx, proxy, id);
assertEnteredPolicy(cx, proxy, id, SET);
RootedObject target(cx, proxy->as<ProxyObject>().target());
return JSObject::setGeneric(cx, target, receiver, id, vp, strict);
}
@ -603,7 +610,7 @@ DirectProxyHandler::set(JSContext *cx, HandleObject proxy, HandleObject receiver
bool
DirectProxyHandler::keys(JSContext *cx, HandleObject proxy, AutoIdVector &props)
{
assertEnteredPolicy(cx, proxy, JSID_VOID);
assertEnteredPolicy(cx, proxy, JSID_VOID, GET);
RootedObject target(cx, proxy->as<ProxyObject>().target());
return GetPropertyNames(cx, target, JSITER_OWNONLY, &props);
}
@ -612,7 +619,7 @@ bool
DirectProxyHandler::iterate(JSContext *cx, HandleObject proxy, unsigned flags,
MutableHandleValue vp)
{
assertEnteredPolicy(cx, proxy, JSID_VOID);
assertEnteredPolicy(cx, proxy, JSID_VOID, GET);
JS_ASSERT(!hasPrototype()); // Should never be called if there's a prototype.
RootedObject target(cx, proxy->as<ProxyObject>().target());
return GetIterator(cx, target, flags, vp);
@ -1033,7 +1040,7 @@ ScriptedIndirectProxyHandler::iterate(JSContext *cx, HandleObject proxy, unsigne
bool
ScriptedIndirectProxyHandler::call(JSContext *cx, HandleObject proxy, const CallArgs &args)
{
assertEnteredPolicy(cx, proxy, JSID_VOID);
assertEnteredPolicy(cx, proxy, JSID_VOID, CALL);
RootedObject ccHolder(cx, &proxy->as<ProxyObject>().extra(0).toObject());
JS_ASSERT(ccHolder->getClass() == &CallConstructHolder);
RootedValue call(cx, ccHolder->getReservedSlot(0));
@ -1044,7 +1051,7 @@ ScriptedIndirectProxyHandler::call(JSContext *cx, HandleObject proxy, const Call
bool
ScriptedIndirectProxyHandler::construct(JSContext *cx, HandleObject proxy, const CallArgs &args)
{
assertEnteredPolicy(cx, proxy, JSID_VOID);
assertEnteredPolicy(cx, proxy, JSID_VOID, CALL);
RootedObject ccHolder(cx, &proxy->as<ProxyObject>().extra(0).toObject());
JS_ASSERT(ccHolder->getClass() == &CallConstructHolder);
RootedValue construct(cx, ccHolder->getReservedSlot(1));
@ -1063,7 +1070,7 @@ ScriptedIndirectProxyHandler::nativeCall(JSContext *cx, IsAcceptableThis test, N
JSString *
ScriptedIndirectProxyHandler::fun_toString(JSContext *cx, HandleObject proxy, unsigned indent)
{
assertEnteredPolicy(cx, proxy, JSID_VOID);
assertEnteredPolicy(cx, proxy, JSID_VOID, GET);
if (!proxy->isCallable()) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr,
JSMSG_INCOMPATIBLE_PROTO,

View File

@ -139,12 +139,18 @@ class JS_FRIEND_API(BaseProxyHandler)
* The |act| parameter to enter() specifies the action being performed.
* If |bp| is false, the trap suggests that the caller throw (though it
* may still decide to squelch the error).
*
* We make these OR-able so that assertEnteredPolicy can pass a union of them.
* For example, get{,Own}PropertyDescriptor is invoked by both calls to ::get()
* and ::set() (since we need to look up the accessor), so its
* assertEnteredPolicy would pass GET | SET.
*/
enum Action {
GET,
SET,
CALL
};
typedef uint32_t Action;
static const Action VOID = 0x00;
static const Action GET = 0x01;
static const Action SET = 0x02;
static const Action CALL = 0x04;
virtual bool enter(JSContext *cx, HandleObject wrapper, HandleId id, Action act,
bool *bp);
@ -462,7 +468,7 @@ class JS_FRIEND_API(AutoEnterPolicy)
{
allow = handler->hasSecurityPolicy() ? handler->enter(cx, wrapper, id, act, &rv)
: true;
recordEnter(cx, wrapper, id);
recordEnter(cx, wrapper, id, act);
// We want to throw an exception if all of the following are true:
// * The policy disallowed access.
// * The policy set rv to false, indicating that we should throw.
@ -481,6 +487,7 @@ class JS_FRIEND_API(AutoEnterPolicy)
AutoEnterPolicy()
#ifdef JS_DEBUG
: context(nullptr)
, enteredAction(BaseProxyHandler::VOID)
#endif
{};
void reportErrorIfExceptionIsNotPending(JSContext *cx, jsid id);
@ -491,16 +498,18 @@ class JS_FRIEND_API(AutoEnterPolicy)
JSContext *context;
mozilla::Maybe<HandleObject> enteredProxy;
mozilla::Maybe<HandleId> enteredId;
Action enteredAction;
// NB: We explicitly don't track the entered action here, because sometimes
// SET traps do an implicit GET during their implementation, leading to
// spurious assertions.
AutoEnterPolicy *prev;
void recordEnter(JSContext *cx, HandleObject proxy, HandleId id);
void recordEnter(JSContext *cx, HandleObject proxy, HandleId id, Action act);
void recordLeave();
friend JS_FRIEND_API(void) assertEnteredPolicy(JSContext *cx, JSObject *proxy, jsid id);
friend JS_FRIEND_API(void) assertEnteredPolicy(JSContext *cx, JSObject *proxy, jsid id, Action act);
#else
inline void recordEnter(JSContext *cx, JSObject *proxy, jsid id) {}
inline void recordEnter(JSContext *cx, JSObject *proxy, jsid id, Action act) {}
inline void recordLeave() {}
#endif
@ -509,18 +518,32 @@ class JS_FRIEND_API(AutoEnterPolicy)
#ifdef JS_DEBUG
class JS_FRIEND_API(AutoWaivePolicy) : public AutoEnterPolicy {
public:
AutoWaivePolicy(JSContext *cx, HandleObject proxy, HandleId id)
AutoWaivePolicy(JSContext *cx, HandleObject proxy, HandleId id,
BaseProxyHandler::Action act)
{
allow = true;
recordEnter(cx, proxy, id);
recordEnter(cx, proxy, id, act);
}
};
#else
class JS_FRIEND_API(AutoWaivePolicy) {
public: AutoWaivePolicy(JSContext *cx, HandleObject proxy, HandleId id) {};
public:
AutoWaivePolicy(JSContext *cx, HandleObject proxy, HandleId id,
BaseProxyHandler::Action act)
{}
};
#endif
#ifdef JS_DEBUG
extern JS_FRIEND_API(void)
assertEnteredPolicy(JSContext *cx, JSObject *obj, jsid id,
BaseProxyHandler::Action act);
#else
inline void assertEnteredPolicy(JSContext *cx, JSObject *obj, jsid id,
BaseProxyHandler::Action act)
{};
#endif
} /* namespace js */
extern JS_FRIEND_API(JSObject *)

View File

@ -67,7 +67,7 @@ ChromeObjectWrapper::getPropertyDescriptor(JSContext *cx,
JS::MutableHandle<JSPropertyDescriptor> desc,
unsigned flags)
{
assertEnteredPolicy(cx, wrapper, id);
assertEnteredPolicy(cx, wrapper, id, GET | SET);
// First, try a lookup on the base wrapper if permitted.
desc.object().set(nullptr);
if (AllowedByBase(cx, wrapper, id, Wrapper::GET) &&
@ -98,7 +98,7 @@ bool
ChromeObjectWrapper::has(JSContext *cx, HandleObject wrapper,
HandleId id, bool *bp)
{
assertEnteredPolicy(cx, wrapper, id);
assertEnteredPolicy(cx, wrapper, id, GET);
// Try the lookup on the base wrapper if permitted.
if (AllowedByBase(cx, wrapper, id, js::Wrapper::GET) &&
!ChromeObjectWrapperBase::has(cx, wrapper, id, bp))
@ -127,7 +127,7 @@ ChromeObjectWrapper::get(JSContext *cx, HandleObject wrapper,
HandleObject receiver, HandleId id,
MutableHandleValue vp)
{
assertEnteredPolicy(cx, wrapper, id);
assertEnteredPolicy(cx, wrapper, id, GET);
vp.setUndefined();
// Only call through to the get trap on the underlying object if we're
// allowed to see the property, and if what we'll find is not on a standard
@ -183,7 +183,7 @@ ChromeObjectWrapper::enter(JSContext *cx, HandleObject wrapper,
// Note that PropIsFromStandardPrototype needs to invoke getPropertyDescriptor
// before we've fully entered the policy. Waive our policy.
js::AutoWaivePolicy policy(cx, wrapper, id);
js::AutoWaivePolicy policy(cx, wrapper, id, act);
return PropIsFromStandardPrototype(cx, wrapper, id);
}

View File

@ -63,7 +63,7 @@ FilteringWrapper<Base, Policy>::getPropertyDescriptor(JSContext *cx, HandleObjec
JS::MutableHandle<JSPropertyDescriptor> desc,
unsigned flags)
{
assertEnteredPolicy(cx, wrapper, id);
assertEnteredPolicy(cx, wrapper, id, BaseProxyHandler::GET | BaseProxyHandler::SET);
if (!Base::getPropertyDescriptor(cx, wrapper, id, desc, flags))
return false;
return FilterSetter<Policy>(cx, wrapper, id, desc);
@ -76,7 +76,7 @@ FilteringWrapper<Base, Policy>::getOwnPropertyDescriptor(JSContext *cx, HandleOb
JS::MutableHandle<JSPropertyDescriptor> desc,
unsigned flags)
{
assertEnteredPolicy(cx, wrapper, id);
assertEnteredPolicy(cx, wrapper, id, BaseProxyHandler::GET | BaseProxyHandler::SET);
if (!Base::getOwnPropertyDescriptor(cx, wrapper, id, desc, flags))
return false;
return FilterSetter<Policy>(cx, wrapper, id, desc);
@ -87,7 +87,7 @@ bool
FilteringWrapper<Base, Policy>::getOwnPropertyNames(JSContext *cx, HandleObject wrapper,
AutoIdVector &props)
{
assertEnteredPolicy(cx, wrapper, JSID_VOID);
assertEnteredPolicy(cx, wrapper, JSID_VOID, BaseProxyHandler::GET);
return Base::getOwnPropertyNames(cx, wrapper, props) &&
Filter<Policy>(cx, wrapper, props);
}
@ -97,7 +97,7 @@ bool
FilteringWrapper<Base, Policy>::enumerate(JSContext *cx, HandleObject wrapper,
AutoIdVector &props)
{
assertEnteredPolicy(cx, wrapper, JSID_VOID);
assertEnteredPolicy(cx, wrapper, JSID_VOID, BaseProxyHandler::GET);
return Base::enumerate(cx, wrapper, props) &&
Filter<Policy>(cx, wrapper, props);
}
@ -107,7 +107,7 @@ bool
FilteringWrapper<Base, Policy>::keys(JSContext *cx, HandleObject wrapper,
AutoIdVector &props)
{
assertEnteredPolicy(cx, wrapper, JSID_VOID);
assertEnteredPolicy(cx, wrapper, JSID_VOID, BaseProxyHandler::GET);
return Base::keys(cx, wrapper, props) &&
Filter<Policy>(cx, wrapper, props);
}
@ -117,7 +117,7 @@ bool
FilteringWrapper<Base, Policy>::iterate(JSContext *cx, HandleObject wrapper,
unsigned flags, MutableHandleValue vp)
{
assertEnteredPolicy(cx, wrapper, JSID_VOID);
assertEnteredPolicy(cx, wrapper, JSID_VOID, BaseProxyHandler::GET);
// We refuse to trigger the iterator hook across chrome wrappers because
// we don't know how to censor custom iterator objects. Instead we trigger
// the default proxy iterate trap, which will ask enumerate() for the list

View File

@ -30,6 +30,7 @@ using namespace JS;
using namespace mozilla;
using js::Wrapper;
using js::BaseProxyHandler;
using js::IsCrossCompartmentWrapper;
using js::UncheckedUnwrap;
using js::CheckedUnwrap;
@ -1438,7 +1439,7 @@ XrayWrapper<Base, Traits>::getPropertyDescriptor(JSContext *cx, HandleObject wra
JS::MutableHandle<JSPropertyDescriptor> desc,
unsigned flags)
{
assertEnteredPolicy(cx, wrapper, id);
assertEnteredPolicy(cx, wrapper, id, BaseProxyHandler::GET | BaseProxyHandler::SET);
RootedObject holder(cx, Traits::singleton.ensureHolder(cx, wrapper));
if (Traits::isResolving(cx, holder, id)) {
desc.object().set(nullptr);
@ -1585,7 +1586,7 @@ XrayWrapper<Base, Traits>::getOwnPropertyDescriptor(JSContext *cx, HandleObject
JS::MutableHandle<JSPropertyDescriptor> desc,
unsigned flags)
{
assertEnteredPolicy(cx, wrapper, id);
assertEnteredPolicy(cx, wrapper, id, BaseProxyHandler::GET | BaseProxyHandler::SET);
RootedObject holder(cx, Traits::singleton.ensureHolder(cx, wrapper));
if (Traits::isResolving(cx, holder, id)) {
desc.object().set(nullptr);
@ -1666,7 +1667,7 @@ bool
XrayWrapper<Base, Traits>::defineProperty(JSContext *cx, HandleObject wrapper,
HandleId id, MutableHandle<JSPropertyDescriptor> desc)
{
assertEnteredPolicy(cx, wrapper, id);
assertEnteredPolicy(cx, wrapper, id, BaseProxyHandler::SET);
// NB: We still need JSRESOLVE_ASSIGNING here for the time being, because it
// tells things like nodelists whether they should create the property or not.
@ -1713,7 +1714,7 @@ bool
XrayWrapper<Base, Traits>::getOwnPropertyNames(JSContext *cx, HandleObject wrapper,
AutoIdVector &props)
{
assertEnteredPolicy(cx, wrapper, JSID_VOID);
assertEnteredPolicy(cx, wrapper, JSID_VOID, BaseProxyHandler::GET);
return enumerate(cx, wrapper, JSITER_OWNONLY | JSITER_HIDDEN, props);
}
@ -1722,7 +1723,7 @@ bool
XrayWrapper<Base, Traits>::delete_(JSContext *cx, HandleObject wrapper,
HandleId id, bool *bp)
{
assertEnteredPolicy(cx, wrapper, id);
assertEnteredPolicy(cx, wrapper, id, BaseProxyHandler::SET);
// Check the expando object.
RootedObject target(cx, Traits::getTargetObject(wrapper));
@ -1740,7 +1741,7 @@ bool
XrayWrapper<Base, Traits>::enumerate(JSContext *cx, HandleObject wrapper, unsigned flags,
AutoIdVector &props)
{
assertEnteredPolicy(cx, wrapper, JSID_VOID);
assertEnteredPolicy(cx, wrapper, JSID_VOID, BaseProxyHandler::GET);
if (!AccessCheck::wrapperSubsumes(wrapper)) {
JS_ReportError(cx, "Not allowed to enumerate cross origin objects");
return false;
@ -1833,7 +1834,7 @@ template <typename Base, typename Traits>
bool
XrayWrapper<Base, Traits>::call(JSContext *cx, HandleObject wrapper, const JS::CallArgs &args)
{
assertEnteredPolicy(cx, wrapper, JSID_VOID);
assertEnteredPolicy(cx, wrapper, JSID_VOID, BaseProxyHandler::CALL);
return Traits::call(cx, wrapper, args, Base::singleton);
}
@ -1841,7 +1842,7 @@ template <typename Base, typename Traits>
bool
XrayWrapper<Base, Traits>::construct(JSContext *cx, HandleObject wrapper, const JS::CallArgs &args)
{
assertEnteredPolicy(cx, wrapper, JSID_VOID);
assertEnteredPolicy(cx, wrapper, JSID_VOID, BaseProxyHandler::CALL);
return Traits::construct(cx, wrapper, args, Base::singleton);
}