Bug 965901 - Add an ENUMERATE policy action. r=gabor sr=mrbkap

This commit is contained in:
Bobby Holley 2014-02-13 10:54:08 -08:00
parent cab18b5855
commit 26295823eb
7 changed files with 24 additions and 26 deletions

View File

@ -231,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, GET);
assertEnteredPolicy(cx, proxy, JSID_VOID, ENUMERATE);
JS_ASSERT(props.length() == 0);
if (!getOwnPropertyNames(cx, proxy, props))
@ -260,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, GET);
assertEnteredPolicy(cx, proxy, JSID_VOID, ENUMERATE);
AutoIdVector props(cx);
if ((flags & JSITER_OWNONLY)
@ -439,7 +439,7 @@ bool
DirectProxyHandler::getOwnPropertyNames(JSContext *cx, HandleObject proxy,
AutoIdVector &props)
{
assertEnteredPolicy(cx, proxy, JSID_VOID, GET);
assertEnteredPolicy(cx, proxy, JSID_VOID, ENUMERATE);
RootedObject target(cx, proxy->as<ProxyObject>().target());
return GetPropertyNames(cx, target, JSITER_OWNONLY | JSITER_HIDDEN, &props);
}
@ -456,7 +456,7 @@ bool
DirectProxyHandler::enumerate(JSContext *cx, HandleObject proxy,
AutoIdVector &props)
{
assertEnteredPolicy(cx, proxy, JSID_VOID, GET);
assertEnteredPolicy(cx, proxy, JSID_VOID, ENUMERATE);
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);
@ -610,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, GET);
assertEnteredPolicy(cx, proxy, JSID_VOID, ENUMERATE);
RootedObject target(cx, proxy->as<ProxyObject>().target());
return GetPropertyNames(cx, target, JSITER_OWNONLY, &props);
}
@ -619,7 +619,7 @@ bool
DirectProxyHandler::iterate(JSContext *cx, HandleObject proxy, unsigned flags,
MutableHandleValue vp)
{
assertEnteredPolicy(cx, proxy, JSID_VOID, GET);
assertEnteredPolicy(cx, proxy, JSID_VOID, ENUMERATE);
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);
@ -2411,7 +2411,7 @@ Proxy::getOwnPropertyNames(JSContext *cx, HandleObject proxy, AutoIdVector &prop
{
JS_CHECK_RECURSION(cx, return false);
BaseProxyHandler *handler = proxy->as<ProxyObject>().handler();
AutoEnterPolicy policy(cx, handler, proxy, JSID_VOIDHANDLE, BaseProxyHandler::GET, true);
AutoEnterPolicy policy(cx, handler, proxy, JSID_VOIDHANDLE, BaseProxyHandler::ENUMERATE, true);
if (!policy.allowed())
return policy.returnValue();
return proxy->as<ProxyObject>().handler()->getOwnPropertyNames(cx, proxy, props);
@ -2454,7 +2454,7 @@ Proxy::enumerate(JSContext *cx, HandleObject proxy, AutoIdVector &props)
{
JS_CHECK_RECURSION(cx, return false);
BaseProxyHandler *handler = proxy->as<ProxyObject>().handler();
AutoEnterPolicy policy(cx, handler, proxy, JSID_VOIDHANDLE, BaseProxyHandler::GET, true);
AutoEnterPolicy policy(cx, handler, proxy, JSID_VOIDHANDLE, BaseProxyHandler::ENUMERATE, true);
if (!policy.allowed())
return policy.returnValue();
if (!handler->hasPrototype())
@ -2579,7 +2579,7 @@ Proxy::keys(JSContext *cx, HandleObject proxy, AutoIdVector &props)
{
JS_CHECK_RECURSION(cx, return false);
BaseProxyHandler *handler = proxy->as<ProxyObject>().handler();
AutoEnterPolicy policy(cx, handler, proxy, JSID_VOIDHANDLE, BaseProxyHandler::GET, true);
AutoEnterPolicy policy(cx, handler, proxy, JSID_VOIDHANDLE, BaseProxyHandler::ENUMERATE, true);
if (!policy.allowed())
return policy.returnValue();
return handler->keys(cx, proxy, props);
@ -2593,7 +2593,7 @@ Proxy::iterate(JSContext *cx, HandleObject proxy, unsigned flags, MutableHandleV
vp.setUndefined(); // default result if we refuse to perform this action
if (!handler->hasPrototype()) {
AutoEnterPolicy policy(cx, handler, proxy, JSID_VOIDHANDLE,
BaseProxyHandler::GET, true);
BaseProxyHandler::ENUMERATE, true);
// If the policy denies access but wants us to return true, we need
// to hand a valid (empty) iterator object to the caller.
if (!policy.allowed()) {

View File

@ -150,6 +150,7 @@ class JS_FRIEND_API(BaseProxyHandler)
static const Action GET = 0x01;
static const Action SET = 0x02;
static const Action CALL = 0x04;
static const Action ENUMERATE = 0x08;
virtual bool enter(JSContext *cx, HandleObject wrapper, HandleId id, Action act,
bool *bp);

View File

@ -217,12 +217,9 @@ AccessCheck::isCrossOriginAccessPermitted(JSContext *cx, JSObject *wrapperArg, j
RootedObject wrapper(cx, wrapperArg);
RootedObject obj(cx, Wrapper::wrappedObject(wrapper));
// Enumerate-like operations pass JSID_VOID to |enter|, since there isn't
// another sane value to pass. For XOWs, we generally want to deny such
// operations but fail silently (see CrossOriginAccessiblePropertiesOnly::
// deny). We could just fall through here and rely on the fact that none
// of the whitelisted properties below will match JSID_VOID, but EIBTI.
if (id == JSID_VOID)
// For XOWs, we generally want to deny enumerate-like operations, but fail
// silently (see CrossOriginAccessiblePropertiesOnly::deny).
if (act == Wrapper::ENUMERATE)
return false;
const char *name;

View File

@ -76,7 +76,7 @@ struct CrossOriginAccessiblePropertiesOnly : public Policy {
}
static bool deny(js::Wrapper::Action act, JS::HandleId id) {
// Silently fail for enumerate-like operations.
if (act == js::Wrapper::GET && id == JSID_VOIDHANDLE)
if (act == js::Wrapper::ENUMERATE)
return true;
return false;
}
@ -92,8 +92,8 @@ struct ExposedPropertiesOnly : public Policy {
static bool check(JSContext *cx, JSObject *wrapper, jsid id, js::Wrapper::Action act);
static bool deny(js::Wrapper::Action act, JS::HandleId id) {
// Fail silently for GETs.
return act == js::Wrapper::GET;
// Fail silently for GETs and ENUMERATEs.
return act == js::Wrapper::GET || act == js::Wrapper::ENUMERATE;
}
static bool allowNativeCall(JSContext *cx, JS::IsAcceptableThis test, JS::NativeImpl impl);
};

View File

@ -177,7 +177,7 @@ ChromeObjectWrapper::enter(JSContext *cx, HandleObject wrapper,
return true;
// COWs fail silently for GETs, and that also happens to be the only case
// where we might want to redirect the lookup to the home prototype chain.
*bp = (act == Wrapper::GET);
*bp = act == Wrapper::GET || act == Wrapper::ENUMERATE;
if (!*bp || id == JSID_VOID)
return false;

View File

@ -87,7 +87,7 @@ bool
FilteringWrapper<Base, Policy>::getOwnPropertyNames(JSContext *cx, HandleObject wrapper,
AutoIdVector &props)
{
assertEnteredPolicy(cx, wrapper, JSID_VOID, BaseProxyHandler::GET);
assertEnteredPolicy(cx, wrapper, JSID_VOID, BaseProxyHandler::ENUMERATE);
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, BaseProxyHandler::GET);
assertEnteredPolicy(cx, wrapper, JSID_VOID, BaseProxyHandler::ENUMERATE);
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, BaseProxyHandler::GET);
assertEnteredPolicy(cx, wrapper, JSID_VOID, BaseProxyHandler::ENUMERATE);
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, BaseProxyHandler::GET);
assertEnteredPolicy(cx, wrapper, JSID_VOID, BaseProxyHandler::ENUMERATE);
// 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

@ -1714,7 +1714,7 @@ bool
XrayWrapper<Base, Traits>::getOwnPropertyNames(JSContext *cx, HandleObject wrapper,
AutoIdVector &props)
{
assertEnteredPolicy(cx, wrapper, JSID_VOID, BaseProxyHandler::GET);
assertEnteredPolicy(cx, wrapper, JSID_VOID, BaseProxyHandler::ENUMERATE);
return enumerate(cx, wrapper, JSITER_OWNONLY | JSITER_HIDDEN, props);
}
@ -1741,7 +1741,7 @@ bool
XrayWrapper<Base, Traits>::enumerate(JSContext *cx, HandleObject wrapper, unsigned flags,
AutoIdVector &props)
{
assertEnteredPolicy(cx, wrapper, JSID_VOID, BaseProxyHandler::GET);
assertEnteredPolicy(cx, wrapper, JSID_VOID, BaseProxyHandler::ENUMERATE);
if (!AccessCheck::wrapperSubsumes(wrapper)) {
JS_ReportError(cx, "Not allowed to enumerate cross origin objects");
return false;