Bug 739796 - Make same-origin cross-compartment Location object access go through the LW in the host compartment. r=gal
authorBobby Holley <bobbyholley@gmail.com>
Thu, 05 Apr 2012 12:21:12 -0700
changeset 94414 fe8ffd7166eb82cce58630bb8112f6e1e8537196
parent 94413 850547d0b635f36934de66c0714eab67b139ee88
child 94415 0b28f9e01c51c6b38f187e8b3f5d4183d4d19ade
push id886
push userlsblakk@mozilla.com
push dateMon, 04 Jun 2012 19:57:52 +0000
treeherdermozilla-beta@bbd8d5efd6d1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgal
bugs739796
milestone14.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 739796 - Make same-origin cross-compartment Location object access go through the LW in the host compartment. r=gal
js/xpconnect/wrappers/WrapperFactory.cpp
--- a/js/xpconnect/wrappers/WrapperFactory.cpp
+++ b/js/xpconnect/wrappers/WrapperFactory.cpp
@@ -368,33 +368,55 @@ WrapperFactory::Rewrap(JSContext *cx, JS
             wrapper = &FilteringWrapper<XrayDOM, CrossOriginAccessiblePropertiesOnly>::singleton;
         } else {
             wrapper = &FilteringWrapper<CrossCompartmentSecurityWrapper,
                                         ExposedPropertiesOnly>::singleton;
         }
     } else if (AccessCheck::isSameOrigin(origin, target)) {
         // For the same-origin case we use a transparent wrapper, unless one
         // of the following is true:
-        // * The wrapper is a Location object.
-        // * The wrapper is flagged as needing a SOW.
+        // * The object is flagged as needing a SOW.
+        // * The object is a location object.
         // * The context compartment specifically requested Xray vision into
         //   same-origin compartments.
         //
         // The first two cases always require a security wrapper for non-chrome
         // access, regardless of the origin of the object.
+        //
+        // The Location case is a bit tricky. Because the security characteristics
+        // depend on the current outer window, we always have a security wrapper
+        // around locations, same-compartment or cross-compartment. We would
+        // normally just use an identical security policy and just switch between
+        // Wrapper and CrossCompartmentWrapper to differentiate the cases (LW/XLW).
+        // However, there's an added wrinkle that same-origin-but-cross-compartment
+        // scripts expect to be able to see expandos on each others' location
+        // objects. So if all cross-compartment access used XLWs, then the expandos
+        // would live on the per-compartment XrayWrapper expando object, and would
+        // not be shared. So to make sure that expandos work correctly in the
+        // same-origin case, we need to use a transparent CrossCompartmentWrapper
+        // to the LW in the host compartment, rather than an XLW directly to the
+        // Location object. This still doesn't share expandos in the
+        // document.domain case, but that's probably fine. Double-wrapping sucks,
+        // but it's kind of unavoidable here.
         XrayType type;
         if (AccessCheck::needsSystemOnlyWrapper(obj)) {
             wrapper = &FilteringWrapper<CrossCompartmentSecurityWrapper,
                                         OnlyIfSubjectIsSystem>::singleton;
-        } else if (IsLocationObject(obj)) {
-            typedef XrayWrapper<CrossCompartmentSecurityWrapper> Xray;
-            usingXray = true;
-            wrapper = &FilteringWrapper<Xray, LocationPolicy>::singleton;
         } else if (!targetdata || !targetdata->wantXrays ||
                    (type = GetXrayType(obj)) == NotXray) {
+            // Do the double-wrapping if need be.
+            if (IsLocationObject(obj)) {
+                JSAutoEnterCompartment ac;
+                if (!ac.enter(cx, obj))
+                    return nsnull;
+                XPCWrappedNative *wn = GetWrappedNative(cx, obj);
+                if (!wn)
+                    return nsnull;
+                obj = wn->GetSameCompartmentSecurityWrapper(cx);
+            }
             wrapper = &CrossCompartmentWrapper::singleton;
         } else if (type == XrayForDOMObject) {
             wrapper = &XrayDOM::singleton;
         } else if (type == XrayForDOMProxyObject) {
             wrapper = &XrayProxy::singleton;
         } else {
             typedef XrayWrapper<CrossCompartmentWrapper> Xray;
             usingXray = true;