Bug 965898 - Switch policies for get{,Own}PropertyDescriptor. r=gabor

This commit is contained in:
Bobby Holley 2014-07-30 12:23:03 -07:00
parent a348ab6fd4
commit 99778c8324
7 changed files with 38 additions and 16 deletions

View File

@ -397,7 +397,7 @@ bool
DirectProxyHandler::getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
MutableHandle<PropertyDescriptor> desc) const
{
assertEnteredPolicy(cx, proxy, id, GET | SET);
assertEnteredPolicy(cx, proxy, id, GET | SET | GET_PROPERTY_DESCRIPTOR);
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, desc);
@ -407,7 +407,7 @@ bool
DirectProxyHandler::getOwnPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
MutableHandle<PropertyDescriptor> desc) const
{
assertEnteredPolicy(cx, proxy, id, GET | SET);
assertEnteredPolicy(cx, proxy, id, GET | SET | GET_PROPERTY_DESCRIPTOR);
RootedObject target(cx, proxy->as<ProxyObject>().target());
return js::GetOwnPropertyDescriptor(cx, target, id, desc);
}
@ -2195,7 +2195,7 @@ Proxy::getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
JS_CHECK_RECURSION(cx, return false);
const BaseProxyHandler *handler = proxy->as<ProxyObject>().handler();
desc.object().set(nullptr); // default result if we refuse to perform this action
AutoEnterPolicy policy(cx, handler, proxy, id, BaseProxyHandler::GET, true);
AutoEnterPolicy policy(cx, handler, proxy, id, BaseProxyHandler::GET_PROPERTY_DESCRIPTOR, true);
if (!policy.allowed())
return policy.returnValue();
if (!handler->hasPrototype())
@ -2226,7 +2226,7 @@ Proxy::getOwnPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
const BaseProxyHandler *handler = proxy->as<ProxyObject>().handler();
desc.object().set(nullptr); // default result if we refuse to perform this action
AutoEnterPolicy policy(cx, handler, proxy, id, BaseProxyHandler::GET, true);
AutoEnterPolicy policy(cx, handler, proxy, id, BaseProxyHandler::GET_PROPERTY_DESCRIPTOR, true);
if (!policy.allowed())
return policy.returnValue();
return handler->getOwnPropertyDescriptor(cx, proxy, id, desc);

View File

