Bug 788914 - Kill the XOW flag. r=mrbkap
authorBobby Holley <bobbyholley@gmail.com>
Tue, 11 Sep 2012 01:05:10 -0700
changeset 104781 4f5b4f0ecf01a4d9a1f5dcf114821acaec848c64
parent 104780 aa0fba2eb32753bd87acbc8f1170ea4906ed686a
child 104782 d042ad078f436e284610366dc39cebdcb6fa8658
push id14674
push userbobbyholley@gmail.com
push dateTue, 11 Sep 2012 08:05:26 +0000
treeherdermozilla-inbound@4f5b4f0ecf01 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmrbkap
bugs788914
milestone18.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 788914 - Kill the XOW flag. r=mrbkap There are really two questions to be asked: is the caller chrome, and does the caller subsume the callee. We have other, more precise ways of asking both of these questions.
dom/base/nsDOMClassInfo.cpp
js/xpconnect/src/XPCWrapper.cpp
js/xpconnect/wrappers/AccessCheck.cpp
js/xpconnect/wrappers/AccessCheck.h
js/xpconnect/wrappers/FilteringWrapper.cpp
js/xpconnect/wrappers/WrapperFactory.h
js/xpconnect/wrappers/XrayWrapper.cpp
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -2165,17 +2165,17 @@ nsDOMClassInfo::DefineStaticJSVals(JSCon
   return NS_OK;
 }
 
 // static
 bool
 nsDOMClassInfo::ObjectIsNativeWrapper(JSContext* cx, JSObject* obj)
 {
   return xpc::WrapperFactory::IsXrayWrapper(obj) &&
-         !xpc::WrapperFactory::IsXOW(obj);
+         xpc::AccessCheck::wrapperSubsumes(obj);
 }
 
 nsDOMClassInfo::nsDOMClassInfo(nsDOMClassInfoData* aData) : mData(aData)
 {
 }
 
 nsDOMClassInfo::~nsDOMClassInfo()
 {
--- a/js/xpconnect/src/XPCWrapper.cpp
+++ b/js/xpconnect/src/XPCWrapper.cpp
@@ -2,17 +2,19 @@
 /* vim: set ts=2 sw=2 et tw=78: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "XPCWrapper.h"
 #include "AccessCheck.h"
 #include "WrapperFactory.h"
+#include "AccessCheck.h"
 
+using namespace xpc;
 namespace XPCNativeWrapper {
 
 static inline
 JSBool
 ThrowException(nsresult ex, JSContext *cx)
 {
   XPCThrower::Throw(ex, cx);
 
@@ -32,18 +34,17 @@ UnwrapNW(JSContext *cx, unsigned argc, j
   }
 
   JSObject *obj = JSVAL_TO_OBJECT(v);
   if (!js::IsWrapper(obj)) {
     JS_SET_RVAL(cx, vp, v);
     return true;
   }
 
-  if (xpc::WrapperFactory::IsXrayWrapper(obj) &&
-      !xpc::WrapperFactory::IsXOW(obj)) {
+  if (WrapperFactory::IsXrayWrapper(obj) && AccessCheck::isChrome(obj)) {
     return JS_GetProperty(cx, obj, "wrappedJSObject", vp);
   }
 
   JS_SET_RVAL(cx, vp, v);
   return true;
 }
 
 static JSBool
--- a/js/xpconnect/wrappers/AccessCheck.cpp
+++ b/js/xpconnect/wrappers/AccessCheck.cpp
@@ -47,16 +47,26 @@ AccessCheck::subsumes(JSCompartment *a, 
 
     bool subsumes;
     nsresult rv = aprin->Subsumes(bprin, &subsumes);
     NS_ENSURE_SUCCESS(rv, false);
 
     return subsumes;
 }
 
+// Does the compartment of the wrapper subsumes the compartment of the wrappee?
+bool
+AccessCheck::wrapperSubsumes(JSObject *wrapper)
+{
+    MOZ_ASSERT(js::IsWrapper(wrapper));
+    JSObject *wrapped = js::UnwrapObject(wrapper);
+    return AccessCheck::subsumes(js::GetObjectCompartment(wrapper),
+                                 js::GetObjectCompartment(wrapped));
+}
+
 bool
 AccessCheck::isLocationObjectSameOrigin(JSContext *cx, JSObject *wrapper)
 {
     // The caller must ensure that the given wrapper wraps a Location object.
     MOZ_ASSERT(WrapperFactory::IsLocationObject(js::UnwrapObject(wrapper)));
 
     // Location objects are parented to the outer window for which they
     // were created. This gives us an easy way to determine whether our
@@ -87,16 +97,22 @@ AccessCheck::isChrome(JSCompartment *com
     }
 
     bool privileged;
     nsIPrincipal *principal = GetCompartmentPrincipal(compartment);
     return NS_SUCCEEDED(ssm->IsSystemPrincipal(principal, &privileged)) && privileged;
 }
 
 bool
+AccessCheck::isChrome(JSObject *obj)
+{
+    return isChrome(js::GetObjectCompartment(obj));
+}
+
+bool
 AccessCheck::callerIsChrome()
 {
     nsIScriptSecurityManager *ssm = XPCWrapper::GetSecurityManager();
     if (!ssm)
         return false;
     bool subjectIsSystem;
     nsresult rv = ssm->SubjectPrincipalIsSystem(&subjectIsSystem);
     return NS_SUCCEEDED(rv) && subjectIsSystem;
--- a/js/xpconnect/wrappers/AccessCheck.h
+++ b/js/xpconnect/wrappers/AccessCheck.h
@@ -14,17 +14,19 @@
 
 class nsIPrincipal;
 
 namespace xpc {
 
 class AccessCheck {
   public:
     static bool subsumes(JSCompartment *a, JSCompartment *b);
+    static bool wrapperSubsumes(JSObject *wrapper);
     static bool isChrome(JSCompartment *compartment);
+    static bool isChrome(JSObject *obj);
     static bool callerIsChrome();
     static nsIPrincipal *getPrincipal(JSCompartment *compartment);
     static bool isCrossOriginAccessPermitted(JSContext *cx, JSObject *obj, jsid id,
                                              js::Wrapper::Action act);
     static bool isSystemOnlyAccessPermitted(JSContext *cx);
     static bool isLocationObjectSameOrigin(JSContext *cx, JSObject *wrapper);
 
     static bool needsSystemOnlyWrapper(JSObject *obj);
--- a/js/xpconnect/wrappers/FilteringWrapper.cpp
+++ b/js/xpconnect/wrappers/FilteringWrapper.cpp
@@ -120,24 +120,20 @@ FilteringWrapper<Base, Policy>::enter(JS
 #define CW FilteringWrapper<SameCompartmentSecurityWrapper, \
                             ComponentsObjectPolicy>
 #define XCW FilteringWrapper<CrossCompartmentSecurityWrapper, \
                             ComponentsObjectPolicy>
 template<> SOW SOW::singleton(WrapperFactory::SCRIPT_ACCESS_ONLY_FLAG |
                               WrapperFactory::SOW_FLAG);
 template<> SCSOW SCSOW::singleton(WrapperFactory::SCRIPT_ACCESS_ONLY_FLAG |
                                   WrapperFactory::SOW_FLAG);
-template<> XOW XOW::singleton(WrapperFactory::SCRIPT_ACCESS_ONLY_FLAG |
-                              WrapperFactory::XOW_FLAG);
-template<> PXOW PXOW::singleton(WrapperFactory::SCRIPT_ACCESS_ONLY_FLAG |
-                                WrapperFactory::XOW_FLAG);
-template<> DXOW DXOW::singleton(WrapperFactory::SCRIPT_ACCESS_ONLY_FLAG |
-                                WrapperFactory::XOW_FLAG);
-template<> NNXOW NNXOW::singleton(WrapperFactory::SCRIPT_ACCESS_ONLY_FLAG |
-                                  WrapperFactory::XOW_FLAG);
+template<> XOW XOW::singleton(WrapperFactory::SCRIPT_ACCESS_ONLY_FLAG);
+template<> PXOW PXOW::singleton(WrapperFactory::SCRIPT_ACCESS_ONLY_FLAG);
+template<> DXOW DXOW::singleton(WrapperFactory::SCRIPT_ACCESS_ONLY_FLAG);
+template<> NNXOW NNXOW::singleton(WrapperFactory::SCRIPT_ACCESS_ONLY_FLAG);
 template<> LW  LW::singleton(WrapperFactory::SHADOWING_FORBIDDEN);
 template<> XLW XLW::singleton(WrapperFactory::SHADOWING_FORBIDDEN);
 
 template<> CW CW::singleton(0);
 template<> XCW XCW::singleton(0);
 
 template class SOW;
 template class XOW;
--- a/js/xpconnect/wrappers/WrapperFactory.h
+++ b/js/xpconnect/wrappers/WrapperFactory.h
@@ -13,18 +13,17 @@
 
 namespace xpc {
 
 class WrapperFactory {
   public:
     enum { WAIVE_XRAY_WRAPPER_FLAG = js::Wrapper::LAST_USED_FLAG << 1,
            IS_XRAY_WRAPPER_FLAG    = WAIVE_XRAY_WRAPPER_FLAG << 1,
            SCRIPT_ACCESS_ONLY_FLAG = IS_XRAY_WRAPPER_FLAG << 1,
-           XOW_FLAG                = SCRIPT_ACCESS_ONLY_FLAG << 1,
-           SOW_FLAG                = XOW_FLAG << 1,
+           SOW_FLAG                = SCRIPT_ACCESS_ONLY_FLAG << 1,
 
            // Prevent scripts from shadowing native properties.
            // NB: Applies only to Xray wrappers.
            // NB: This will prevent scriptable helpers from defining special
            //     handlers for properties defined in IDL. Use with caution.
            SHADOWING_FORBIDDEN     = SOW_FLAG << 1 };
 
     // Return true if any of any of the nested wrappers have the flag set.
@@ -33,20 +32,16 @@ class WrapperFactory {
         js::UnwrapObject(wrapper, true, &flags);
         return !!(flags & flag);
     }
 
     static bool IsXrayWrapper(JSObject *wrapper) {
         return HasWrapperFlag(wrapper, IS_XRAY_WRAPPER_FLAG);
     }
 
-    static bool IsXOW(JSObject *wrapper) {
-        return HasWrapperFlag(wrapper, XOW_FLAG);
-    }
-
     static bool HasWaiveXrayFlag(JSObject *wrapper) {
         return HasWrapperFlag(wrapper, WAIVE_XRAY_WRAPPER_FLAG);
     }
 
     static bool IsShadowingForbidden(JSObject *wrapper) {
         return HasWrapperFlag(wrapper, SHADOWING_FORBIDDEN);
     }
 
--- a/js/xpconnect/wrappers/XrayWrapper.cpp
+++ b/js/xpconnect/wrappers/XrayWrapper.cpp
@@ -914,23 +914,22 @@ bool
 XPCWrappedNativeXrayTraits::resolveOwnProperty(JSContext *cx, js::Wrapper &jsWrapper,
                                                JSObject *wrapper, JSObject *holder, jsid id,
                                                bool set, PropertyDescriptor *desc)
 {
     // Xray wrappers don't use the regular wrapper hierarchy, so we should be
     // in the wrapper's compartment here, not the wrappee.
     MOZ_ASSERT(js::IsObjectInContextCompartment(wrapper, cx));
     XPCJSRuntime* rt = nsXPConnect::GetRuntimeInstance();
-    if (!WrapperFactory::IsXOW(wrapper) &&
+    if (AccessCheck::isChrome(wrapper) &&
         (((id == rt->GetStringID(XPCJSRuntime::IDX_BASEURIOBJECT) ||
            id == rt->GetStringID(XPCJSRuntime::IDX_NODEPRINCIPAL)) &&
           Is<nsINode>(wrapper)) ||
           (id == rt->GetStringID(XPCJSRuntime::IDX_DOCUMENTURIOBJECT) &&
-          Is<nsIDocument>(wrapper))) &&
-        (AccessCheck::callerIsChrome())) {
+          Is<nsIDocument>(wrapper)))) {
         bool status;
         Wrapper::Action action = set ? Wrapper::SET : Wrapper::GET;
         desc->obj = NULL; // default value
         if (!jsWrapper.enter(cx, wrapper, id, action, &status))
             return status;
 
         desc->obj = wrapper;
         desc->attrs = JSPROP_ENUMERATE|JSPROP_SHARED;
@@ -1383,19 +1382,21 @@ XrayWrapper<Base, Traits>::getPropertyDe
         if (desc->obj)
             desc->obj = wrapper;
         return JS_WrapPropertyDescriptor(cx, desc);
     }
 
     if (!holder)
         return false;
 
-    // XOWs don't have a .wrappedJSObject property.
+    // Only chrome wrappers and same-origin xrays (used by jetpack sandboxes)
+    // get .wrappedJSObject. We can check this by determining if the compartment
+    // of the wrapper subsumes that of the wrappee.
     XPCJSRuntime* rt = nsXPConnect::GetRuntimeInstance();
-    if (!WrapperFactory::IsXOW(wrapper) &&
+    if (AccessCheck::wrapperSubsumes(wrapper) &&
         id == rt->GetStringID(XPCJSRuntime::IDX_WRAPPED_JSOBJECT)) {
         bool status;
         Wrapper::Action action = set ? Wrapper::SET : Wrapper::GET;
         desc->obj = NULL; // default value
         if (!this->enter(cx, wrapper, id, action, &status))
             return status;
 
         desc->obj = wrapper;
@@ -1576,17 +1577,17 @@ XrayWrapper<Base, Traits>::enumerate(JSC
 {
     // Redirect access straight to the wrapper if we should be transparent.
     if (XrayUtils::IsTransparent(cx, wrapper)) {
         JSObject *obj = Traits::getInnerObject(wrapper);
         JSAutoCompartment ac(cx, obj);
         return js::GetPropertyNames(cx, obj, flags, &props);
     }
 
-    if (WrapperFactory::IsXOW(wrapper)) {
+    if (!AccessCheck::wrapperSubsumes(wrapper)) {
         JS_ReportError(cx, "Not allowed to enumerate cross origin objects");
         return false;
     }
 
     return Traits::enumerateNames(cx, wrapper, flags, props);
 }
 
 template <typename Base, typename Traits>