JSObject * WrapperFactory::Rewrap(JSContext *cx, JSObject *obj, JSObject *wrappedProto, JSObject *parent, unsigned flags) { NS_ASSERTION(!IsWrapper(obj) || GetProxyHandler(obj) == &WaiveXrayWrapperWrapper || js::GetObjectClass(obj)->ext.innerObject, "wrapped object passed to rewrap"); NS_ASSERTION(JS_GetClass(obj) != &XrayUtils::HolderClass, "trying to wrap a holder"); JSCompartment *origin = js::GetObjectCompartment(obj); JSCompartment *target = js::GetContextCompartment(cx); bool usingXray = false; Wrapper *wrapper; CompartmentPrivate *targetdata = static_cast<CompartmentPrivate *>(JS_GetCompartmentPrivate(target)); if (AccessCheck::isChrome(target)) { if (AccessCheck::isChrome(origin)) { wrapper = &CrossCompartmentWrapper::singleton; } else { bool isSystem; { JSAutoEnterCompartment ac; if (!ac.enter(cx, obj)) return nsnull; JSObject *globalObj = JS_GetGlobalForObject(cx, obj); JS_ASSERT(globalObj); isSystem = JS_IsSystemObject(cx, globalObj); } if (isSystem) { 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 = &CrossOriginWrapper::singleton; } else { // Native objects must be wrapped into an X-ray wrapper. bool proxy; if (CanXray(obj, &proxy)) { if (proxy) { wrapper = &XrayProxy::singleton; } else { typedef XrayWrapper<CrossCompartmentWrapper> Xray; usingXray = true; wrapper = &Xray::singleton; } } else { wrapper = &NoWaiverWrapper::singleton; } } } } else if (AccessCheck::isChrome(origin)) { JSFunction *fun = JS_GetObjectFunction(obj); if (fun) { if (JS_IsBuiltinEvalFunction(fun) || JS_IsBuiltinFunctionConstructor(fun)) { JS_ReportError(cx, "Not allowed to access chrome eval or Function from content"); return nsnull; } } XPCWrappedNative *wn; if (targetdata && (wn = GetWrappedNative(cx, obj)) && wn->HasProto() && wn->GetProto()->ClassIsDOMObject()) { typedef XrayWrapper<CrossCompartmentSecurityWrapper> Xray; usingXray = true; if (IsLocationObject(obj)) wrapper = &FilteringWrapper<Xray, LocationPolicy>::singleton; else wrapper = &FilteringWrapper<Xray, 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 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. bool proxy; 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 && CanXray(obj, &proxy)) { if (proxy) { wrapper = &XrayProxy::singleton; } else { typedef XrayWrapper<CrossCompartmentWrapper> Xray; usingXray = true; wrapper = &Xray::singleton; } } else { wrapper = &CrossCompartmentWrapper::singleton; } } else { NS_ASSERTION(!AccessCheck::needsSystemOnlyWrapper(obj), "bad object exposed across origins"); // Cross origin we want to disallow scripting and limit access to // a predefined set of properties. XrayWrapper adds a property // (.wrappedJSObject) which allows bypassing the XrayWrapper, but // we filter out access to that property. bool proxy; if (!CanXray(obj, &proxy)) { wrapper = &FilteringWrapper<CrossCompartmentSecurityWrapper, CrossOriginAccessiblePropertiesOnly>::singleton; } else { if (proxy) { wrapper = &FilteringWrapper<XrayProxy, CrossOriginAccessiblePropertiesOnly>::singleton; } else { typedef XrayWrapper<CrossCompartmentSecurityWrapper> Xray; usingXray = true; // Location objects can become same origin after navigation, so we might // have to grant transparent access later on. if (IsLocationObject(obj)) { wrapper = &FilteringWrapper<Xray, LocationPolicy>::singleton; } else { wrapper = &FilteringWrapper<Xray, CrossOriginAccessiblePropertiesOnly>::singleton; } } } } JSObject *wrapperObj = Wrapper::New(cx, obj, wrappedProto, parent, wrapper); if (!wrapperObj || !usingXray) return wrapperObj; JSObject *xrayHolder = XrayUtils::createHolder(cx, obj, parent); if (!xrayHolder) return nsnull; js::SetProxyExtra(wrapperObj, 0, js::ObjectValue(*xrayHolder)); return wrapperObj; }
JSObject * WrapperFactory::Rewrap(JSContext *cx, JSObject *obj, JSObject *wrappedProto, JSObject *parent, uintN flags) { NS_ASSERTION(!obj->isWrapper() || (obj->isWrapper() && obj->getProxyHandler() == &WaiveXrayWrapperWrapper) || obj->getClass()->ext.innerObject, "wrapped object passed to rewrap"); NS_ASSERTION(JS_GET_CLASS(cx, obj) != &XrayUtils::HolderClass, "trying to wrap a holder"); JSCompartment *origin = obj->compartment(); JSCompartment *target = cx->compartment; JSObject *xrayHolder = nsnull; JSWrapper *wrapper; CompartmentPrivate *targetdata = static_cast<CompartmentPrivate *>(JS_GetCompartmentPrivate(cx, target)); if (AccessCheck::isChrome(target)) { if (AccessCheck::isChrome(origin)) { wrapper = &JSCrossCompartmentWrapper::singleton; } else { bool isSystem; { JSAutoEnterCompartment ac; if (!ac.enter(cx, obj)) return nsnull; JSObject *globalObj = JS_GetGlobalForObject(cx, obj); JS_ASSERT(globalObj); isSystem = JS_IsSystemObject(cx, globalObj); } if (isSystem) { wrapper = &JSCrossCompartmentWrapper::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 = &CrossOriginWrapper::singleton; } else { // Native objects must be wrapped into an X-ray wrapper. if (IS_WN_WRAPPER(obj) || obj->getClass()->ext.innerObject) { typedef XrayWrapper<JSCrossCompartmentWrapper> Xray; wrapper = &Xray::singleton; xrayHolder = Xray::createHolder(cx, obj, parent); if (!xrayHolder) return nsnull; } else { wrapper = &NoWaiverWrapper::singleton; } } } } else if (AccessCheck::isChrome(origin)) { if (obj->isFunction()) { JSFunction *fun = obj->getFunctionPrivate(); if (JS_IsBuiltinEvalFunction(fun) || JS_IsBuiltinFunctionConstructor(fun)) { JS_ReportError(cx, "Not allowed to access chrome eval or Function from content"); return nsnull; } } XPCWrappedNative *wn; if (targetdata && (wn = GetWrappedNative(cx, obj)) && wn->HasProto() && wn->GetProto()->ClassIsDOMObject()) { typedef XrayWrapper<JSCrossCompartmentWrapper> Xray; wrapper = &FilteringWrapper<Xray, CrossOriginAccessiblePropertiesOnly>::singleton; xrayHolder = Xray::createHolder(cx, obj, parent); if (!xrayHolder) return nsnull; } else { wrapper = &FilteringWrapper<JSCrossCompartmentWrapper, ExposedPropertiesOnly>::singleton; } } else if (AccessCheck::isSameOrigin(origin, target)) { // Same origin we use a transparent wrapper, unless the compartment asks // for an Xray or the wrapper needs a SOW. if (AccessCheck::needsSystemOnlyWrapper(obj)) { wrapper = &FilteringWrapper<JSCrossCompartmentWrapper, OnlyIfSubjectIsSystem>::singleton; } else if (targetdata && targetdata->wantXrays && (IS_WN_WRAPPER(obj) || obj->getClass()->ext.innerObject)) { typedef XrayWrapper<JSCrossCompartmentWrapper> Xray; wrapper = &Xray::singleton; xrayHolder = Xray::createHolder(cx, obj, parent); if (!xrayHolder) return nsnull; } else { wrapper = &JSCrossCompartmentWrapper::singleton; } } else { NS_ASSERTION(!AccessCheck::needsSystemOnlyWrapper(obj), "bad object exposed across origins"); // Cross origin we want to disallow scripting and limit access to // a predefined set of properties. XrayWrapper adds a property // (.wrappedJSObject) which allows bypassing the XrayWrapper, but // we filter out access to that property. if (!IS_WN_WRAPPER(obj) && !obj->getClass()->ext.innerObject) { wrapper = &FilteringWrapper<JSCrossCompartmentWrapper, CrossOriginAccessiblePropertiesOnly>::singleton; } else { typedef XrayWrapper<JSCrossCompartmentWrapper> Xray; // Location objects can become same origin after navigation, so we might // have to grant transparent access later on. if (IsLocationObject(obj)) { wrapper = &FilteringWrapper<Xray, SameOriginOrCrossOriginAccessiblePropertiesOnly>::singleton; } else { wrapper = &FilteringWrapper<Xray, CrossOriginAccessiblePropertiesOnly>::singleton; } xrayHolder = Xray::createHolder(cx, obj, parent); if (!xrayHolder) return nsnull; } } JSObject *wrapperObj = JSWrapper::New(cx, obj, wrappedProto, parent, wrapper); if (!wrapperObj || !xrayHolder) return wrapperObj; // NB: The fact that the only wrappers to use ProxyExtra are XrayWrappers // is relied on by XPCNativeWrapper.unwrap. wrapperObj->setProxyExtra(js::ObjectValue(*xrayHolder)); return wrapperObj; }