@ -155,9 +155,9 @@ class JS_FRIEND_API(BaseProxyHandler)
* 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.
* For example, get{,Own}PropertyDescriptor is invoked by calls to ::get()
* ::set(), in addition to being invoked on its own, so there are several
* valid Actions that could have been entered.
*/
typedef uint32_t Action;
enum {
@ -165,7 +165,8 @@ class JS_FRIEND_API(BaseProxyHandler)
GET = 0x01,
SET = 0x02,
CALL = 0x04,
ENUMERATE = 0x08
ENUMERATE = 0x08,
GET_PROPERTY_DESCRIPTOR = 0x10
};
virtual bool enter(JSContext *cx, HandleObject wrapper, HandleId id, Action act,

View File

@ -157,6 +157,13 @@ AccessCheck::isCrossOriginAccessPermitted(JSContext *cx, JSObject *wrapperArg, j
if (act == Wrapper::ENUMERATE)
return true;
// For the case of getting a property descriptor, we allow if either GET or SET
// is allowed, and rely on FilteringWrapper to filter out any disallowed accessors.
if (act == Wrapper::GET_PROPERTY_DESCRIPTOR) {
return isCrossOriginAccessPermitted(cx, wrapperArg, idArg, Wrapper::GET) ||
isCrossOriginAccessPermitted(cx, wrapperArg, idArg, Wrapper::SET);
}
RootedId id(cx, idArg);
RootedObject wrapper(cx, wrapperArg);
RootedObject obj(cx, Wrapper::wrappedObject(wrapper));
@ -212,6 +219,14 @@ ExposedPropertiesOnly::check(JSContext *cx, JSObject *wrapperArg, jsid idArg, Wr
if (act == Wrapper::CALL)
return true;
// For the case of getting a property descriptor, we allow if either GET or SET
// is allowed, and rely on FilteringWrapper to filter out any disallowed accessors.
if (act == Wrapper::GET_PROPERTY_DESCRIPTOR) {
return check(cx, wrapperArg, idArg, Wrapper::GET) ||
check(cx, wrapperArg, idArg, Wrapper::SET);
}
RootedId exposedPropsId(cx, GetRTIdByIndex(cx, XPCJSRuntime::IDX_EXPOSEDPROPS));
// We need to enter the wrappee's compartment to look at __exposedProps__,

View File

@ -79,8 +79,9 @@ 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 and ENUMERATEs.
return act == js::Wrapper::GET || act == js::Wrapper::ENUMERATE;
// Fail silently for GET ENUMERATE, and GET_PROPERTY_DESCRIPTOR.
return act == js::Wrapper::GET || act == js::Wrapper::ENUMERATE ||
act == js::Wrapper::GET_PROPERTY_DESCRIPTOR;
}
static bool allowNativeCall(JSContext *cx, JS::IsAcceptableThis test, JS::NativeImpl impl) {
return false;

View File

@ -77,7 +77,7 @@ ChromeObjectWrapper::getPropertyDescriptor(JSContext *cx,
HandleId id,
JS::MutableHandle<JSPropertyDescriptor> desc) const
{
assertEnteredPolicy(cx, wrapper, id, GET | SET);
assertEnteredPolicy(cx, wrapper, id, GET | SET | GET_PROPERTY_DESCRIPTOR);
// First, try a lookup on the base wrapper if permitted.
desc.object().set(nullptr);
if (AllowedByBase(cx, wrapper, id, Wrapper::GET) &&
@ -274,7 +274,8 @@ 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 || act == Wrapper::ENUMERATE;
*bp = act == Wrapper::GET || act == Wrapper::ENUMERATE ||
act == Wrapper::GET_PROPERTY_DESCRIPTOR;
if (!*bp || id == JSID_VOID)
return false;

View File

@ -80,7 +80,8 @@ FilteringWrapper<Base, Policy>::getPropertyDescriptor(JSContext *cx, HandleObjec
HandleId id,
JS::MutableHandle<JSPropertyDescriptor> desc) const
{
assertEnteredPolicy(cx, wrapper, id, BaseProxyHandler::GET | BaseProxyHandler::SET);
assertEnteredPolicy(cx, wrapper, id, BaseProxyHandler::GET | BaseProxyHandler::SET |
BaseProxyHandler::GET_PROPERTY_DESCRIPTOR);
if (!Base::getPropertyDescriptor(cx, wrapper, id, desc))
return false;
return FilterPropertyDescriptor<Policy>(cx, wrapper, id, desc);
@ -92,7 +93,8 @@ FilteringWrapper<Base, Policy>::getOwnPropertyDescriptor(JSContext *cx, HandleOb
HandleId id,
JS::MutableHandle<JSPropertyDescriptor> desc) const
{
assertEnteredPolicy(cx, wrapper, id, BaseProxyHandler::GET | BaseProxyHandler::SET);
assertEnteredPolicy(cx, wrapper, id, BaseProxyHandler::GET | BaseProxyHandler::SET |
BaseProxyHandler::GET_PROPERTY_DESCRIPTOR);
if (!Base::getOwnPropertyDescriptor(cx, wrapper, id, desc))
return false;
return FilterPropertyDescriptor<Policy>(cx, wrapper, id, desc);

View File

@ -2364,7 +2364,8 @@ XrayWrapper<Base, Traits>::getPropertyDescriptor(JSContext *cx, HandleObject wra
JS::MutableHandle<JSPropertyDescriptor> desc)
const
{
assertEnteredPolicy(cx, wrapper, id, BaseProxyHandler::GET | BaseProxyHandler::SET);
assertEnteredPolicy(cx, wrapper, id, BaseProxyHandler::GET | BaseProxyHandler::SET |
BaseProxyHandler::GET_PROPERTY_DESCRIPTOR);
RootedObject holder(cx, Traits::singleton.ensureHolder(cx, wrapper));
if (Traits::isResolving(cx, holder, id)) {
desc.object().set(nullptr);
@ -2496,7 +2497,8 @@ XrayWrapper<Base, Traits>::getOwnPropertyDescriptor(JSContext *cx, HandleObject
JS::MutableHandle<JSPropertyDescriptor> desc)
const
{
assertEnteredPolicy(cx, wrapper, id, BaseProxyHandler::GET | BaseProxyHandler::SET);
assertEnteredPolicy(cx, wrapper, id, BaseProxyHandler::GET | BaseProxyHandler::SET |
BaseProxyHandler::GET_PROPERTY_DESCRIPTOR);
RootedObject holder(cx, Traits::singleton.ensureHolder(cx, wrapper));
if (Traits::isResolving(cx, holder, id)) {
desc.object().set(nullptr);