Merge m-c to inbound
authorRyan VanderMeulen <ryanvm@gmail.com>
Sun, 10 Jun 2012 21:34:50 -0400
changeset 96355 75b67011b798fb0ab754da5ced223dd0d0eb996a
parent 96353 b7fd38dad196e552a71a12f681b668449ddef107 (current diff)
parent 96334 af2a59c2334728db194971a51392b5eb27a70b9d (diff)
child 96356 2d4c140e2f47326f5014f6eab482a1914382cab5
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
milestone16.0a1
Merge m-c to inbound
accessible/src/atk/HTMLTableAccessibleWrap.h
accessible/src/atk/XULListboxAccessibleWrap.h
accessible/src/atk/XULMenuAccessibleWrap.h
accessible/src/atk/XULTreeGridAccessibleWrap.h
accessible/src/generic/Accessible.h
accessible/src/generic/RootAccessible.h
accessible/src/html/HTMLTableAccessible.cpp
accessible/src/html/HTMLTableAccessible.h
accessible/src/mac/HTMLTableAccessibleWrap.h
accessible/src/mac/XULListboxAccessibleWrap.h
accessible/src/mac/XULMenuAccessibleWrap.h
accessible/src/mac/XULTreeGridAccessibleWrap.h
accessible/src/msaa/HTMLTableAccessibleWrap.cpp
accessible/src/msaa/HTMLTableAccessibleWrap.h
accessible/src/msaa/XULListboxAccessibleWrap.cpp
accessible/src/msaa/XULListboxAccessibleWrap.h
accessible/src/msaa/XULMenuAccessibleWrap.cpp
accessible/src/msaa/XULMenuAccessibleWrap.h
accessible/src/msaa/XULTreeGridAccessibleWrap.cpp
accessible/src/msaa/XULTreeGridAccessibleWrap.h
accessible/src/other/HTMLTableAccessibleWrap.h
accessible/src/other/XULMenuAccessibleWrap.h
accessible/src/other/XULTreeGridAccessibleWrap.h
accessible/src/xul/XULAlertAccessible.cpp
accessible/src/xul/XULAlertAccessible.h
accessible/src/xul/XULColorPickerAccessible.cpp
accessible/src/xul/XULColorPickerAccessible.h
accessible/src/xul/XULComboboxAccessible.cpp
accessible/src/xul/XULComboboxAccessible.h
accessible/src/xul/XULElementAccessibles.cpp
accessible/src/xul/XULElementAccessibles.h
accessible/src/xul/XULMenuAccessible.cpp
accessible/src/xul/XULMenuAccessible.h
accessible/src/xul/XULSliderAccessible.cpp
accessible/src/xul/XULSliderAccessible.h
accessible/src/xul/XULTabAccessible.cpp
accessible/src/xul/XULTabAccessible.h
accessible/src/xul/XULTreeAccessible.cpp
accessible/src/xul/XULTreeAccessible.h
accessible/src/xul/XULTreeGridAccessible.cpp
accessible/src/xul/XULTreeGridAccessible.h
caps/src/nsPrincipal.cpp
content/html/content/test/forms/test_meter_element.html
content/html/content/test/forms/test_meter_pseudo-classes.html
dom/base/nsDOMWindowUtils.cpp
dom/browser-element/BrowserElementChild.js
dom/browser-element/BrowserElementParent.js
dom/browser-element/BrowserElementParent.manifest
dom/browser-element/BrowserElementPromptService.jsm
dom/browser-element/mochitest/Makefile.in
dom/browser-element/mochitest/browserElementTestHelpers.js
dom/browser-element/mochitest/browserElement_Alert.js
dom/browser-element/mochitest/browserElement_Close.js
dom/browser-element/mochitest/browserElement_DataURI.js
dom/browser-element/mochitest/browserElement_GetScreenshot.js
dom/browser-element/mochitest/browserElement_Iconchange.js
dom/browser-element/mochitest/browserElement_KeyEvents.js
dom/browser-element/mochitest/browserElement_LoadEvents.js
dom/browser-element/mochitest/browserElement_PromptCheck.js
dom/browser-element/mochitest/browserElement_PromptConfirm.js
dom/browser-element/mochitest/browserElement_SetVisible.js
dom/browser-element/mochitest/browserElement_Titlechange.js
dom/browser-element/mochitest/browserElement_TopBarrier.js
dom/browser-element/mochitest/file_empty.html
dom/browser-element/mochitest/file_focus.html
dom/browser-element/mochitest/test_browserElement_NoAttr.html
dom/browser-element/mochitest/test_browserElement_NoPref.html
dom/browser-element/mochitest/test_browserElement_NoWhitelist.html
dom/browser-element/mochitest/test_browserElement_inproc_Alert.html
dom/browser-element/mochitest/test_browserElement_inproc_Close.html
dom/browser-element/mochitest/test_browserElement_inproc_DataURI.html
dom/browser-element/mochitest/test_browserElement_inproc_GetScreenshot.html
dom/browser-element/mochitest/test_browserElement_inproc_Iconchange.html
dom/browser-element/mochitest/test_browserElement_inproc_KeyEvents.html
dom/browser-element/mochitest/test_browserElement_inproc_LoadEvents.html
dom/browser-element/mochitest/test_browserElement_inproc_PromptCheck.html
dom/browser-element/mochitest/test_browserElement_inproc_PromptConfirm.html
dom/browser-element/mochitest/test_browserElement_inproc_SetVisible.html
dom/browser-element/mochitest/test_browserElement_inproc_Titlechange.html
dom/browser-element/mochitest/test_browserElement_inproc_TopBarrier.html
dom/browser-element/mochitest/test_browserElement_oop_Alert.html
dom/browser-element/mochitest/test_browserElement_oop_Close.html
dom/browser-element/mochitest/test_browserElement_oop_DataURI.html
dom/browser-element/mochitest/test_browserElement_oop_GetScreenshot.html
dom/browser-element/mochitest/test_browserElement_oop_Iconchange.html
dom/browser-element/mochitest/test_browserElement_oop_KeyEvents.html
dom/browser-element/mochitest/test_browserElement_oop_LoadEvents.html
dom/browser-element/mochitest/test_browserElement_oop_PromptCheck.html
dom/browser-element/mochitest/test_browserElement_oop_PromptConfirm.html
dom/browser-element/mochitest/test_browserElement_oop_SetVisible.html
dom/browser-element/mochitest/test_browserElement_oop_Titlechange.html
dom/browser-element/mochitest/test_browserElement_oop_TopBarrier.html
dom/network/interfaces/nsIDOMUSSDReceivedEvent.idl
js/src/jit-test/tests/e4x/bug557168-1.js
js/src/jit-test/tests/e4x/bug557168-2.js
js/src/jit-test/tests/e4x/bug557168-3.js
js/src/jit-test/tests/e4x/bug557168.js
js/src/jit-test/tests/e4x/bug569843.js
js/src/jit-test/tests/e4x/bug574280.js
js/src/jit-test/tests/e4x/bug596502-version.js
js/src/jit-test/tests/e4x/bug605200.js
js/src/jit-test/tests/e4x/bug613151.js
js/src/jit-test/tests/e4x/bug632206.js
js/src/jit-test/tests/e4x/bug651966.js
js/src/jit-test/tests/e4x/bug665812.js
js/src/jit-test/tests/e4x/bug672153.js
js/src/jit-test/tests/e4x/bug700799.js
js/src/jit-test/tests/e4x/bug716713.js
js/src/jit-test/tests/e4x/bug731724.js
js/src/jit-test/tests/e4x/bug731745.js
js/src/jit-test/tests/e4x/bug737251.js
js/src/jit-test/tests/e4x/bug753885-1.js
js/src/jit-test/tests/e4x/bug753885-2.js
js/src/jit-test/tests/e4x/e4x-descendants-with-arguments.js
js/src/jit-test/tests/e4x/testXMLPropertyNames.js
js/src/vm/Debugger.cpp
layout/base/nsCSSRendering.cpp
layout/base/nsPresShell.cpp
layout/generic/Selection.h
layout/generic/nsFontInflationData.cpp
layout/generic/nsFontInflationData.h
layout/generic/nsHTMLReflowState.cpp
mobile/android/base/TabsPanel.java
mobile/android/base/resources/drawable-hdpi/tabs_carat.png
mobile/android/base/resources/drawable-land-hdpi-v14/tabs_carat.png
mobile/android/base/resources/drawable-land-mdpi-v14/tabs_carat.png
mobile/android/base/resources/drawable-land-xhdpi-v14/tabs_carat.png
mobile/android/base/resources/drawable-sw600dp-hdpi/tabs_carat.png
mobile/android/base/resources/drawable-sw600dp-mdpi/tabs_carat.png
mobile/android/base/resources/drawable-sw600dp-xhdpi/tabs_carat.png
mobile/android/base/resources/drawable-xhdpi-v11/tabs_carat.png
mobile/android/base/resources/drawable-xlarge-hdpi/tabs_carat.png
mobile/android/base/resources/drawable-xlarge-mdpi/tabs_carat.png
mobile/android/base/resources/drawable-xlarge-xhdpi/tabs_carat.png
mobile/android/base/resources/drawable/tabs_carat.png
mobile/android/base/resources/drawable/tabs_tray_active_selector.xml
mobile/android/base/resources/drawable/tabs_tray_default_selector.xml
mobile/android/base/resources/layout-sw600dp/gecko_app.xml
mobile/android/base/resources/layout-sw600dp/tabs_panel.xml
mobile/android/base/resources/layout-sw600dp/tabs_row.xml
mobile/android/base/resources/layout-xlarge/gecko_app.xml
mobile/android/base/resources/layout-xlarge/tabs_panel.xml
mobile/android/base/resources/layout-xlarge/tabs_row.xml
mobile/android/base/resources/layout/tabs_panel.xml
toolkit/components/osfile/Makefile.in
toolkit/components/osfile/osfile.jsm
toolkit/components/osfile/tests/mochi/Makefile.in
toolkit/components/osfile/tests/mochi/test_osfile_back.xul
--- a/caps/idl/nsIScriptSecurityManager.idl
+++ b/caps/idl/nsIScriptSecurityManager.idl
@@ -4,17 +4,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsISupports.idl"
 #include "nsIPrincipal.idl"
 #include "nsIXPCSecurityManager.idl"
 interface nsIURI;
 interface nsIChannel;
 
