diff --git a/js/xpconnect/wrappers/AccessCheck.h b/js/xpconnect/wrappers/AccessCheck.h
index 9afd8dbd78a1..84ee1177cad5 100644
--- a/js/xpconnect/wrappers/AccessCheck.h
+++ b/js/xpconnect/wrappers/AccessCheck.h
@@ -35,6 +35,7 @@ enum CrossOriginObjectType {
CrossOriginObjectType IdentifyCrossOriginObject(JSObject *obj);
struct Policy {
+ static const bool AllowGetPrototypeOf = false;
};
// This policy allows no interaction with the underlying callable. Everything throws.
@@ -83,6 +84,12 @@ struct CrossOriginAccessiblePropertiesOnly : public Policy {
// This policy only permits access to properties if they appear in the
// objects exposed properties list.
struct ExposedPropertiesOnly : public Policy {
+
+ // COWs are the only type of filtering wrapper that allow access to the
+ // prototype, because the standard prototypes are remapped into the
+ // wrapper's compartment.
+ static const bool AllowGetPrototypeOf = true;
+
static bool check(JSContext *cx, JS::HandleObject wrapper, JS::HandleId id, js::Wrapper::Action act);
static bool deny(js::Wrapper::Action act, JS::HandleId id);
diff --git a/js/xpconnect/wrappers/FilteringWrapper.cpp b/js/xpconnect/wrappers/FilteringWrapper.cpp
index a40572fb56f9..272e370b90f9 100644
--- a/js/xpconnect/wrappers/FilteringWrapper.cpp
+++ b/js/xpconnect/wrappers/FilteringWrapper.cpp
@@ -152,6 +152,20 @@ FilteringWrapper::defaultValue(JSContext *cx, HandleObject obj,
return Base::defaultValue(cx, obj, hint, vp);
}
+template
+bool
+FilteringWrapper::getPrototypeOf(JSContext *cx, JS::HandleObject wrapper,
+ JS::MutableHandleObject protop) const
+{
+ // If the policy explicitly allows access to the prototype, bounce to the base.
+ if (Policy::AllowGetPrototypeOf)
+ return Base::getPrototypeOf(cx, wrapper, protop);
+
+ // In general, filtering wrappers do not allow access to the prototype.
+ protop.set(nullptr);
+ return true;
+}
+
template
bool
FilteringWrapper::enter(JSContext *cx, HandleObject wrapper,
@@ -201,15 +215,6 @@ CrossOriginXrayWrapper::getOwnPropertyDescriptor(JSContext *cx,
return getPropertyDescriptor(cx, wrapper, id, desc);
}
-bool
-CrossOriginXrayWrapper::getPrototypeOf(JSContext *cx, JS::HandleObject wrapper,
- JS::MutableHandleObject protop) const
-{
- // Cross-origin objects have null prototypes.
- protop.set(nullptr);
- return true;
-}
-
bool
CrossOriginXrayWrapper::ownPropertyKeys(JSContext *cx, JS::Handle wrapper,
JS::AutoIdVector &props) const
diff --git a/js/xpconnect/wrappers/FilteringWrapper.h b/js/xpconnect/wrappers/FilteringWrapper.h
index c6910e3b8d59..021252f69499 100644
--- a/js/xpconnect/wrappers/FilteringWrapper.h
+++ b/js/xpconnect/wrappers/FilteringWrapper.h
@@ -49,6 +49,9 @@ class FilteringWrapper : public Base {
virtual bool defaultValue(JSContext *cx, JS::Handle obj, JSType hint,
JS::MutableHandleValue vp) const MOZ_OVERRIDE;
+ virtual bool getPrototypeOf(JSContext *cx, JS::HandleObject wrapper,
+ JS::MutableHandleObject protop) const MOZ_OVERRIDE;
+
static const FilteringWrapper singleton;
};
@@ -73,8 +76,6 @@ class CrossOriginXrayWrapper : public SecurityXrayDOM {
JS::Handle id, bool *bp) const MOZ_OVERRIDE;
virtual bool enumerate(JSContext *cx, JS::Handle wrapper,
JS::AutoIdVector &props) const MOZ_OVERRIDE;
- virtual bool getPrototypeOf(JSContext *cx, JS::HandleObject wrapper,
- JS::MutableHandleObject protop) const MOZ_OVERRIDE;
virtual bool getPropertyDescriptor(JSContext *cx, JS::Handle wrapper,
JS::Handle id,