diff --git a/js/xpconnect/wrappers/WrapperFactory.cpp b/js/xpconnect/wrappers/WrapperFactory.cpp index 38d602b2201..9c5d80c61cd 100644 --- a/js/xpconnect/wrappers/WrapperFactory.cpp +++ b/js/xpconnect/wrappers/WrapperFactory.cpp @@ -307,6 +307,41 @@ DEBUG_CheckUnwrapSafety(JSObject *obj, js::Wrapper *handler, #define DEBUG_CheckUnwrapSafety(obj, handler, origin, target) {} #endif +static Wrapper * +SelectWrapper(bool securityWrapper, bool wantXrays, XrayType xrayType, + bool waiveXrays) +{ + // Waived Xray uses a modified CCW that has transparent behavior but + // transitively waives Xrays on arguments. + if (waiveXrays) { + MOZ_ASSERT(!securityWrapper); + return &WaiveXrayWrapper::singleton; + } + + // If we don't want or can't use Xrays, select a wrapper that's either + // entirely transparent or entirely opaque. + if (!wantXrays || xrayType == NotXray) { + if (!securityWrapper) + return &CrossCompartmentWrapper::singleton; + return &FilteringWrapper::singleton; + } + + // Ok, we're using Xray. If this isn't a security wrapper, use the permissive + // version and skip the filter. + if (!securityWrapper) { + if (xrayType == XrayForWrappedNative) + return &PermissiveXrayXPCWN::singleton; + return &PermissiveXrayDOM::singleton; + } + + // This is a security wrapper. Use the security versions and filter. + if (xrayType == XrayForWrappedNative) + return &FilteringWrapper::singleton; + return &FilteringWrapper::singleton; +} + JSObject * WrapperFactory::Rewrap(JSContext *cx, JSObject *existing, JSObject *obj, JSObject *wrappedProto, JSObject *parent, @@ -367,66 +402,33 @@ WrapperFactory::Rewrap(JSContext *cx, JSObject *existing, JSObject *obj, // // Now, handle the regular cases. // + // These are wrappers we can compute using a rule-based approach. In order + // to do so, we need to compute some parameters. + // + else { - else if (targetIsChrome) { - if (originIsChrome) { - wrapper = &CrossCompartmentWrapper::singleton; - } else { - if (flags & WAIVE_XRAY_WRAPPER_FLAG) { - // If we waived the X-ray wrapper for this object, wrap it into a - // special wrapper to transitively maintain the X-ray waiver. - wrapper = &WaiveXrayWrapper::singleton; - } else { - // Native objects must be wrapped into an X-ray wrapper. - if (xrayType == XrayForDOMObject) { - wrapper = &PermissiveXrayDOM::singleton; - } else if (xrayType == XrayForWrappedNative) { - wrapper = &PermissiveXrayXPCWN::singleton; - } else { - wrapper = &CrossCompartmentWrapper::singleton; - } - } - } - } else if (originIsChrome) { + // The wrapper is a security wrapper (protecting the wrappee) if and + // only if the target does not subsume the origin. + bool securityWrapper = !targetSubsumesOrigin; - if (xrayType == XrayForWrappedNative) { - wrapper = &FilteringWrapper::singleton; - } else if (xrayType == XrayForDOMObject) { - wrapper = &FilteringWrapper::singleton; - } else { - MOZ_NOT_REACHED(); - } - } else if (targetSubsumesOrigin) { - // For the same-origin case we use a transparent wrapper, unless one - // of the following is true: - // * The object is flagged as needing a SOW. - // * The object is a Components object. - // * The context compartment specifically requested Xray vision into - // same-origin compartments. + // Xrays are warranted if either the target or the origin don't trust + // each other. This is generally the case, unless the two are same-origin + // and the caller has not requested same-origin Xrays. // - // The first two cases always require a security wrapper for non-chrome - // access, regardless of the origin of the object. - if (!targetdata->wantXrays || xrayType == NotXray) { - wrapper = &CrossCompartmentWrapper::singleton; - } else if (xrayType == XrayForDOMObject) { - wrapper = &PermissiveXrayDOM::singleton; - } else { - wrapper = &PermissiveXrayXPCWN::singleton; - } - } else { - // Cross origin we want to disallow scripting and limit access to - // a predefined set of properties. - if (xrayType == NotXray) { - wrapper = &FilteringWrapper::singleton; - } else if (xrayType == XrayForDOMObject) { - wrapper = &FilteringWrapper::singleton; - } else { - wrapper = &FilteringWrapper::singleton; - } + // Xrays are a bidirectional protection, since it affords clarity to the + // caller and privacy to the callee. + bool wantXrays = !(sameOrigin && !targetdata->wantXrays); + + // If Xrays are warranted, the caller may waive them for non-security + // wrappers. + bool waiveXrays = wantXrays && !securityWrapper && + (flags & WAIVE_XRAY_WRAPPER_FLAG); + + wrapper = SelectWrapper(securityWrapper, wantXrays, xrayType, waiveXrays); } + + // If the prototype of a chrome object being wrapped in content is a prototype // for a standard class, use the one from the content compartment so // that we can safely take advantage of things like .forEach().