diff --git a/js/xpconnect/wrappers/WrapperFactory.cpp b/js/xpconnect/wrappers/WrapperFactory.cpp index cdb8b92fe30..cdbb30dcabe 100644 --- a/js/xpconnect/wrappers/WrapperFactory.cpp +++ b/js/xpconnect/wrappers/WrapperFactory.cpp @@ -373,23 +373,45 @@ WrapperFactory::Rewrap(JSContext *cx, JSObject *obj, JSObject *wrappedProto, JSO } 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::singleton; - } else if (IsLocationObject(obj)) { - typedef XrayWrapper Xray; - usingXray = true; - wrapper = &FilteringWrapper::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;