-[scriptable, uuid(cdb27711-492b-4973-938b-de81ac124658)]
+[scriptable, uuid(3708aa92-e2d9-4fd1-9e46-edfa3eb5ebf5)]
 interface nsIScriptSecurityManager : nsIXPCSecurityManager
 {
     ///////////////// Security Checks //////////////////
     /**
      * Checks whether the running script is allowed to access aProperty.
      */
     [noscript] void checkPropertyAccess(in JSContextPtr aJSContext,
                                         in JSObjectPtr aJSObject,
@@ -255,14 +255,37 @@ interface nsIScriptSecurityManager : nsI
      * Same as getSubjectPrincipal(), only faster. cx must *never* be
      * passed null, and it must be the context on the top of the
      * context stack. Does *not* reference count the returned
      * principal.
      */
     [noscript,notxpcom] nsIPrincipal getCxSubjectPrincipal(in JSContextPtr cx);
     [noscript,notxpcom] nsIPrincipal getCxSubjectPrincipalAndFrame(in JSContextPtr cx,
                                                                    out JSStackFramePtr fp);
+
+    /**
+     * If no scripted code is running "above" (or called from) fp, then
+     * instead of looking at cx->globalObject, we will return |principal|.
+     * This function only affects |cx|. If someone pushes another context onto
+     * the context stack, then it supersedes this call.
+     * NOTE: If |fp| is non-null popContextPrincipal must be called before fp
+     * has finished executing.
+     *
+     * @param cx The context to clamp.
+     * @param fp The frame pointer to clamp at. May be 'null'.
+     * @param principal The principal to clamp to.
+     */
+    [noscript] void pushContextPrincipal(in JSContextPtr cx,
+                                         in JSStackFramePtr fp,
+                                         in nsIPrincipal principal);
+
+    /**
+     * Removes a clamp set by pushContextPrincipal from cx. This must be
+     * called in a stack-like fashion (e.g., given two contexts |a| and |b|,
+     * it is not legal to do: push(a) push(b) pop(a)).
+     */
+    [noscript] void popContextPrincipal(in JSContextPtr cx);
 };
 
 %{C++
 #define NS_SCRIPTSECURITYMANAGER_CONTRACTID "@mozilla.org/scriptsecuritymanager;1"
 #define NS_SCRIPTSECURITYMANAGER_CLASSNAME "scriptsecuritymanager"
 %}
--- a/caps/include/nsScriptSecurityManager.h
+++ b/caps/include/nsScriptSecurityManager.h
@@ -398,21 +398,22 @@ private:
     ObjectPrincipalFinder(JSObject *obj);
     
     // Decides, based on CSP, whether or not eval() and stuff can be executed.
     static JSBool
     ContentSecurityPolicyPermitsJSAction(JSContext *cx);
 
     // Returns null if a principal cannot be found; generally callers
     // should error out at that point.
-    static nsIPrincipal* doGetObjectPrincipal(JSObject *obj);
+    static nsIPrincipal*
+    doGetObjectPrincipal(JSObject *obj
 #ifdef DEBUG
-    static nsIPrincipal*
-    old_doGetObjectPrincipal(JSObject *obj, bool aAllowShortCircuit = true);
+                         , bool aAllowShortCircuit = true
 #endif
+                         );
 
     // Returns null if a principal cannot be found.  Note that rv can be NS_OK
     // when this happens -- this means that there was no JS running.
     nsIPrincipal*
     doGetSubjectPrincipal(nsresult* rv);
     
     nsresult
     CheckPropertyAccessImpl(PRUint32 aAction,
@@ -548,28 +549,40 @@ private:
     nsresult
     InitPrincipals(PRUint32 prefCount, const char** prefNames);
 
 #ifdef DEBUG_CAPS_HACKER
     void
     PrintPolicyDB();
 #endif
 
+    struct ContextPrincipal {
+        ContextPrincipal(ContextPrincipal *next, JSContext *cx,
+                         JSStackFrame *fp, nsIPrincipal *principal)
+            : mNext(next), mCx(cx), mFp(fp), mPrincipal(principal) {}
+
+        ContextPrincipal *mNext;
+        JSContext *mCx;
+        JSStackFrame *mFp;
+        nsCOMPtr<nsIPrincipal> mPrincipal;
+    };
+
     // JS strings we need to clean up on shutdown
     static jsid sEnabledID;
 
     inline void
     ScriptSecurityPrefChanged();
 
     nsObjectHashtable* mOriginToPolicyMap;
     DomainPolicy* mDefaultPolicy;
     nsObjectHashtable* mCapabilities;
 
     nsCOMPtr<nsIPrincipal> mSystemPrincipal;
     nsCOMPtr<nsIPrincipal> mSystemCertificate;
+    ContextPrincipal *mContextPrincipals;
     nsInterfaceHashtable<PrincipalKey, nsIPrincipal> mPrincipals;
     bool mPrefInitialized;
     bool mIsJavaScriptEnabled;
     bool mIsWritingPrefs;
     bool mPolicyPrefsChanged;
 
     static bool sStrictFileOriginPolicy;
 
--- a/caps/src/nsScriptSecurityManager.cpp
+++ b/caps/src/nsScriptSecurityManager.cpp
@@ -157,16 +157,54 @@ GetPrincipalDomainOrigin(nsIPrincipal* a
 }
 
 static nsIScriptContext *
 GetScriptContext(JSContext *cx)
 {
     return GetScriptContextFromJSContext(cx);
 }
 
+// Callbacks for the JS engine to use to push/pop context principals.
+static JSBool
+PushPrincipalCallback(JSContext *cx, JSPrincipals *principals)
+{
+    // We should already be in the compartment of the given principal.
+    MOZ_ASSERT(principals ==
+               JS_GetCompartmentPrincipals((js::GetContextCompartment(cx))));
+
+    // Get the security manager.
+    nsIScriptSecurityManager *ssm = XPCWrapper::GetSecurityManager();
+    if (!ssm) {
+        return true;
+    }
+
+    // Push the principal.
+    JSStackFrame *fp = NULL;
+    nsresult rv = ssm->PushContextPrincipal(cx, JS_FrameIterator(cx, &fp),
+                                            nsJSPrincipals::get(principals));
+    if (NS_FAILED(rv)) {
+        JS_ReportOutOfMemory(cx);
+        return false;
+    }
+
+    return true;
+}
+
+static JSBool
+PopPrincipalCallback(JSContext *cx)
+{
+    nsIScriptSecurityManager *ssm = XPCWrapper::GetSecurityManager();
+    if (ssm) {
+        ssm->PopContextPrincipal(cx);
+    }
+
+    return true;
+}
+
+
 inline void SetPendingException(JSContext *cx, const char *aMsg)
 {
     JSAutoRequest ar(cx);
     JS_ReportError(cx, "%s", aMsg);
 }
 
 inline void SetPendingException(JSContext *cx, const PRUnichar *aMsg)
 {
@@ -361,16 +399,44 @@ nsScriptSecurityManager::GetCxSubjectPri
     nsresult rv = NS_ERROR_FAILURE;
     nsIPrincipal *principal = GetPrincipalAndFrame(cx, fp, &rv);
     if (NS_FAILED(rv))
         return nsnull;
 
     return principal;
 }
 
+NS_IMETHODIMP
+nsScriptSecurityManager::PushContextPrincipal(JSContext *cx,
+                                              JSStackFrame *fp,
+                                              nsIPrincipal *principal)
+{
+    NS_ASSERTION(principal, "Must pass a non-null principal");
+
+    ContextPrincipal *cp = new ContextPrincipal(mContextPrincipals, cx, fp,
+                                                principal);
+    if (!cp)
+        return NS_ERROR_OUT_OF_MEMORY;
+
+    mContextPrincipals = cp;
+    return NS_OK;
+}
+
+NS_IMETHODIMP
+nsScriptSecurityManager::PopContextPrincipal(JSContext *cx)
+{
+    NS_ASSERTION(mContextPrincipals->mCx == cx, "Mismatched push/pop");
+
+    ContextPrincipal *next = mContextPrincipals->mNext;
+    delete mContextPrincipals;
+    mContextPrincipals = next;
+
+    return NS_OK;
+}
+
 ////////////////////
 // Policy Storage //
 ////////////////////
 
 // Table of security levels
 static bool
 DeleteCapability(nsHashKey *aKey, void *aData, void* closure)
 {
@@ -2232,29 +2298,62 @@ nsScriptSecurityManager::GetPrincipalAnd
 {
     NS_PRECONDITION(rv, "Null out param");
     //-- If there's no principal on the stack, look at the global object
     //   and return the innermost frame for annotations.
     *rv = NS_OK;
 
     if (cx)
     {
+        JSStackFrame *target = nsnull;
+        nsIPrincipal *targetPrincipal = nsnull;
+        for (ContextPrincipal *cp = mContextPrincipals; cp; cp = cp->mNext)
+        {
+            if (cp->mCx == cx)
+            {
+                target = cp->mFp;
+                targetPrincipal = cp->mPrincipal;
+                break;
+            }
+        }
+
         // Get principals from innermost JavaScript frame.
         JSStackFrame *fp = nsnull; // tell JS_FrameIterator to start at innermost
         for (fp = JS_FrameIterator(cx, &fp); fp; fp = JS_FrameIterator(cx, &fp))
         {
+            if (fp == target)
+                break;
             nsIPrincipal* result = GetFramePrincipal(cx, fp, rv);
             if (result)
             {
                 NS_ASSERTION(NS_SUCCEEDED(*rv), "Weird return");
                 *frameResult = fp;
                 return result;
             }
         }
 
+        // If targetPrincipal is non-null, then it means that someone wants to
+        // clamp the principals on this context to this principal. Note that
+        // fp might not equal target here (fp might be null) because someone
+        // could have set aside the frame chain in the meantime.
+        if (targetPrincipal)
+        {
+            if (fp && fp == target)
+            {
+                *frameResult = fp;
+            }
+            else
+            {
+                JSStackFrame *inner = nsnull;
+                *frameResult = JS_FrameIterator(cx, &inner);
+            }
+
+            return targetPrincipal;
+        }
+
         nsIScriptContextPrincipal* scp =
             GetScriptContextPrincipalFromJSContext(cx);
         if (scp)
         {
             nsIScriptObjectPrincipal* globalData = scp->GetObjectPrincipal();
             if (!globalData)
             {
                 *rv = NS_ERROR_FAILURE;
@@ -2275,67 +2374,47 @@ nsScriptSecurityManager::GetPrincipalAnd
 
     return nsnull;
 }
 
 nsIPrincipal*
 nsScriptSecurityManager::GetSubjectPrincipal(JSContext *cx,
                                              nsresult* rv)
 {
-    *rv = NS_OK;
-    JSCompartment *compartment = js::GetContextCompartment(cx);
-
-    // The context should always be in a compartment, either one it has entered
-    // or the one associated with its global.
-    MOZ_ASSERT(!!compartment);
-
-    JSPrincipals *principals = JS_GetCompartmentPrincipals(compartment);
-    return nsJSPrincipals::get(principals);
+    NS_PRECONDITION(rv, "Null out param");
+    JSStackFrame *fp;
+    return GetPrincipalAndFrame(cx, &fp, rv);
 }
 
 NS_IMETHODIMP
 nsScriptSecurityManager::GetObjectPrincipal(JSContext *aCx, JSObject *aObj,
                                             nsIPrincipal **result)
 {
     *result = doGetObjectPrincipal(aObj);
     if (!*result)
         return NS_ERROR_FAILURE;
     NS_ADDREF(*result);
     return NS_OK;
 }
 
 // static
 nsIPrincipal*
-nsScriptSecurityManager::doGetObjectPrincipal(JSObject *aObj)
-{
-    JSCompartment *compartment = js::GetObjectCompartment(aObj);
-    JSPrincipals *principals = JS_GetCompartmentPrincipals(compartment);
-    nsIPrincipal *principal = nsJSPrincipals::get(principals);
-
-    // We leave the old code in for a little while to make sure that pulling
-    // object principals directly off the compartment always gives an equivalent
-    // result (from a security perspective).
+nsScriptSecurityManager::doGetObjectPrincipal(JSObject *aObj
 #ifdef DEBUG
-    nsIPrincipal *old = old_doGetObjectPrincipal(aObj);
-    MOZ_ASSERT(NS_SUCCEEDED(CheckSameOriginPrincipal(principal, old)));
+                                              , bool aAllowShortCircuit
 #endif
-
-    return principal;
-}
-
-#ifdef DEBUG
-// static
-nsIPrincipal*
-nsScriptSecurityManager::old_doGetObjectPrincipal(JSObject *aObj,
-                                                  bool aAllowShortCircuit)
+                                              )
 {
     NS_ASSERTION(aObj, "Bad call to doGetObjectPrincipal()!");
     nsIPrincipal* result = nsnull;
 
+#ifdef DEBUG
     JSObject* origObj = aObj;
+#endif
+    
     js::Class *jsClass = js::GetObjectClass(aObj);
 
     // A common case seen in this code is that we enter this function
     // with aObj being a Function object, whose parent is a Call
     // object. Neither of those have object principals, so we can skip
     // those objects here before we enter the below loop. That way we
     // avoid wasting time checking properties of their classes etc in
     // the loop.
@@ -2359,41 +2438,48 @@ nsScriptSecurityManager::old_doGetObject
     }
 
     do {
         // Note: jsClass is set before this loop, and also at the
         // *end* of this loop.
         
         if (IS_WRAPPER_CLASS(jsClass)) {
             result = sXPConnect->GetPrincipal(aObj,
-                                              aAllowShortCircuit);
+#ifdef DEBUG
+                                              aAllowShortCircuit
+#else
+                                              true
+#endif
+                                              );
             if (result) {
                 break;
             }
         } else {
             nsISupports *priv;
             if (!(~jsClass->flags & (JSCLASS_HAS_PRIVATE |
                                      JSCLASS_PRIVATE_IS_NSISUPPORTS))) {
                 priv = (nsISupports *) js::GetObjectPrivate(aObj);
             } else if (IsDOMClass(jsClass) &&
                        DOMJSClass::FromJSClass(jsClass)->mDOMObjectIsISupports) {
                 priv = UnwrapDOMObject<nsISupports>(aObj);
             } else {
                 priv = nsnull;
             }
 
+#ifdef DEBUG
             if (aAllowShortCircuit) {
                 nsCOMPtr<nsIXPConnectWrappedNative> xpcWrapper =
                     do_QueryInterface(priv);
 
                 NS_ASSERTION(!xpcWrapper ||
                              !strcmp(jsClass->name, "XPCNativeWrapper"),
                              "Uh, an nsIXPConnectWrappedNative with the "
                              "wrong JSClass or getObjectOps hooks!");
             }
+#endif
 
             nsCOMPtr<nsIScriptObjectPrincipal> objPrin =
                 do_QueryInterface(priv);
 
             if (objPrin) {
                 result = objPrin->GetPrincipal();
 
                 if (result) {
@@ -2405,45 +2491,62 @@ nsScriptSecurityManager::old_doGetObject
         aObj = js::GetObjectParentMaybeScope(aObj);
 
         if (!aObj)
             break;
 
         jsClass = js::GetObjectClass(aObj);
     } while (1);
 
+#ifdef DEBUG
     if (aAllowShortCircuit) {
-        nsIPrincipal *principal = old_doGetObjectPrincipal(origObj, false);
+        nsIPrincipal *principal = doGetObjectPrincipal(origObj, false);
 
         // Because of inner window reuse, we can have objects with one principal
         // living in a scope with a different (but same-origin) principal. So
         // just check same-origin here.
         NS_ASSERTION(NS_SUCCEEDED(CheckSameOriginPrincipal(result, principal)),
                      "Principal mismatch.  Not good");
     }
+#endif
 
     return result;
 }
-#endif /* DEBUG */
 
 ///////////////// Capabilities API /////////////////////
 NS_IMETHODIMP
 nsScriptSecurityManager::IsCapabilityEnabled(const char *capability,
                                              bool *result)
 {
     nsresult rv;
     JSStackFrame *fp = nsnull;
     JSContext *cx = GetCurrentJSContext();
     fp = cx ? JS_FrameIterator(cx, &fp) : nsnull;
 
+    JSStackFrame *target = nsnull;
+    nsIPrincipal *targetPrincipal = nsnull;
+    for (ContextPrincipal *cp = mContextPrincipals; cp; cp = cp->mNext)
+    {
+        if (cp->mCx == cx)
+        {
+            target = cp->mFp;
+            targetPrincipal = cp->mPrincipal;
+            break;
+        }
+    }
+
     if (!fp)
     {
-        // No script code on stack. We don't have enough information and have
-        // to allow execution.
-        *result = true;
+        // No script code on stack. If we had a principal pushed for this
+        // context and fp is null, then we use that principal. Otherwise, we
+        // don't have enough information and have to allow execution.
+
+        *result = (targetPrincipal && !target)
+                  ? (targetPrincipal == mSystemPrincipal)
+                  : true;
 
         return NS_OK;
     }
 
     *result = false;
     nsIPrincipal* previousPrincipal = nsnull;
     do
     {
@@ -2477,17 +2580,17 @@ nsScriptSecurityManager::IsCapabilityEna
         if (NS_FAILED(rv)) return rv;
         if (*result)
             return NS_OK;
 
         // Capabilities do not extend to calls into C/C++ and then back into
         // the JS engine via JS_EvaluateScript or similar APIs.
         if (JS_IsGlobalFrame(cx, fp))
             break;
-    } while ((fp = JS_FrameIterator(cx, &fp)) != nsnull);
+    } while (fp != target && (fp = JS_FrameIterator(cx, &fp)) != nsnull);
 
     if (!previousPrincipal)
     {
         // No principals on the stack, all native code.  Allow
         // execution if the subject principal is the system principal.
 
         return SubjectPrincipalIsSystem(result);
     }
@@ -2961,16 +3064,17 @@ nsScriptSecurityManager::Observe(nsISupp
 
 /////////////////////////////////////////////
 // Constructor, Destructor, Initialization //
 /////////////////////////////////////////////
 nsScriptSecurityManager::nsScriptSecurityManager(void)
     : mOriginToPolicyMap(nsnull),
       mDefaultPolicy(nsnull),
       mCapabilities(nsnull),
+      mContextPrincipals(nsnull),
       mPrefInitialized(false),
       mIsJavaScriptEnabled(false),
       mIsWritingPrefs(false),
       mPolicyPrefsChanged(true)
 {
     MOZ_STATIC_ASSERT(sizeof(intptr_t) == sizeof(void*),
                       "intptr_t and void* have different lengths on this platform. "
                       "This may cause a security failure with the SecurityLevel union.");
@@ -3021,17 +3125,19 @@ nsresult nsScriptSecurityManager::Init()
 
     rv = runtimeService->GetRuntime(&sRuntime);
     NS_ENSURE_SUCCESS(rv, rv);
 
     static const JSSecurityCallbacks securityCallbacks = {
         CheckObjectAccess,
         nsJSPrincipals::Subsume,
         ObjectPrincipalFinder,
-        ContentSecurityPolicyPermitsJSAction
+        ContentSecurityPolicyPermitsJSAction,
+        PushPrincipalCallback,
+        PopPrincipalCallback
     };
 
     MOZ_ASSERT(!JS_GetSecurityCallbacks(sRuntime));
     JS_SetSecurityCallbacks(sRuntime, &securityCallbacks);
     JS_InitDestroyPrincipalsCallback(sRuntime, nsJSPrincipals::Destroy);
 
     JS_SetTrustedPrincipals(sRuntime, system);
 
@@ -3040,16 +3146,17 @@ nsresult nsScriptSecurityManager::Init()
 
 static nsScriptSecurityManager *gScriptSecMan = nsnull;
 
 jsid nsScriptSecurityManager::sEnabledID   = JSID_VOID;
 
 nsScriptSecurityManager::~nsScriptSecurityManager(void)
 {
     Preferences::RemoveObservers(this, kObservedPrefs);
+    NS_ASSERTION(!mContextPrincipals, "Leaking mContextPrincipals");
     delete mOriginToPolicyMap;
     if(mDefaultPolicy)
         mDefaultPolicy->Drop();
     delete mCapabilities;
     gScriptSecMan = nsnull;
 }
 
 void
--- a/dom/base/nsJSEnvironment.cpp
+++ b/dom/base/nsJSEnvironment.cpp
@@ -1193,55 +1193,56 @@ nsJSContext::EvaluateStringWithValue(con
     }
 
     return NS_OK;
   }
 
   xpc_UnmarkGrayObject(aScopeObject);
   nsAutoMicroTask mt;
 
-  // Ignore the principal that was passed in, and just assert that it matches
-  // the one we pull off the global.
-  nsCOMPtr<nsIPrincipal> principal;
-  nsCOMPtr<nsIScriptObjectPrincipal> objPrincipal = do_QueryInterface(GetGlobalObject());
-  if (!objPrincipal)
-    return NS_ERROR_FAILURE;
-  principal = objPrincipal->GetPrincipal();
-  if (!principal)
-    return NS_ERROR_FAILURE;
-#ifdef DEBUG
-  bool equal = false;
-  principal->Equals(aPrincipal, &equal);
-  MOZ_ASSERT(equal);
-  nsIPrincipal *scopeObjectPrincipal =
-    nsJSPrincipals::get(JS_GetCompartmentPrincipals(js::GetObjectCompartment(aScopeObject)));
-  equal = false;
-  principal->Equals(scopeObjectPrincipal, &equal);
-  MOZ_ASSERT(equal);
-#endif
+  // Safety first: get an object representing the script's principals, i.e.,
+  // the entities who signed this script, or the fully-qualified-domain-name
+  // or "codebase" from which it was loaded.
+  nsCOMPtr<nsIPrincipal> principal = aPrincipal;
+  nsresult rv;
+  if (!aPrincipal) {
+    nsIScriptGlobalObject *global = GetGlobalObject();
+    if (!global)
+      return NS_ERROR_FAILURE;
+    nsCOMPtr<nsIScriptObjectPrincipal> objPrincipal =
+      do_QueryInterface(global, &rv);
+    if (NS_FAILED(rv))
+      return NS_ERROR_FAILURE;
+    principal = objPrincipal->GetPrincipal();
+    if (!principal)
+      return NS_ERROR_FAILURE;
+  }
 
   bool ok = false;
 
-  nsresult rv = sSecurityManager->CanExecuteScripts(mContext, principal, &ok);
+  rv = sSecurityManager->CanExecuteScripts(mContext, principal, &ok);
   if (NS_FAILED(rv)) {
     return NS_ERROR_FAILURE;
   }
 
   // Push our JSContext on the current thread's context stack so JS called
   // from native code via XPConnect uses the right context.  Do this whether
   // or not the SecurityManager said "ok", in order to simplify control flow
   // below where we pop before returning.
   nsCOMPtr<nsIJSContextStack> stack =
            do_GetService("@mozilla.org/js/xpc/ContextStack;1", &rv);
   if (NS_FAILED(rv) || NS_FAILED(stack->Push(mContext))) {
     return NS_ERROR_FAILURE;
   }
 
   jsval val;
 
+  rv = sSecurityManager->PushContextPrincipal(mContext, nsnull, principal);
+  NS_ENSURE_SUCCESS(rv, rv);
+
   nsJSContext::TerminationFuncHolder holder(this);
 
   // SecurityManager said "ok", but don't compile if aVersion is unknown.
   // Since the caller is responsible for parsing the version strings, we just
   // check it isn't JSVERSION_UNKNOWN.
   if (ok && ((JSVersion)aVersion) != JSVERSION_UNKNOWN) {
 
     XPCAutoRequest ar(mContext);
@@ -1287,16 +1288,18 @@ nsJSContext::EvaluateStringWithValue(con
     // tricky...
   }
   else {
     if (aIsUndefined) {
       *aIsUndefined = true;
     }
   }
 
+  sSecurityManager->PopContextPrincipal(mContext);
+
   // Pop here, after JS_ValueToString and any other possible evaluation.
   if (NS_FAILED(stack->Pop(nsnull)))
     rv = NS_ERROR_FAILURE;
 
   // ScriptEvaluated needs to come after we pop the stack
   ScriptEvaluated(true);
 
   return rv;
@@ -1392,35 +1395,29 @@ nsJSContext::EvaluateString(const nsAStr
   nsAutoMicroTask mt;
 
   if (!aScopeObject) {
     aScopeObject = JS_GetGlobalObject(mContext);
   }
 
   xpc_UnmarkGrayObject(aScopeObject);
 
-  // Ignore the principal that was passed in, and just assert that it matches
-  // the one we pull off the global.
-  nsCOMPtr<nsIPrincipal> principal;
-  nsCOMPtr<nsIScriptObjectPrincipal> objPrincipal = do_QueryInterface(GetGlobalObject());
-  if (!objPrincipal)
-    return NS_ERROR_FAILURE;
-  principal = objPrincipal->GetPrincipal();
-  if (!principal)
-    return NS_ERROR_FAILURE;
-#ifdef DEBUG
-  bool equal = false;
-  principal->Equals(aPrincipal, &equal);
-  MOZ_ASSERT(equal);
-  nsIPrincipal *scopeObjectPrincipal =
-    nsJSPrincipals::get(JS_GetCompartmentPrincipals(js::GetObjectCompartment(aScopeObject)));
-  equal = false;
-  principal->Equals(scopeObjectPrincipal, &equal);
-  MOZ_ASSERT(equal);
-#endif
+  // Safety first: get an object representing the script's principals, i.e.,
+  // the entities who signed this script, or the fully-qualified-domain-name
+  // or "codebase" from which it was loaded.
+  nsCOMPtr<nsIPrincipal> principal = aPrincipal;
+  if (!aPrincipal) {
+    nsCOMPtr<nsIScriptObjectPrincipal> objPrincipal =
+      do_QueryInterface(GetGlobalObject());
+    if (!objPrincipal)
+      return NS_ERROR_FAILURE;
+    principal = objPrincipal->GetPrincipal();
+    if (!principal)
+      return NS_ERROR_FAILURE;
+  }
 
   bool ok = false;
 
   nsresult rv = sSecurityManager->CanExecuteScripts(mContext, principal, &ok);
   if (NS_FAILED(rv)) {
     return NS_ERROR_FAILURE;
   }
 
@@ -1435,16 +1432,19 @@ nsJSContext::EvaluateString(const nsAStr
   }
 
   // The result of evaluation, used only if there were no errors.  This need
   // not be a GC root currently, provided we run the GC only from the
   // operation callback or from ScriptEvaluated.
   jsval val = JSVAL_VOID;
   jsval* vp = aRetValue ? &val : NULL;
 
+  rv = sSecurityManager->PushContextPrincipal(mContext, nsnull, principal);
+  NS_ENSURE_SUCCESS(rv, rv);
+
   nsJSContext::TerminationFuncHolder holder(this);
 
   ++mExecuteDepth;
 
   // SecurityManager said "ok", but don't compile if aVersion is unknown.
   // Since the caller is responsible for parsing the version strings, we just
   // check it isn't JSVERSION_UNKNOWN.
   if (ok && JSVersion(aVersion) != JSVERSION_UNKNOWN) {
@@ -1486,16 +1486,18 @@ nsJSContext::EvaluateString(const nsAStr
 
     if (aRetValue) {
       aRetValue->Truncate();
     }
   }
 
   --mExecuteDepth;
 
+  sSecurityManager->PopContextPrincipal(mContext);
+
   // Pop here, after JS_ValueToString and any other possible evaluation.
   if (NS_FAILED(stack->Pop(nsnull)))
     rv = NS_ERROR_FAILURE;
 
   // ScriptEvaluated needs to come after we pop the stack
   ScriptEvaluated(true);
 
   return rv;
@@ -1583,16 +1585,25 @@ nsJSContext::ExecuteScript(JSScript* aSc
   // called from JS calls back into JS via XPConnect.
   nsresult rv;
   nsCOMPtr<nsIJSContextStack> stack =
            do_GetService("@mozilla.org/js/xpc/ContextStack;1", &rv);
   if (NS_FAILED(rv) || NS_FAILED(stack->Push(mContext))) {
     return NS_ERROR_FAILURE;
   }
 
+  nsCOMPtr<nsIPrincipal> principal;
+  rv = sSecurityManager->GetObjectPrincipal(mContext,
+                                            JS_GetGlobalFromScript(aScriptObject),
+                                            getter_AddRefs(principal));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  rv = sSecurityManager->PushContextPrincipal(mContext, nsnull, principal);
+  NS_ENSURE_SUCCESS(rv, rv);
+
   nsJSContext::TerminationFuncHolder holder(this);
   XPCAutoRequest ar(mContext);
   ++mExecuteDepth;
 
   // The result of evaluation, used only if there were no errors. This need
   // not be a GC root currently, provided we run the GC only from the
   // operation callback or from ScriptEvaluated.
   jsval val;
@@ -1609,16 +1620,18 @@ nsJSContext::ExecuteScript(JSScript* aSc
 
     if (aRetValue) {
       aRetValue->Truncate();
     }
   }
 
   --mExecuteDepth;
 
+  sSecurityManager->PopContextPrincipal(mContext);
+
   // Pop here, after JS_ValueToString and any other possible evaluation.
   if (NS_FAILED(stack->Pop(nsnull)))
     rv = NS_ERROR_FAILURE;
 
   // ScriptEvaluated needs to come after we pop the stack
   ScriptEvaluated(true);
 
   return rv;
@@ -1849,22 +1862,34 @@ nsJSContext::CallEventHandler(nsISupport
   nsJSContext::TerminationFuncHolder holder(this);
 
   if (NS_SUCCEEDED(rv)) {
     // Convert args to jsvals.
     PRUint32 argc = 0;
     jsval *argv = nsnull;
 
     JSObject *funobj = aHandler;
+    nsCOMPtr<nsIPrincipal> principal;
+    rv = sSecurityManager->GetObjectPrincipal(mContext, funobj,
+                                              getter_AddRefs(principal));
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    JSStackFrame *currentfp = nsnull;
+    rv = sSecurityManager->PushContextPrincipal(mContext,
+                                                JS_FrameIterator(mContext, &currentfp),
+                                                principal);
+    NS_ENSURE_SUCCESS(rv, rv);
+
     jsval funval = OBJECT_TO_JSVAL(funobj);
     JSAutoEnterCompartment ac;
     js::ForceFrame ff(mContext, funobj);
     if (!ac.enter(mContext, funobj) || !ff.enter() ||
         !JS_WrapObject(mContext, &target)) {
       ReportPendingException();
+      sSecurityManager->PopContextPrincipal(mContext);
       return NS_ERROR_FAILURE;
     }
 
     Maybe<nsRootedJSValueArray> tempStorage;
 
     // Use |target| as the scope for wrapping the arguments, since aScope is
     // the safe scope in many cases, which isn't very useful.  Wrapping aTarget
     // was OK because those typically have PreCreate methods that give them the
@@ -1897,16 +1922,18 @@ nsJSContext::CallEventHandler(nsISupport
       rv = nsContentUtils::XPConnect()->JSToVariant(mContext, rval, arv);
     }
 
     // Tell XPConnect about any pending exceptions. This is needed
     // to avoid dropping JS exceptions in case we got here through
     // nested calls through XPConnect.
     if (NS_FAILED(rv))
       ReportPendingException();
+
+    sSecurityManager->PopContextPrincipal(mContext);
   }
 
   pusher.Pop();
 
   // ScriptEvaluated needs to come after we pop the stack
   ScriptEvaluated(true);
 
   return rv;
--- a/dom/bindings/Makefile.in
+++ b/dom/bindings/Makefile.in
@@ -91,26 +91,26 @@ bindinggen_dependencies := \
 	$(INSTALL) $(IFLAGS1) $(webidl_base)/$* .
 
 $(test_webidl_files): %: $(srcdir)/test/%
 	$(INSTALL) $(IFLAGS1) $(srcdir)/test/$* .
 
 $(binding_header_files): %Binding.h: $(bindinggen_dependencies) \
                                      %.webidl \
                                      $(NULL)
-	PYTHONDONTWRITEBYTECODE=1 $(PYTHON_PATH) \
+	PYTHONDONTWRITEBYTECODE=1 $(PYTHON) $(topsrcdir)/config/pythonpath.py \
 	  $(PLY_INCLUDE) -I$(srcdir)/parser \
 	  $(srcdir)/BindingGen.py $(ACCESSOR_OPT) header \
 	  $(srcdir)/Bindings.conf $*Binding \
 	  $*.webidl
 
 $(binding_cpp_files): %Binding.cpp: $(bindinggen_dependencies) \
                                     %.webidl \
                                     $(NULL)
-	PYTHONDONTWRITEBYTECODE=1 $(PYTHON_PATH) \
+	PYTHONDONTWRITEBYTECODE=1 $(PYTHON) $(topsrcdir)/config/pythonpath.py \
 	  $(PLY_INCLUDE) -I$(srcdir)/parser \
 	  $(srcdir)/BindingGen.py $(ACCESSOR_OPT) cpp \
 	  $(srcdir)/Bindings.conf $*Binding \
 	  $*.webidl
 
 $(globalgen_targets): ParserResults.pkl
 
 CACHE_DIR = _cache
@@ -125,17 +125,17 @@ globalgen_dependencies := \
   $(NULL)
 
 $(CACHE_DIR)/.done:
 	$(MKDIR) -p $(CACHE_DIR)
 	@$(TOUCH) $@
 
 ParserResults.pkl: $(globalgen_dependencies) \
                    $(all_webidl_files)
-	PYTHONDONTWRITEBYTECODE=1 $(PYTHON_PATH) \
+	PYTHONDONTWRITEBYTECODE=1 $(PYTHON) $(topsrcdir)/config/pythonpath.py \
     $(PLY_INCLUDE) -I$(srcdir)/parser \
     $(srcdir)/GlobalGen.py $(ACCESSOR_OPT) $(srcdir)/Bindings.conf . \
     --cachedir=$(CACHE_DIR) \
     $(all_webidl_files)
 
 GARBAGE += \
   $(binding_header_files) \
   $(binding_cpp_files) \
--- a/dom/src/json/nsJSON.cpp
+++ b/dom/src/json/nsJSON.cpp
@@ -172,25 +172,42 @@ NS_IMETHODIMP
 nsJSON::EncodeFromJSVal(JS::Value *value, JSContext *cx, nsAString &result)
 {
   result.Truncate();
 
   // Begin a new request
   JSAutoRequest ar(cx);
 
   JSAutoEnterCompartment ac;
+  nsIScriptSecurityManager *ssm = nsnull;
   if (value->isObject()) {
     JSObject *obj = &value->toObject();
     if (!ac.enter(cx, obj)) {
       return NS_ERROR_FAILURE;
     }
+
+    nsCOMPtr<nsIPrincipal> principal;
+    ssm = nsContentUtils::GetSecurityManager();
+    nsresult rv = ssm->GetObjectPrincipal(cx, obj, getter_AddRefs(principal));
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    JSStackFrame *fp = nsnull;
+    rv = ssm->PushContextPrincipal(cx, JS_FrameIterator(cx, &fp), principal);
+    NS_ENSURE_SUCCESS(rv, rv);
   }
 
   nsJSONWriter writer;
-  if (!JS_Stringify(cx, value, NULL, JSVAL_NULL, WriteCallback, &writer)) {
+  JSBool ok = JS_Stringify(cx, value, NULL, JSVAL_NULL,
+                           WriteCallback, &writer);
+
+  if (ssm) {
+    ssm->PopContextPrincipal(cx);
+  }
+
+  if (!ok) {
     return NS_ERROR_XPC_BAD_CONVERT_JS;
   }
 
   NS_ENSURE_TRUE(writer.DidWrite(), NS_ERROR_UNEXPECTED);
   writer.FlushBuffer();
   result.Assign(writer.mOutputString);
   return NS_OK;
 }
--- a/dom/tests/mochitest/whatwg/postMessage_chrome_helper.html
+++ b/dom/tests/mochitest/whatwg/postMessage_chrome_helper.html
@@ -32,17 +32,19 @@
           msg += " wrong-message(" + evt.data + ")";
 
         respond(msg);
       }
     }
     
     function respond(msg)
     {
-      SpecialPowers.wrap(window).parent.postMessage(msg, "*");
+      // ...so get privileges and test that this works with privileges
+      netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+      window.parent.postMessage(msg, "*");
     }
     
     window.addEventListener("message", receiveMessage, false);
   </script>
 </head>
 <body>
 <h1 id="domain">example.org</h1>
 </body>
--- a/dom/tests/mochitest/whatwg/test_postMessage_chrome.html
+++ b/dom/tests/mochitest/whatwg/test_postMessage_chrome.html
@@ -88,16 +88,20 @@ function chromePathIsSet(evt)
 
 /*************
  * RECEIVERS *
  *************/
 
 function receiveContent(evt)
 {
   is(evt.isTrusted, true, "should have sent a trusted event");
+  is(evt.origin, "http://example.org", "content response event has wrong URI");
+  is(evt.source, window.frames.contentDomain,
+     "wrong source for same-domain message!");
+
   finish();
 }
 
 
 /**************
  * TEST SETUP *
  **************/
 
--- a/ipc/testshell/XPCShellEnvironment.cpp
+++ b/ipc/testshell/XPCShellEnvironment.cpp
@@ -875,16 +875,30 @@ FullTrustSecMan::GetCxSubjectPrincipal(J
 NS_IMETHODIMP_(nsIPrincipal *)
 FullTrustSecMan::GetCxSubjectPrincipalAndFrame(JSContext *cx,
                                                JSStackFrame **fp)
 {
     *fp = nsnull;
     return mSystemPrincipal;
 }
 
+NS_IMETHODIMP
+FullTrustSecMan::PushContextPrincipal(JSContext *cx,
+                                      JSStackFrame *fp,
+                                      nsIPrincipal *principal)
+{
+    return NS_OK;
+}
+
+NS_IMETHODIMP
+FullTrustSecMan::PopContextPrincipal(JSContext *cx)
+{
+    return NS_OK;
+}
+
 NS_IMETHODIMP_(nsrefcnt)
 XPCShellDirProvider::AddRef()
 {
     return 2;
 }
 
 NS_IMETHODIMP_(nsrefcnt)
 XPCShellDirProvider::Release()
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -1667,16 +1667,26 @@ typedef JSPrincipals *
 /*
  * Used to check if a CSP instance wants to disable eval() and friends.
  * See js_CheckCSPPermitsJSAction() in jsobj.
  */
 typedef JSBool
 (* JSCSPEvalChecker)(JSContext *cx);
 
 /*
+ * Security callbacks for pushing and popping context principals. These are only
+ * temporarily necessary and will hopefully be gone again in a matter of weeks.
+ */
+typedef JSBool
+(* JSPushContextPrincipalOp)(JSContext *cx, JSPrincipals *principals);
+
+typedef JSBool
+(* JSPopContextPrincipalOp)(JSContext *cx);
+
+/*
  * Callback used to ask the embedding for the cross compartment wrapper handler
  * that implements the desired prolicy for this kind of object in the
  * destination compartment.
  */
 typedef JSObject *
 (* JSWrapObjectCallback)(JSContext *cx, JSObject *obj, JSObject *proto, JSObject *parent,
                          unsigned flags);
 
@@ -4334,16 +4344,18 @@ JS_HoldPrincipals(JSPrincipals *principa
 extern JS_PUBLIC_API(void)
 JS_DropPrincipals(JSRuntime *rt, JSPrincipals *principals);
 
 struct JSSecurityCallbacks {
     JSCheckAccessOp            checkObjectAccess;
     JSSubsumePrincipalsOp      subsumePrincipals;
     JSObjectPrincipalsFinder   findObjectPrincipals;
     JSCSPEvalChecker           contentSecurityPolicyAllows;
+    JSPushContextPrincipalOp   pushContextPrincipal;
+    JSPopContextPrincipalOp    popContextPrincipal;
 };
 
 extern JS_PUBLIC_API(void)
 JS_SetSecurityCallbacks(JSRuntime *rt, const JSSecurityCallbacks *callbacks);
 
 extern JS_PUBLIC_API(const JSSecurityCallbacks *)
 JS_GetSecurityCallbacks(JSRuntime *rt);
 
--- a/js/src/jsclone.cpp
+++ b/js/src/jsclone.cpp
@@ -467,16 +467,47 @@ JSStructuredCloneWriter::startObject(JSO
     if (!objs.append(ObjectValue(*obj)) || !counts.append(count))
         return false;
     checkStack();
 
     /* Write the header for obj. */
     return out.writePair(obj->isArray() ? SCTAG_ARRAY_OBJECT : SCTAG_OBJECT_OBJECT, 0);
 }
 
+class AutoEnterCompartmentAndPushPrincipal : public JSAutoEnterCompartment
+{
+  public:
+    bool enter(JSContext *cx, JSObject *target) {
+        // First, enter the compartment.
+        if (!JSAutoEnterCompartment::enter(cx, target))
+            return false;
+
+        // We only need to push a principal if we changed compartments.
+        if (state != STATE_OTHER_COMPARTMENT)
+            return true;
+
+        // Push.
+        const JSSecurityCallbacks *cb = cx->runtime->securityCallbacks;
+        if (cb->pushContextPrincipal)
+          return cb->pushContextPrincipal(cx, target->principals(cx));
+        return true;
+    };
+
+    ~AutoEnterCompartmentAndPushPrincipal() {
+        // Pop the principal if necessary.
+        if (state == STATE_OTHER_COMPARTMENT) {
+            AutoCompartment *ac = getAutoCompartment();
+            const JSSecurityCallbacks *cb = ac->context->runtime->securityCallbacks;
+            if (cb->popContextPrincipal)
+              cb->popContextPrincipal(ac->context);
+        }
+    };
+};
+
+
 bool
 JSStructuredCloneWriter::startWrite(const Value &v)
 {
     assertSameCompartment(context(), v);
 
     if (v.isString()) {
         return writeString(SCTAG_STRING, v.toString());
     } else if (v.isNumber()) {
@@ -493,17 +524,17 @@ JSStructuredCloneWriter::startWrite(cons
         // The object might be a security wrapper. See if we can clone what's
         // behind it. If we can, unwrap the object.
         obj = UnwrapObjectChecked(context(), obj);
         if (!obj)
             return false;
 
         // If we unwrapped above, we'll need to enter the underlying compartment.
         // Let the AutoEnterCompartment do the right thing for us.
-        JSAutoEnterCompartment ac;
+        AutoEnterCompartmentAndPushPrincipal ac;
         if (!ac.enter(context(), obj))
             return false;
 
         if (obj->isRegExp()) {
             RegExpObject &reobj = obj->asRegExp();
             return out.writePair(SCTAG_REGEXP_OBJECT, reobj.getFlags()) &&
                    writeString(SCTAG_STRING, reobj.getSource());
         } else if (obj->isDate()) {
@@ -538,17 +569,17 @@ JSStructuredCloneWriter::write(const Val
 {
     if (!startWrite(v))
         return false;
 
     while (!counts.empty()) {
         RootedObject obj(context(), &objs.back().toObject());
 
         // The objects in |obj| can live in other compartments.
-        JSAutoEnterCompartment ac;
+        AutoEnterCompartmentAndPushPrincipal ac;
         if (!ac.enter(context(), obj))
             return false;
 
         if (counts.back()) {
             counts.back()--;
             RootedId id(context(), ids.back());
             ids.popBack();
             checkStack();
--- a/js/xpconnect/shell/xpcshell.cpp
+++ b/js/xpconnect/shell/xpcshell.cpp
@@ -1390,16 +1390,30 @@ FullTrustSecMan::CanExecuteScripts(JSCon
 /* [noscript] nsIPrincipal getSubjectPrincipal (); */
 NS_IMETHODIMP
 FullTrustSecMan::GetSubjectPrincipal(nsIPrincipal **_retval)
 {
     NS_IF_ADDREF(*_retval = mSystemPrincipal);
     return *_retval ? NS_OK : NS_ERROR_FAILURE;
 }
 
+/* [noscript] void pushContextPrincipal (in JSContextPtr cx, in JSStackFramePtr fp, in nsIPrincipal principal); */
+NS_IMETHODIMP
+FullTrustSecMan::PushContextPrincipal(JSContext * cx, JSStackFrame * fp, nsIPrincipal *principal)
+{
+    return NS_OK;
+}
+
+/* [noscript] void popContextPrincipal (in JSContextPtr cx); */
+NS_IMETHODIMP
+FullTrustSecMan::PopContextPrincipal(JSContext * cx)
+{
+    return NS_OK;
+}
+
 /* [noscript] nsIPrincipal getSystemPrincipal (); */
 NS_IMETHODIMP
 FullTrustSecMan::GetSystemPrincipal(nsIPrincipal **_retval)
 {
     NS_IF_ADDREF(*_retval = mSystemPrincipal);
     return *_retval ? NS_OK : NS_ERROR_FAILURE;
 }
 
--- a/js/xpconnect/src/XPCWrappedJSClass.cpp
+++ b/js/xpconnect/src/XPCWrappedJSClass.cpp
@@ -1111,16 +1111,27 @@ nsXPCWrappedJSClass::CheckForException(X
         // see if JS code signaled failure result without throwing exception
         if (NS_FAILED(pending_result)) {
             return pending_result;
         }
     }
     return NS_ERROR_FAILURE;
 }
 
+class ContextPrincipalGuard
+{
+    nsIScriptSecurityManager *ssm;
+    XPCCallContext &ccx;
+  public:
+    ContextPrincipalGuard(XPCCallContext &ccx)
+      : ssm(nsnull), ccx(ccx) {}
+    void principalPushed(nsIScriptSecurityManager *ssm) { this->ssm = ssm; }
+    ~ContextPrincipalGuard() { if (ssm) ssm->PopContextPrincipal(ccx); }
+};
+
 NS_IMETHODIMP
 nsXPCWrappedJSClass::CallMethod(nsXPCWrappedJS* wrapper, uint16_t methodIndex,
                                 const XPTMethodDescriptor* info,
                                 nsXPTCMiniVariant* nativeParams)
 {
     jsval* sp = nsnull;
     jsval* argv = nsnull;
     uint8_t i;
@@ -1154,29 +1165,52 @@ nsXPCWrappedJSClass::CallMethod(nsXPCWra
     JSAutoEnterCompartment ac;
     if (!ac.enter(cx, obj))
         return NS_ERROR_FAILURE;
 
     ccx.SetScopeForNewJSObjects(obj);
 
     JS::AutoValueVector args(cx);
     AutoScriptEvaluate scriptEval(cx);
+    ContextPrincipalGuard principalGuard(ccx);
 
     // XXX ASSUMES that retval is last arg. The xpidl compiler ensures this.
     uint8_t paramCount = info->num_args;
     uint8_t argc = paramCount -
         (paramCount && XPT_PD_IS_RETVAL(info->params[paramCount-1].flags) ? 1 : 0);
 
     if (!scriptEval.StartEvaluating(obj, xpcWrappedJSErrorReporter))
         goto pre_call_clean_up;
 
     xpcc->SetPendingResult(pending_result);
     xpcc->SetException(nsnull);
     ccx.GetThreadData()->SetException(nsnull);
 
+    if (XPCPerThreadData::IsMainThread(ccx)) {
+        // TODO Remove me in favor of security wrappers.
+        nsIScriptSecurityManager *ssm = XPCWrapper::GetSecurityManager();
+        if (ssm) {
+            nsIPrincipal *objPrincipal =
+                xpc::AccessCheck::getPrincipal(js::GetObjectCompartment(obj));
+            if (objPrincipal) {
+                JSStackFrame* fp = nsnull;
+                nsresult rv =
+                    ssm->PushContextPrincipal(ccx, JS_FrameIterator(ccx, &fp),
+                                              objPrincipal);
+                if (NS_FAILED(rv)) {
+                    JS_ReportOutOfMemory(ccx);
+                    retval = NS_ERROR_OUT_OF_MEMORY;
+                    goto pre_call_clean_up;
+                }
+
+                principalGuard.principalPushed(ssm);
+            }
+        }
+    }
+
     // We use js_Invoke so that the gcthings we use as args will be rooted by
     // the engine as we do conversions and prepare to do the function call.
 
     // setup stack
 
     // if this isn't a function call then we don't need to push extra stuff
     if (!(XPT_MD_IS_SETTER(info->flags) || XPT_MD_IS_GETTER(info->flags))) {
         // We get fval before allocating the stack to avoid gc badness that can
--- a/js/xpconnect/wrappers/CrossOriginWrapper.cpp
+++ b/js/xpconnect/wrappers/CrossOriginWrapper.cpp
@@ -10,17 +10,25 @@
 #include "XPCWrapper.h"
 
 #include "CrossOriginWrapper.h"
 #include "AccessCheck.h"
 #include "WrapperFactory.h"
 
 namespace xpc {
 
-CrossOriginWrapper::CrossOriginWrapper(unsigned flags) : js::CrossCompartmentWrapper(flags)
+NoWaiverWrapper::NoWaiverWrapper(unsigned flags) : js::CrossCompartmentWrapper(flags)
+{
+}
+
+NoWaiverWrapper::~NoWaiverWrapper()
+{
+}
+
+CrossOriginWrapper::CrossOriginWrapper(unsigned flags) : NoWaiverWrapper(flags)
 {
 }
 
 CrossOriginWrapper::~CrossOriginWrapper()
 {
 }
 
 bool
@@ -57,9 +65,41 @@ CrossOriginWrapper::call(JSContext *cx, 
 bool
 CrossOriginWrapper::construct(JSContext *cx, JSObject *wrapper,
                               unsigned argc, js::Value *argv, js::Value *rval)
 {
     return CrossCompartmentWrapper::construct(cx, wrapper, argc, argv, rval) &&
            WrapperFactory::WaiveXrayAndWrap(cx, rval);
 }
 
+bool
+NoWaiverWrapper::enter(JSContext *cx, JSObject *wrapper, jsid id, Action act, bool *bp)
+{
+    *bp = true; // always allowed
+    nsIScriptSecurityManager *ssm = XPCWrapper::GetSecurityManager();
+    if (!ssm) {
+        return true;
+    }
+
+    // Note: By the time enter is called here, CrossCompartmentWrapper has
+    // already pushed the fake stack frame onto cx. Because of this, the frame
+    // that we're clamping is the one that we want (the one in our compartment).
+    JSStackFrame *fp = NULL;
+    nsIPrincipal *principal = GetCompartmentPrincipal(js::GetObjectCompartment(wrappedObject(wrapper)));
+    nsresult rv = ssm->PushContextPrincipal(cx, JS_FrameIterator(cx, &fp), principal);
+    if (NS_FAILED(rv)) {
+        NS_WARNING("Not allowing call because we're out of memory");
+        JS_ReportOutOfMemory(cx);
+        return false;
+    }
+    return true;
 }
+
+void
+NoWaiverWrapper::leave(JSContext *cx, JSObject *wrapper)
+{
+    nsIScriptSecurityManager *ssm = XPCWrapper::GetSecurityManager();
+    if (ssm) {
+        ssm->PopContextPrincipal(cx);
+    }
+}
+
+}
--- a/js/xpconnect/wrappers/CrossOriginWrapper.h
+++ b/js/xpconnect/wrappers/CrossOriginWrapper.h
@@ -10,17 +10,28 @@
 
 #include "mozilla/Attributes.h"
 
 #include "jsapi.h"
 #include "jswrapper.h"
 
 namespace xpc {
 
-class CrossOriginWrapper : public js::CrossCompartmentWrapper {
+class NoWaiverWrapper : public js::CrossCompartmentWrapper {
+  public:
+    NoWaiverWrapper(unsigned flags);
+    virtual ~NoWaiverWrapper();
+
+    virtual bool enter(JSContext *cx, JSObject *wrapper, jsid id, Action act, bool *bp) MOZ_OVERRIDE;
+    virtual void leave(JSContext *cx, JSObject *wrapper) MOZ_OVERRIDE;
+
+    static NoWaiverWrapper singleton;
+};
+
+class CrossOriginWrapper : public NoWaiverWrapper {
   public:
     CrossOriginWrapper(unsigned flags);
     virtual ~CrossOriginWrapper();
 
     virtual bool getPropertyDescriptor(JSContext *cx, JSObject *wrapper, jsid id,
                                        bool set, js::PropertyDescriptor *desc) MOZ_OVERRIDE;
     virtual bool getOwnPropertyDescriptor(JSContext *cx, JSObject *wrapper, jsid id,
                                           bool set, js::PropertyDescriptor *desc) MOZ_OVERRIDE;
--- a/js/xpconnect/wrappers/WrapperFactory.cpp
+++ b/js/xpconnect/wrappers/WrapperFactory.cpp
@@ -26,16 +26,23 @@ namespace xpc {
 // .wrappedJSObject, we want it to cross the membrane into the
 // chrome compartment without automatically being wrapped into an
 // X-ray wrapper. We achieve this by wrapping it into a special
 // transparent wrapper in the origin (non-chrome) compartment. When
 // an object with that special wrapper applied crosses into chrome,
 // we know to not apply an X-ray wrapper.
 Wrapper WaiveXrayWrapperWrapper(WrapperFactory::WAIVE_XRAY_WRAPPER_FLAG);
 
+// Objects that haven't been explicitly waived, but have been exposed
+// to chrome don't want a CrossOriginWrapper, since that deeply-waives
+// but need the transparent behavior of a CrossOriginWrapper. The
+// NoWaiverWrapper is like a CrossOriginWrapper that can also hand out
+// XrayWrappers as return values.
+NoWaiverWrapper NoWaiverWrapper::singleton(0);
+
 // When objects for which we waived the X-ray wrapper cross into
 // chrome, we wrap them into a special cross-compartment wrapper
 // that transitively extends the waiver to all properties we get
 // off it.
 CrossOriginWrapper CrossOriginWrapper::singleton(0);
 
 static JSObject *
 GetCurrentOuter(JSContext *cx, JSObject *obj)
@@ -329,17 +336,17 @@ WrapperFactory::Rewrap(JSContext *cx, JS
                     wrapper = &XrayDOM::singleton;
                 } else if (type == XrayForDOMProxyObject) {
                     wrapper = &XrayProxy::singleton;
                 } else if (type == XrayForWrappedNative) {
                     typedef XrayWrapper<CrossCompartmentWrapper> Xray;
                     usingXray = true;
                     wrapper = &Xray::singleton;
                 } else {
-                    wrapper = &CrossCompartmentWrapper::singleton;
+                    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");