Sat, 03 Jan 2015 20:18:00 +0100
Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* vim: set ts=8 sts=4 et sw=4 tw=99: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "WaiveXrayWrapper.h"
8 #include "FilteringWrapper.h"
9 #include "XrayWrapper.h"
10 #include "AccessCheck.h"
11 #include "XPCWrapper.h"
12 #include "ChromeObjectWrapper.h"
13 #include "WrapperFactory.h"
15 #include "xpcprivate.h"
16 #include "XPCMaps.h"
17 #include "mozilla/dom/BindingUtils.h"
18 #include "jsfriendapi.h"
19 #include "mozilla/Likely.h"
20 #include "nsContentUtils.h"
22 using namespace JS;
23 using namespace js;
24 using namespace mozilla;
26 namespace xpc {
28 // When chrome pulls a naked property across the membrane using
29 // .wrappedJSObject, we want it to cross the membrane into the
30 // chrome compartment without automatically being wrapped into an
31 // X-ray wrapper. We achieve this by wrapping it into a special
32 // transparent wrapper in the origin (non-chrome) compartment. When
33 // an object with that special wrapper applied crosses into chrome,
34 // we know to not apply an X-ray wrapper.
35 Wrapper XrayWaiver(WrapperFactory::WAIVE_XRAY_WRAPPER_FLAG);
37 // When objects for which we waived the X-ray wrapper cross into
38 // chrome, we wrap them into a special cross-compartment wrapper
39 // that transitively extends the waiver to all properties we get
40 // off it.
41 WaiveXrayWrapper WaiveXrayWrapper::singleton(0);
43 bool
44 WrapperFactory::IsCOW(JSObject *obj)
45 {
46 return IsWrapper(obj) &&
47 Wrapper::wrapperHandler(obj) == &ChromeObjectWrapper::singleton;
48 }
50 JSObject *
51 WrapperFactory::GetXrayWaiver(HandleObject obj)
52 {
53 // Object should come fully unwrapped but outerized.
54 MOZ_ASSERT(obj == UncheckedUnwrap(obj));
55 MOZ_ASSERT(!js::GetObjectClass(obj)->ext.outerObject);
56 XPCWrappedNativeScope *scope = GetObjectScope(obj);
57 MOZ_ASSERT(scope);
59 if (!scope->mWaiverWrapperMap)
60 return nullptr;
62 JSObject* xrayWaiver = scope->mWaiverWrapperMap->Find(obj);
63 if (xrayWaiver)
64 JS::ExposeObjectToActiveJS(xrayWaiver);
66 return xrayWaiver;
67 }
69 JSObject *
70 WrapperFactory::CreateXrayWaiver(JSContext *cx, HandleObject obj)
71 {
72 // The caller is required to have already done a lookup.
73 // NB: This implictly performs the assertions of GetXrayWaiver.
74 MOZ_ASSERT(!GetXrayWaiver(obj));
75 XPCWrappedNativeScope *scope = GetObjectScope(obj);
77 JSAutoCompartment ac(cx, obj);
78 JSObject *waiver = Wrapper::New(cx, obj,
79 JS_GetGlobalForObject(cx, obj),
80 &XrayWaiver);
81 if (!waiver)
82 return nullptr;
84 // Add the new waiver to the map. It's important that we only ever have
85 // one waiver for the lifetime of the target object.
86 if (!scope->mWaiverWrapperMap) {
87 scope->mWaiverWrapperMap =
88 JSObject2JSObjectMap::newMap(XPC_WRAPPER_MAP_SIZE);
89 MOZ_ASSERT(scope->mWaiverWrapperMap);
90 }
91 if (!scope->mWaiverWrapperMap->Add(cx, obj, waiver))
92 return nullptr;
93 return waiver;
94 }
96 JSObject *
97 WrapperFactory::WaiveXray(JSContext *cx, JSObject *objArg)
98 {
99 RootedObject obj(cx, objArg);
100 obj = UncheckedUnwrap(obj);
101 MOZ_ASSERT(!js::IsInnerObject(obj));
103 JSObject *waiver = GetXrayWaiver(obj);
104 if (waiver)
105 return waiver;
106 return CreateXrayWaiver(cx, obj);
107 }
109 // DoubleWrap is called from PrepareForWrapping to maintain the state that
110 // we're supposed to waive Xray wrappers for the given on. On entrance, it
111 // expects |cx->compartment != obj->compartment()|. The returned object will
112 // be in the same compartment as |obj|.
113 JSObject *
114 WrapperFactory::DoubleWrap(JSContext *cx, HandleObject obj, unsigned flags)
115 {
116 if (flags & WrapperFactory::WAIVE_XRAY_WRAPPER_FLAG) {
117 JSAutoCompartment ac(cx, obj);
118 return WaiveXray(cx, obj);
119 }
120 return obj;
121 }
123 JSObject *
124 WrapperFactory::PrepareForWrapping(JSContext *cx, HandleObject scope,
125 HandleObject objArg, unsigned flags)
126 {
127 RootedObject obj(cx, objArg);
128 // Outerize any raw inner objects at the entry point here, so that we don't
129 // have to worry about them for the rest of the wrapping code.
130 if (js::IsInnerObject(obj)) {
131 JSAutoCompartment ac(cx, obj);
132 obj = JS_ObjectToOuterObject(cx, obj);
133 NS_ENSURE_TRUE(obj, nullptr);
134 // The outerization hook wraps, which means that we can end up with a
135 // CCW here if |obj| was a navigated-away-from inner. Strip any CCWs.
136 obj = js::UncheckedUnwrap(obj);
137 MOZ_ASSERT(js::IsOuterObject(obj));
138 }
140 // If we've got an outer window, there's nothing special that needs to be
141 // done here, and we can move on to the next phase of wrapping. We handle
142 // this case first to allow us to assert against wrappers below.
143 if (js::IsOuterObject(obj))
144 return DoubleWrap(cx, obj, flags);
146 // Here are the rules for wrapping:
147 // We should never get a proxy here (the JS engine unwraps those for us).
148 MOZ_ASSERT(!IsWrapper(obj));
150 // If the object being wrapped is a prototype for a standard class and the
151 // wrapper does not subsumes the wrappee, use the one from the content
152 // compartment. This is generally safer all-around, and in the COW case this
153 // lets us safely take advantage of things like .forEach() via the
154 // ChromeObjectWrapper machinery.
155 //
156 // If the prototype chain of chrome object |obj| looks like this:
157 //
158 // obj => foo => bar => chromeWin.StandardClass.prototype
159 //
160 // The prototype chain of COW(obj) looks lke this:
161 //
162 // COW(obj) => COW(foo) => COW(bar) => contentWin.StandardClass.prototype
163 //
164 // NB: We now remap all non-subsuming access of standard prototypes.
165 //
166 // NB: We need to ignore domain here so that the security relationship we
167 // compute here can't change over time. See the comment above the other
168 // subsumes call below.
169 bool subsumes = AccessCheck::subsumes(js::GetContextCompartment(cx),
170 js::GetObjectCompartment(obj));
171 XrayType xrayType = GetXrayType(obj);
172 if (!subsumes && xrayType == NotXray) {
173 JSProtoKey key = JSProto_Null;
174 {
175 JSAutoCompartment ac(cx, obj);
176 key = IdentifyStandardPrototype(obj);
177 }
178 if (key != JSProto_Null) {
179 RootedObject homeProto(cx);
180 if (!JS_GetClassPrototype(cx, key, &homeProto))
181 return nullptr;
182 MOZ_ASSERT(homeProto);
183 // No need to double-wrap here. We should never have waivers to
184 // COWs.
185 return homeProto;
186 }
187 }
189 // Now, our object is ready to be wrapped, but several objects (notably
190 // nsJSIIDs) have a wrapper per scope. If we are about to wrap one of
191 // those objects in a security wrapper, then we need to hand back the
192 // wrapper for the new scope instead. Also, global objects don't move
193 // between scopes so for those we also want to return the wrapper. So...
194 if (!IS_WN_REFLECTOR(obj) || !js::GetObjectParent(obj))
195 return DoubleWrap(cx, obj, flags);
197 XPCWrappedNative *wn = XPCWrappedNative::Get(obj);
199 JSAutoCompartment ac(cx, obj);
200 XPCCallContext ccx(JS_CALLER, cx, obj);
201 RootedObject wrapScope(cx, scope);
203 {
204 if (NATIVE_HAS_FLAG(&ccx, WantPreCreate)) {
205 // We have a precreate hook. This object might enforce that we only
206 // ever create JS object for it.
208 // Note: this penalizes objects that only have one wrapper, but are
209 // being accessed across compartments. We would really prefer to
210 // replace the above code with a test that says "do you only have one
211 // wrapper?"
212 nsresult rv = wn->GetScriptableInfo()->GetCallback()->
213 PreCreate(wn->Native(), cx, scope, wrapScope.address());
214 NS_ENSURE_SUCCESS(rv, DoubleWrap(cx, obj, flags));
216 // If the handed back scope differs from the passed-in scope and is in
217 // a separate compartment, then this object is explicitly requesting
218 // that we don't create a second JS object for it: create a security
219 // wrapper.
220 if (js::GetObjectCompartment(scope) != js::GetObjectCompartment(wrapScope))
221 return DoubleWrap(cx, obj, flags);
223 RootedObject currentScope(cx, JS_GetGlobalForObject(cx, obj));
224 if (MOZ_UNLIKELY(wrapScope != currentScope)) {
225 // The wrapper claims it wants to be in the new scope, but
226 // currently has a reflection that lives in the old scope. This
227 // can mean one of two things, both of which are rare:
228 //
229 // 1 - The object has a PreCreate hook (we checked for it above),
230 // but is deciding to request one-wrapper-per-scope (rather than
231 // one-wrapper-per-native) for some reason. Usually, a PreCreate
232 // hook indicates one-wrapper-per-native. In this case we want to
233 // make a new wrapper in the new scope.
234 //
235 // 2 - We're midway through wrapper reparenting. The document has
236 // moved to a new scope, but |wn| hasn't been moved yet, and
237 // we ended up calling JS_WrapObject() on its JS object. In this
238 // case, we want to return the existing wrapper.
239 //
240 // So we do a trick: call PreCreate _again_, but say that we're
241 // wrapping for the old scope, rather than the new one. If (1) is
242 // the case, then PreCreate will return the scope we pass to it
243 // (the old scope). If (2) is the case, PreCreate will return the
244 // scope of the document (the new scope).
245 RootedObject probe(cx);
246 rv = wn->GetScriptableInfo()->GetCallback()->
247 PreCreate(wn->Native(), cx, currentScope, probe.address());
249 // Check for case (2).
250 if (probe != currentScope) {
251 MOZ_ASSERT(probe == wrapScope);
252 return DoubleWrap(cx, obj, flags);
253 }
255 // Ok, must be case (1). Fall through and create a new wrapper.
256 }
258 // Nasty hack for late-breaking bug 781476. This will confuse identity checks,
259 // but it's probably better than any of our alternatives.
260 //
261 // Note: We have to ignore domain here. The JS engine assumes that, given a
262 // compartment c, if c->wrap(x) returns a cross-compartment wrapper at time t0,
263 // it will also return a cross-compartment wrapper for any time t1 > t0 unless
264 // an explicit transplant is performed. In particular, wrapper recomputation
265 // assumes that recomputing a wrapper will always result in a wrapper.
266 //
267 // This doesn't actually pose a security issue, because we'll still compute
268 // the correct (opaque) wrapper for the object below given the security
269 // characteristics of the two compartments.
270 if (!AccessCheck::isChrome(js::GetObjectCompartment(wrapScope)) &&
271 AccessCheck::subsumes(js::GetObjectCompartment(wrapScope),
272 js::GetObjectCompartment(obj)))
273 {
274 return DoubleWrap(cx, obj, flags);
275 }
276 }
277 }
279 // This public WrapNativeToJSVal API enters the compartment of 'wrapScope'
280 // so we don't have to.
281 RootedValue v(cx);
282 nsresult rv =
283 nsXPConnect::XPConnect()->WrapNativeToJSVal(cx, wrapScope, wn->Native(), nullptr,
284 &NS_GET_IID(nsISupports), false, &v);
285 NS_ENSURE_SUCCESS(rv, nullptr);
287 obj.set(&v.toObject());
288 MOZ_ASSERT(IS_WN_REFLECTOR(obj), "bad object");
290 // Because the underlying native didn't have a PreCreate hook, we had
291 // to a new (or possibly pre-existing) XPCWN in our compartment.
292 // This could be a problem for chrome code that passes XPCOM objects
293 // across compartments, because the effects of QI would disappear across
294 // compartments.
295 //
296 // So whenever we pull an XPCWN across compartments in this manner, we
297 // give the destination object the union of the two native sets. We try
298 // to do this cleverly in the common case to avoid too much overhead.
299 XPCWrappedNative *newwn = XPCWrappedNative::Get(obj);
300 XPCNativeSet *unionSet = XPCNativeSet::GetNewOrUsed(newwn->GetSet(),
301 wn->GetSet(), false);
302 if (!unionSet)
303 return nullptr;
304 newwn->SetSet(unionSet);
306 return DoubleWrap(cx, obj, flags);
307 }
309 #ifdef DEBUG
310 static void
311 DEBUG_CheckUnwrapSafety(HandleObject obj, js::Wrapper *handler,
312 JSCompartment *origin, JSCompartment *target)
313 {
314 if (AccessCheck::isChrome(target) || xpc::IsUniversalXPConnectEnabled(target)) {
315 // If the caller is chrome (or effectively so), unwrap should always be allowed.
316 MOZ_ASSERT(!handler->hasSecurityPolicy());
317 } else if (handler == &FilteringWrapper<CrossCompartmentSecurityWrapper, GentlyOpaque>::singleton) {
318 // We explicitly use a SecurityWrapper to protect privileged callers from
319 // less-privileged objects that they should never see. Skip the check in
320 // this case.
321 } else {
322 // Otherwise, it should depend on whether the target subsumes the origin.
323 MOZ_ASSERT(handler->hasSecurityPolicy() == !AccessCheck::subsumesConsideringDomain(target, origin));
324 }
325 }
326 #else
327 #define DEBUG_CheckUnwrapSafety(obj, handler, origin, target) {}
328 #endif
330 static Wrapper *
331 SelectWrapper(bool securityWrapper, bool wantXrays, XrayType xrayType,
332 bool waiveXrays, bool originIsXBLScope)
333 {
334 // Waived Xray uses a modified CCW that has transparent behavior but
335 // transitively waives Xrays on arguments.
336 if (waiveXrays) {
337 MOZ_ASSERT(!securityWrapper);
338 return &WaiveXrayWrapper::singleton;
339 }
341 // If we don't want or can't use Xrays, select a wrapper that's either
342 // entirely transparent or entirely opaque.
343 if (!wantXrays || xrayType == NotXray) {
344 if (!securityWrapper)
345 return &CrossCompartmentWrapper::singleton;
346 // In general, we don't want opaque function wrappers to be callable.
347 // But in the case of XBL, we rely on content being able to invoke
348 // functions exposed from the XBL scope. We could remove this exception,
349 // if needed, by using ExportFunction to generate the content-side
350 // representations of XBL methods.
351 else if (originIsXBLScope)
352 return &FilteringWrapper<CrossCompartmentSecurityWrapper, OpaqueWithCall>::singleton;
353 return &FilteringWrapper<CrossCompartmentSecurityWrapper, Opaque>::singleton;
354 }
356 // Ok, we're using Xray. If this isn't a security wrapper, use the permissive
357 // version and skip the filter.
358 if (!securityWrapper) {
359 if (xrayType == XrayForWrappedNative)
360 return &PermissiveXrayXPCWN::singleton;
361 else if (xrayType == XrayForDOMObject)
362 return &PermissiveXrayDOM::singleton;
363 MOZ_ASSERT(xrayType == XrayForJSObject);
364 return &PermissiveXrayJS::singleton;
365 }
367 // This is a security wrapper. Use the security versions and filter.
368 if (xrayType == XrayForWrappedNative)
369 return &FilteringWrapper<SecurityXrayXPCWN,
370 CrossOriginAccessiblePropertiesOnly>::singleton;
371 else if (xrayType == XrayForDOMObject)
372 return &FilteringWrapper<SecurityXrayDOM,
373 CrossOriginAccessiblePropertiesOnly>::singleton;
374 // There's never any reason to expose pure JS objects to non-subsuming actors.
375 // Just use an opaque wrapper in this case.
376 MOZ_ASSERT(xrayType == XrayForJSObject);
377 return &FilteringWrapper<CrossCompartmentSecurityWrapper, Opaque>::singleton;
378 }
380 JSObject *
381 WrapperFactory::Rewrap(JSContext *cx, HandleObject existing, HandleObject obj,
382 HandleObject wrappedProto, HandleObject parent,
383 unsigned flags)
384 {
385 MOZ_ASSERT(!IsWrapper(obj) ||
386 GetProxyHandler(obj) == &XrayWaiver ||
387 js::GetObjectClass(obj)->ext.innerObject,
388 "wrapped object passed to rewrap");
389 MOZ_ASSERT(!XrayUtils::IsXPCWNHolderClass(JS_GetClass(obj)), "trying to wrap a holder");
390 MOZ_ASSERT(!js::IsInnerObject(obj));
391 // We sometimes end up here after nsContentUtils has been shut down but before
392 // XPConnect has been shut down, so check the context stack the roundabout way.
393 MOZ_ASSERT(XPCJSRuntime::Get()->GetJSContextStack()->Peek() == cx);
395 // Compute the information we need to select the right wrapper.
396 JSCompartment *origin = js::GetObjectCompartment(obj);
397 JSCompartment *target = js::GetContextCompartment(cx);
398 bool originIsChrome = AccessCheck::isChrome(origin);
399 bool targetIsChrome = AccessCheck::isChrome(target);
400 bool originSubsumesTarget = AccessCheck::subsumesConsideringDomain(origin, target);
401 bool targetSubsumesOrigin = AccessCheck::subsumesConsideringDomain(target, origin);
402 bool sameOrigin = targetSubsumesOrigin && originSubsumesTarget;
403 XrayType xrayType = GetXrayType(obj);
404 bool waiveXrayFlag = flags & WAIVE_XRAY_WRAPPER_FLAG;
406 Wrapper *wrapper;
407 CompartmentPrivate *targetdata = EnsureCompartmentPrivate(target);
409 //
410 // First, handle the special cases.
411 //
413 // If UniversalXPConnect is enabled, this is just some dumb mochitest. Use
414 // a vanilla CCW.
415 if (xpc::IsUniversalXPConnectEnabled(target)) {
416 wrapper = &CrossCompartmentWrapper::singleton;
417 }
419 // If this is a chrome object being exposed to content without Xrays, use
420 // a COW.
421 else if (originIsChrome && !targetIsChrome && xrayType == NotXray) {
422 wrapper = &ChromeObjectWrapper::singleton;
423 }
425 // Normally, a non-xrayable non-waived content object that finds itself in
426 // a privileged scope is wrapped with a CrossCompartmentWrapper, even though
427 // the lack of a waiver _really_ should give it an opaque wrapper. This is
428 // a bit too entrenched to change for content-chrome, but we can at least fix
429 // it for XBL scopes.
430 //
431 // See bug 843829.
432 else if (targetSubsumesOrigin && !originSubsumesTarget &&
433 !waiveXrayFlag && xrayType == NotXray &&
434 IsXBLScope(target))
435 {
436 wrapper = &FilteringWrapper<CrossCompartmentSecurityWrapper, GentlyOpaque>::singleton;
437 }
439 //
440 // Now, handle the regular cases.
441 //
442 // These are wrappers we can compute using a rule-based approach. In order
443 // to do so, we need to compute some parameters.
444 //
445 else {
447 // The wrapper is a security wrapper (protecting the wrappee) if and
448 // only if the target does not subsume the origin.
449 bool securityWrapper = !targetSubsumesOrigin;
451 // Xrays are warranted if either the target or the origin don't trust
452 // each other. This is generally the case, unless the two are same-origin
453 // and the caller has not requested same-origin Xrays.
454 //
455 // Xrays are a bidirectional protection, since it affords clarity to the
456 // caller and privacy to the callee.
457 bool wantXrays = !(sameOrigin && !targetdata->wantXrays);
459 // If Xrays are warranted, the caller may waive them for non-security
460 // wrappers.
461 bool waiveXrays = wantXrays && !securityWrapper && waiveXrayFlag;
463 // We have slightly different behavior for the case when the object
464 // being wrapped is in an XBL scope.
465 bool originIsXBLScope = IsXBLScope(origin);
467 wrapper = SelectWrapper(securityWrapper, wantXrays, xrayType, waiveXrays,
468 originIsXBLScope);
469 }
471 if (!targetSubsumesOrigin) {
472 // Do a belt-and-suspenders check against exposing eval()/Function() to
473 // non-subsuming content.
474 JSFunction *fun = JS_GetObjectFunction(obj);
475 if (fun) {
476 if (JS_IsBuiltinEvalFunction(fun) || JS_IsBuiltinFunctionConstructor(fun)) {
477 JS_ReportError(cx, "Permission denied to expose eval or Function to non-subsuming content");
478 return nullptr;
479 }
480 }
481 }
483 DEBUG_CheckUnwrapSafety(obj, wrapper, origin, target);
485 if (existing)
486 return Wrapper::Renew(cx, existing, obj, wrapper);
488 return Wrapper::New(cx, obj, parent, wrapper);
489 }
491 // Call WaiveXrayAndWrap when you have a JS object that you don't want to be
492 // wrapped in an Xray wrapper. cx->compartment is the compartment that will be
493 // using the returned object. If the object to be wrapped is already in the
494 // correct compartment, then this returns the unwrapped object.
495 bool
496 WrapperFactory::WaiveXrayAndWrap(JSContext *cx, MutableHandleValue vp)
497 {
498 if (vp.isPrimitive())
499 return JS_WrapValue(cx, vp);
501 RootedObject obj(cx, &vp.toObject());
502 if (!WaiveXrayAndWrap(cx, &obj))
503 return false;
505 vp.setObject(*obj);
506 return true;
507 }
509 bool
510 WrapperFactory::WaiveXrayAndWrap(JSContext *cx, MutableHandleObject argObj)
511 {
512 MOZ_ASSERT(argObj);
513 RootedObject obj(cx, js::UncheckedUnwrap(argObj));
514 MOZ_ASSERT(!js::IsInnerObject(obj));
515 if (js::IsObjectInContextCompartment(obj, cx)) {
516 argObj.set(obj);
517 return true;
518 }
520 // Even though waivers have no effect on access by scopes that don't subsume
521 // the underlying object, good defense-in-depth dictates that we should avoid
522 // handing out waivers to callers that can't use them. The transitive waiving
523 // machinery unconditionally calls WaiveXrayAndWrap on return values from
524 // waived functions, even though the return value might be not be same-origin
525 // with the function. So if we find ourselves trying to create a waiver for
526 // |cx|, we should check whether the caller has any business with waivers
527 // to things in |obj|'s compartment.
528 JSCompartment *target = js::GetContextCompartment(cx);
529 JSCompartment *origin = js::GetObjectCompartment(obj);
530 obj = AccessCheck::subsumes(target, origin) ? WaiveXray(cx, obj) : obj;
531 if (!obj)
532 return false;
534 if (!JS_WrapObject(cx, &obj))
535 return false;
536 argObj.set(obj);
537 return true;
538 }
540 bool
541 WrapperFactory::XrayWrapperNotShadowing(JSObject *wrapper, jsid id)
542 {
543 ResolvingId *rid = ResolvingId::getResolvingIdFromWrapper(wrapper);
544 return rid->isXrayShadowing(id);
545 }
547 /*
548 * Calls to JS_TransplantObject* should go through these helpers here so that
549 * waivers get fixed up properly.
550 */
552 static bool
553 FixWaiverAfterTransplant(JSContext *cx, HandleObject oldWaiver, HandleObject newobj)
554 {
555 MOZ_ASSERT(Wrapper::wrapperHandler(oldWaiver) == &XrayWaiver);
556 MOZ_ASSERT(!js::IsCrossCompartmentWrapper(newobj));
558 // Create a waiver in the new compartment. We know there's not one already
559 // because we _just_ transplanted, which means that |newobj| was either
560 // created from scratch, or was previously cross-compartment wrapper (which
561 // should have no waiver). CreateXrayWaiver asserts this.
562 JSObject *newWaiver = WrapperFactory::CreateXrayWaiver(cx, newobj);
563 if (!newWaiver)
564 return false;
566 // Update all the cross-compartment references to oldWaiver to point to
567 // newWaiver.
568 if (!js::RemapAllWrappersForObject(cx, oldWaiver, newWaiver))
569 return false;
571 // There should be no same-compartment references to oldWaiver, and we
572 // just remapped all cross-compartment references. It's dead, so we can
573 // remove it from the map.
574 XPCWrappedNativeScope *scope = GetObjectScope(oldWaiver);
575 JSObject *key = Wrapper::wrappedObject(oldWaiver);
576 MOZ_ASSERT(scope->mWaiverWrapperMap->Find(key));
577 scope->mWaiverWrapperMap->Remove(key);
578 return true;
579 }
581 JSObject *
582 TransplantObject(JSContext *cx, JS::HandleObject origobj, JS::HandleObject target)
583 {
584 RootedObject oldWaiver(cx, WrapperFactory::GetXrayWaiver(origobj));
585 RootedObject newIdentity(cx, JS_TransplantObject(cx, origobj, target));
586 if (!newIdentity || !oldWaiver)
587 return newIdentity;
589 if (!FixWaiverAfterTransplant(cx, oldWaiver, newIdentity))
590 return nullptr;
591 return newIdentity;
592 }
594 nsIGlobalObject *
595 GetNativeForGlobal(JSObject *obj)
596 {
597 MOZ_ASSERT(JS_IsGlobalObject(obj));
598 if (!MaybeGetObjectScope(obj))
599 return nullptr;
601 // Every global needs to hold a native as its private or be a
602 // WebIDL object with an nsISupports DOM object.
603 MOZ_ASSERT((GetObjectClass(obj)->flags & (JSCLASS_PRIVATE_IS_NSISUPPORTS |
604 JSCLASS_HAS_PRIVATE)) ||
605 dom::UnwrapDOMObjectToISupports(obj));
607 nsISupports *native = dom::UnwrapDOMObjectToISupports(obj);
608 if (!native) {
609 native = static_cast<nsISupports *>(js::GetObjectPrivate(obj));
610 MOZ_ASSERT(native);
612 // In some cases (like for windows) it is a wrapped native,
613 // in other cases (sandboxes, backstage passes) it's just
614 // a direct pointer to the native. If it's a wrapped native
615 // let's unwrap it first.
616 if (nsCOMPtr<nsIXPConnectWrappedNative> wn = do_QueryInterface(native)) {
617 native = wn->Native();
618 }
619 }
621 nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(native);
622 MOZ_ASSERT(global, "Native held by global needs to implement nsIGlobalObject!");
624 return global;
625 }
627 }