Fixing bug 504862. Sanitize modal dialog argument handling. r=mrbkap@gmail.com, sr=bzbarsky@mit.edu
authorJohnny Stenback <jst@mozilla.com>
Tue, 06 Oct 2009 17:09:16 -0700
changeset 33525 526f516cbd4669c288eb0c4dc24ac4b98bc552e7
parent 33524 052d562cc791e2b6591ac9d432c6acddea632cb4
child 33526 d96ffc8c27498f2a986a048b1b9d43cd612ce167
push idunknown
push userunknown
push dateunknown
reviewersmrbkap, bzbarsky
bugs504862
milestone1.9.3a1pre
Fixing bug 504862. Sanitize modal dialog argument handling. r=mrbkap@gmail.com, sr=bzbarsky@mit.edu
content/xbl/src/nsXBLDocumentInfo.cpp
content/xul/document/src/nsXULPrototypeDocument.cpp
dom/base/nsDOMClassInfo.cpp
dom/base/nsDOMClassInfo.h
dom/base/nsGlobalWindow.cpp
dom/base/nsGlobalWindow.h
dom/base/nsIScriptGlobalObject.h
dom/base/nsPIDOMWindow.h
dom/tests/mochitest/bugs/Makefile.in
embedding/components/windowwatcher/src/nsWindowWatcher.cpp
--- a/content/xbl/src/nsXBLDocumentInfo.cpp
+++ b/content/xbl/src/nsXBLDocumentInfo.cpp
@@ -71,17 +71,16 @@ public:
   // nsIScriptGlobalObject methods
   virtual nsresult EnsureScriptEnvironment(PRUint32 aLangID);
   virtual nsresult SetScriptContext(PRUint32 lang_id, nsIScriptContext *aContext);
 
   virtual nsIScriptContext *GetContext();
   virtual JSObject *GetGlobalJSObject();
   virtual void OnFinalize(PRUint32 aLangID, void *aScriptGlobal);
   virtual void SetScriptsEnabled(PRBool aEnabled, PRBool aFireTimeouts);
-  virtual nsresult SetNewArguments(nsIArray *aArguments);
 
   // nsIScriptObjectPrincipal methods
   virtual nsIPrincipal* GetPrincipal();
 
   static JSBool doCheckAccess(JSContext *cx, JSObject *obj, jsval id,
                               PRUint32 accessType);
 
   NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsXBLDocGlobalObject,
@@ -388,23 +387,16 @@ nsXBLDocGlobalObject::OnFinalize(PRUint3
 }
 
 void
 nsXBLDocGlobalObject::SetScriptsEnabled(PRBool aEnabled, PRBool aFireTimeouts)
 {
     // We don't care...
 }
 
-nsresult
-nsXBLDocGlobalObject::SetNewArguments(nsIArray *aArguments)
-{
-  NS_NOTREACHED("waaah!");
-  return NS_ERROR_UNEXPECTED;
-}
-
 //----------------------------------------------------------------------
 //
 // nsIScriptObjectPrincipal methods
 //
 
 nsIPrincipal*
 nsXBLDocGlobalObject::GetPrincipal()
 {
--- a/content/xul/document/src/nsXULPrototypeDocument.cpp
+++ b/content/xul/document/src/nsXULPrototypeDocument.cpp
@@ -76,17 +76,16 @@ public:
     nsXULPDGlobalObject(nsXULPrototypeDocument* owner);
 
     // nsISupports interface
     NS_DECL_CYCLE_COLLECTING_ISUPPORTS
 
     // nsIScriptGlobalObject methods
     virtual void OnFinalize(PRUint32 aLangID, void *aGlobal);
     virtual void SetScriptsEnabled(PRBool aEnabled, PRBool aFireTimeouts);
-    virtual nsresult SetNewArguments(nsIArray *aArguments);
 
     virtual void *GetScriptGlobal(PRUint32 lang);
     virtual nsresult EnsureScriptEnvironment(PRUint32 aLangID);
 
     virtual nsIScriptContext *GetScriptContext(PRUint32 lang);
     virtual nsresult SetScriptContext(PRUint32 language, nsIScriptContext *ctx);
 
     // nsIScriptObjectPrincipal methods
@@ -804,23 +803,16 @@ nsXULPDGlobalObject::OnFinalize(PRUint32
 }
 
 void
 nsXULPDGlobalObject::SetScriptsEnabled(PRBool aEnabled, PRBool aFireTimeouts)
 {
     // We don't care...
 }
 
-nsresult
-nsXULPDGlobalObject::SetNewArguments(nsIArray *aArguments)
-{
-    NS_NOTREACHED("waaah!");
-    return NS_ERROR_UNEXPECTED;
-}
-
 //----------------------------------------------------------------------
 //
 // nsIScriptObjectPrincipal methods
 //
 
 nsIPrincipal*
 nsXULPDGlobalObject::GetPrincipal()
 {
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -1409,16 +1409,17 @@ jsval nsDOMClassInfo::sLocation_id      
 jsval nsDOMClassInfo::sConstructor_id     = JSVAL_VOID;
 jsval nsDOMClassInfo::s_content_id        = JSVAL_VOID;
 jsval nsDOMClassInfo::sContent_id         = JSVAL_VOID;
 jsval nsDOMClassInfo::sMenubar_id         = JSVAL_VOID;
 jsval nsDOMClassInfo::sToolbar_id         = JSVAL_VOID;
 jsval nsDOMClassInfo::sLocationbar_id     = JSVAL_VOID;
 jsval nsDOMClassInfo::sPersonalbar_id     = JSVAL_VOID;
 jsval nsDOMClassInfo::sStatusbar_id       = JSVAL_VOID;
+jsval nsDOMClassInfo::sDialogArguments_id = JSVAL_VOID;
 jsval nsDOMClassInfo::sDirectories_id     = JSVAL_VOID;
 jsval nsDOMClassInfo::sControllers_id     = JSVAL_VOID;
 jsval nsDOMClassInfo::sLength_id          = JSVAL_VOID;
 jsval nsDOMClassInfo::sInnerHeight_id     = JSVAL_VOID;
 jsval nsDOMClassInfo::sInnerWidth_id      = JSVAL_VOID;
 jsval nsDOMClassInfo::sOuterHeight_id     = JSVAL_VOID;
 jsval nsDOMClassInfo::sOuterWidth_id      = JSVAL_VOID;
 jsval nsDOMClassInfo::sScreenX_id         = JSVAL_VOID;
@@ -1604,16 +1605,17 @@ nsDOMClassInfo::DefineStaticJSVals(JSCon
   SET_JSVAL_TO_STRING(sConstructor_id,     cx, "constructor");
   SET_JSVAL_TO_STRING(s_content_id,        cx, "_content");
   SET_JSVAL_TO_STRING(sContent_id,         cx, "content");
   SET_JSVAL_TO_STRING(sMenubar_id,         cx, "menubar");
   SET_JSVAL_TO_STRING(sToolbar_id,         cx, "toolbar");
   SET_JSVAL_TO_STRING(sLocationbar_id,     cx, "locationbar");
   SET_JSVAL_TO_STRING(sPersonalbar_id,     cx, "personalbar");
   SET_JSVAL_TO_STRING(sStatusbar_id,       cx, "statusbar");
+  SET_JSVAL_TO_STRING(sDialogArguments_id, cx, "dialogArguments");
   SET_JSVAL_TO_STRING(sDirectories_id,     cx, "directories");
   SET_JSVAL_TO_STRING(sControllers_id,     cx, "controllers");
   SET_JSVAL_TO_STRING(sLength_id,          cx, "length");
   SET_JSVAL_TO_STRING(sInnerHeight_id,     cx, "innerHeight");
   SET_JSVAL_TO_STRING(sInnerWidth_id,      cx, "innerWidth");
   SET_JSVAL_TO_STRING(sOuterHeight_id,     cx, "outerHeight");
   SET_JSVAL_TO_STRING(sOuterWidth_id,      cx, "outerWidth");
   SET_JSVAL_TO_STRING(sScreenX_id,         cx, "screenX");
@@ -4449,16 +4451,17 @@ nsDOMClassInfo::ShutDown()
   sConstructor_id     = JSVAL_VOID;
   s_content_id        = JSVAL_VOID;
   sContent_id         = JSVAL_VOID;
   sMenubar_id         = JSVAL_VOID;
   sToolbar_id         = JSVAL_VOID;
   sLocationbar_id     = JSVAL_VOID;
   sPersonalbar_id     = JSVAL_VOID;
   sStatusbar_id       = JSVAL_VOID;
+  sDialogArguments_id = JSVAL_VOID;
   sDirectories_id     = JSVAL_VOID;
   sControllers_id     = JSVAL_VOID;
   sLength_id          = JSVAL_VOID;
   sInnerHeight_id     = JSVAL_VOID;
   sInnerWidth_id      = JSVAL_VOID;
   sOuterHeight_id     = JSVAL_VOID;
   sOuterWidth_id      = JSVAL_VOID;
   sScreenX_id         = JSVAL_VOID;
@@ -6682,34 +6685,51 @@ nsWindowSH::NewResolve(nsIXPConnectWrapp
         }
 
         if (hasProp) {
           *objp = obj;
 
           return NS_OK;
         }
       }
+    } else if (id == sDialogArguments_id &&
+               mData == &sClassInfoData[eDOMClassInfo_ModalContentWindow_id]) {
+      nsCOMPtr<nsIArray> args;
+      ((nsGlobalModalWindow *)win)->GetDialogArguments(getter_AddRefs(args));
+
+      nsIScriptContext *script_cx = win->GetContext();
+      if (script_cx) {
+        JSAutoSuspendRequest asr(cx);
+
+        // Make nsJSContext::SetProperty()'s magic argument array
+        // handling happen.
+        rv = script_cx->SetProperty(obj, "dialogArguments", args);
+        NS_ENSURE_SUCCESS(rv, rv);
+
+        *objp = obj;
+      }
+
+      return NS_OK;
     }
   }
 
   JSObject *oldobj = *objp;
   rv = nsEventReceiverSH::NewResolve(wrapper, cx, obj, id, flags, objp,
                                      _retval);
 
   if (NS_FAILED(rv) || *objp != oldobj) {
     // Something went wrong, or the property got resolved. Return.
     return rv;
   }
 
   // Make a fast expando if we're assigning to (not declaring or
   // binding a name) a new undefined property that's not already
   // defined on our prototype chain. This way we can access this
   // expando w/o ever getting back into XPConnect.
-  if ((flags & JSRESOLVE_ASSIGNING) &&
-      !(flags & JSRESOLVE_WITH) &&
+  if ((flags & JSRESOLVE_ASSIGNING) && !(flags & JSRESOLVE_WITH) &&
       win->IsInnerWindow()) {
     JSObject *realObj;
     wrapper->GetJSObject(&realObj);
 
     if (obj == realObj) {
       JSObject *proto = STOBJ_GET_PROTO(obj);
       if (proto) {
         jsid interned_id;
@@ -9600,17 +9620,20 @@ nsHTMLPluginObjElementSH::PreCreate(nsIS
   return rv == NS_SUCCESS_ALLOW_SLIM_WRAPPERS ? NS_OK : rv;
 }
 
 NS_IMETHODIMP
 nsHTMLPluginObjElementSH::PostCreate(nsIXPConnectWrappedNative *wrapper,
                                      JSContext *cx, JSObject *obj)
 {
   if (nsContentUtils::IsSafeToRunScript()) {
-    nsresult rv = SetupProtoChain(wrapper, cx, obj);
+#ifdef DEBUG
+    nsresult rv =
+#endif
+      SetupProtoChain(wrapper, cx, obj);
 
     // If SetupProtoChain failed then we're in real trouble. We're about to fail
     // PostCreate but it's more than likely that we handed our (now invalid)
     // wrapper to someone already. Bug 429442 is an example of the kind of crash
     // that can result from such a situation. We'll return NS_OK for the time
     // being and hope for the best.
     NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "SetupProtoChain failed!");
     return NS_OK;
--- a/dom/base/nsDOMClassInfo.h
+++ b/dom/base/nsDOMClassInfo.h
@@ -282,16 +282,17 @@ protected:
   static jsval sConstructor_id;
   static jsval s_content_id;
   static jsval sContent_id;
   static jsval sMenubar_id;
   static jsval sToolbar_id;
   static jsval sLocationbar_id;
   static jsval sPersonalbar_id;
   static jsval sStatusbar_id;
+  static jsval sDialogArguments_id;
   static jsval sDirectories_id;
   static jsval sControllers_id;
   static jsval sLength_id;
   static jsval sInnerHeight_id;
   static jsval sInnerWidth_id;
   static jsval sOuterHeight_id;
   static jsval sOuterWidth_id;
   static jsval sScreenX_id;
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -891,16 +891,17 @@ nsGlobalWindow::CleanUp()
   }
 
   PRUint32 scriptIndex;
   NS_STID_FOR_INDEX(scriptIndex) {
     mInnerWindowHolders[scriptIndex] = nsnull;
   }
   mArguments = nsnull;
   mArgumentsLast = nsnull;
+  mArgumentsOrigin = nsnull;
 
   CleanupCachedXBLHandlers(this);
 
 #ifdef DEBUG
   nsCycleCollector_DEBUG_shouldBeFreed(static_cast<nsIScriptGlobalObject*>(this));
 #endif
 }
 
@@ -1190,17 +1191,17 @@ nsGlobalWindow::SetScriptContext(PRUint3
       aScriptContext->SetGCOnDestruction(PR_FALSE);
     }
 
     aScriptContext->DidInitializeContext();
     script_glob = aScriptContext->GetNativeGlobal();
     NS_ASSERTION(script_glob, "GetNativeGlobal returned NULL!");
   }
   // for now, keep mContext real.
-  if (lang_id==nsIProgrammingLanguage::JAVASCRIPT) {
+  if (lang_id == nsIProgrammingLanguage::JAVASCRIPT) {
     mContext = aScriptContext;
     mJSObject = (JSObject *)script_glob;
   }
   mScriptContexts[lang_ndx] = aScriptContext;
   mScriptGlobals[lang_ndx] = script_glob;
   return NS_OK;
 }
 
@@ -2030,18 +2031,22 @@ nsGlobalWindow::SetNewDocument(nsIDocume
                                              navigator,
                                              getter_AddRefs(navigatorHolder));
             }
           }
         }
       }
 
       if (mArguments) {
-        newInnerWindow->SetNewArguments(mArguments);
+        newInnerWindow->DefineArgumentsProperty(mArguments);
+        newInnerWindow->mArguments = mArguments;
+        newInnerWindow->mArgumentsOrigin = mArgumentsOrigin;
+
         mArguments = nsnull;
+        mArgumentsOrigin = nsnull;
       }
 
       // Give the new inner window our chrome event handler (since it
       // doesn't have one).
       newInnerWindow->mChromeEventHandler = mChromeEventHandler;
     }
 
     NS_STID_FOR_ID(st_id) {
@@ -2115,19 +2120,20 @@ nsGlobalWindow::SetDocShell(nsIDocShell*
     }
 
     ClearControllers();
 
     mChromeEventHandler = nsnull; // force release now
 
     if (mArguments) { 
       // We got no new document after someone called
-      // SetNewArguments(), drop our reference to the arguments.
+      // SetArguments(), drop our reference to the arguments.
       mArguments = nsnull;
-      // xxxmarkh - should we also drop mArgumentsLast?
+      mArgumentsLast = nsnull;
+      mArgumentsOrigin = nsnull;
     }
 
     PRUint32 st_ndx;
 
     // Drop holders and tell each context to cleanup and release them now.
     NS_ASSERTION(mContext == mScriptContexts[NS_STID_INDEX(nsIProgrammingLanguage::JAVASCRIPT)],
                  "Contexts confused");
     NS_STID_FOR_INDEX(st_ndx) {
@@ -2370,51 +2376,72 @@ nsGlobalWindow::SetScriptsEnabled(PRBool
     // Scripts are enabled (again?) on this context, run timeouts that
     // fired on this context while scripts were disabled.
 
     RunTimeout(nsnull);
   }
 }
 
 nsresult
-nsGlobalWindow::SetNewArguments(nsIArray *aArguments)
-{
-  FORWARD_TO_OUTER(SetNewArguments, (aArguments), NS_ERROR_NOT_INITIALIZED);
-
-  JSContext *cx;
-  NS_ENSURE_TRUE(aArguments && mContext &&
-                 (cx = (JSContext *)mContext->GetNativeContext()),
-                 NS_ERROR_NOT_INITIALIZED);
-
-  // Note that currentInner may be non-null if someone's doing a
-  // window.open with an existing window name.
-  nsGlobalWindow *currentInner = GetCurrentInnerWindowInternal();
-  
-  nsresult rv;
-
-  if (currentInner) {
-    PRUint32 langID;
-    NS_STID_FOR_ID(langID) {
-      void *glob = currentInner->GetScriptGlobal(langID);
-      nsIScriptContext *ctx = GetScriptContext(langID);
-      if (glob && ctx) {
-        if (mIsModalContentWindow) {
-          rv = ctx->SetProperty(glob, "dialogArguments", aArguments);
-        } else {
-          rv = ctx->SetProperty(glob, "arguments", aArguments);
-        }
-        NS_ENSURE_SUCCESS(rv, rv);
-      }
-    }
-  }
+nsGlobalWindow::SetArguments(nsIArray *aArguments, nsIPrincipal *aOrigin)
+{
+  FORWARD_TO_OUTER(SetArguments, (aArguments, aOrigin),
+                   NS_ERROR_NOT_INITIALIZED);
 
   // Hold on to the arguments so that we can re-set them once the next
   // document is loaded.
   mArguments = aArguments;
-  mArgumentsLast = aArguments;
+  mArgumentsOrigin = aOrigin;
+
+  nsGlobalWindow *currentInner = GetCurrentInnerWindowInternal();
+
+  if (!mIsModalContentWindow) {
+    mArgumentsLast = aArguments;
+  } else if (currentInner) {
+    // SetArguments() is being called on a modal content window that
+    // already has an inner window. This can happen when loading
+    // javascript: URIs as modal content dialogs. In this case, we'll
+    // set up the dialog window, both inner and outer, before we call
+    // SetArguments() on the window, so to deal with that, make sure
+    // here that the arguments are propagated to the inner window.
+
+    currentInner->mArguments = aArguments;
+    currentInner->mArgumentsOrigin = aOrigin;
+  }
+
+  return currentInner ?
+    currentInner->DefineArgumentsProperty(aArguments) : NS_OK;
+}
+
+nsresult
+nsGlobalWindow::DefineArgumentsProperty(nsIArray *aArguments)
+{
+  JSContext *cx;
+  nsIScriptContext *ctx = GetOuterWindowInternal()->mContext;
+  NS_ENSURE_TRUE(aArguments && ctx &&
+                 (cx = (JSContext *)ctx->GetNativeContext()),
+                 NS_ERROR_NOT_INITIALIZED);
+
+  if (mIsModalContentWindow) {
+    // Modal content windows don't have an "arguments" property, they
+    // have a "dialogArguments" property which is handled
+    // separately. See nsWindowSH::NewResolve().
+
+    return NS_OK;
+  }
+
+  PRUint32 langID;
+  NS_STID_FOR_ID(langID) {
+    void *glob = GetScriptGlobal(langID);
+    ctx = GetScriptContext(langID);
+    if (glob && ctx) {
+      nsresult rv = ctx->SetProperty(glob, "arguments", aArguments);
+      NS_ENSURE_SUCCESS(rv, rv);
+    }
+  }
 
   return NS_OK;
 }
 
 //*****************************************************************************
 // nsGlobalWindow::nsIScriptObjectPrincipal
 //*****************************************************************************
 
@@ -6093,24 +6120,52 @@ nsGlobalWindow::ShowModalDialog(const ns
                              nsnull, aArgs,     // args
                              GetPrincipal(),    // aCalleePrincipal
                              nsnull,            // aJSCallerContext
                              getter_AddRefs(dlgWin));
 
   NS_ENSURE_SUCCESS(rv, rv);
   
   if (dlgWin) {
-    nsCOMPtr<nsPIDOMWindow> win(do_QueryInterface(dlgWin));
-
-    nsPIDOMWindow *inner = win->GetCurrentInnerWindow();
-
-    nsCOMPtr<nsIDOMModalContentWindow> dlgInner(do_QueryInterface(inner));
-
-    if (dlgInner) {
-      dlgInner->GetReturnValue(aRetVal);
+    nsCOMPtr<nsIPrincipal> subjectPrincipal;
+    rv = nsContentUtils::GetSecurityManager()->
+      GetSubjectPrincipal(getter_AddRefs(subjectPrincipal));
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+
+    PRBool canAccess = PR_TRUE;
+
+    if (subjectPrincipal) {
+      nsCOMPtr<nsIScriptObjectPrincipal> objPrincipal =
+        do_QueryInterface(dlgWin);
+      nsCOMPtr<nsIPrincipal> dialogPrincipal;
+
+      if (objPrincipal) {
+        dialogPrincipal = objPrincipal->GetPrincipal();
+
+        rv = subjectPrincipal->Subsumes(dialogPrincipal, &canAccess);
+        NS_ENSURE_SUCCESS(rv, rv);
+      } else {
+        // Uh, not sure what kind of dialog this is. Prevent access to
+        // be on the safe side...
+
+        canAccess = PR_FALSE;
+      }
+    }
+
+    if (canAccess) {
+      nsCOMPtr<nsPIDOMWindow> win(do_QueryInterface(dlgWin));
+      nsPIDOMWindow *inner = win->GetCurrentInnerWindow();
+
+      nsCOMPtr<nsIDOMModalContentWindow> dlgInner(do_QueryInterface(inner));
+
+      if (dlgInner) {
+        dlgInner->GetReturnValue(aRetVal);
+      }
     }
   }
   
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsGlobalWindow::UpdateCommands(const nsAString& anAction)
@@ -7401,17 +7456,17 @@ nsGlobalWindow::OpenInternal(const nsASt
   NS_PRECONDITION(!aExtraArgument || (!argv && argc == 0),
                   "Can't pass in arguments both ways");
   NS_PRECONDITION(!aCalledNoScript || (!argv && argc == 0),
                   "Can't pass JS args when called via the noscript methods");
   NS_PRECONDITION(!aJSCallerContext || !aCalledNoScript,
                   "Shouldn't have caller context when called noscript");
 
   *aReturn = nsnull;
-  
+
   nsCOMPtr<nsIWebBrowserChrome> chrome;
   GetWebBrowserChrome(getter_AddRefs(chrome));
   if (!chrome) {
     // No chrome means we don't want to go through with this open call
     // -- see nsIWindowWatcher.idl
     return NS_ERROR_NOT_AVAILABLE;
   }
 
@@ -9035,17 +9090,24 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 
 NS_IMETHODIMP
 nsGlobalModalWindow::GetDialogArguments(nsIArray **aArguments)
 {
   FORWARD_TO_INNER_MODAL_CONTENT_WINDOW(GetDialogArguments, (aArguments),
                                         NS_ERROR_NOT_INITIALIZED);
 
-  *aArguments = mArguments;
+  PRBool subsumes = PR_FALSE;
+  nsIPrincipal *self = GetPrincipal();
+  if (self && NS_SUCCEEDED(self->Subsumes(mArgumentsOrigin, &subsumes)) &&
+      subsumes) {
+    NS_IF_ADDREF(*aArguments = mArguments);
+  } else {
+    *aArguments = nsnull;
+  }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsGlobalModalWindow::GetReturnValue(nsIVariant **aRetVal)
 {
   FORWARD_TO_OUTER_MODAL_CONTENT_WINDOW(GetReturnValue, (aRetVal), NS_OK);
@@ -9060,16 +9122,30 @@ nsGlobalModalWindow::SetReturnValue(nsIV
 {
   FORWARD_TO_OUTER_MODAL_CONTENT_WINDOW(SetReturnValue, (aRetVal), NS_OK);
 
   mReturnValue = aRetVal;
 
   return NS_OK;
 }
 
+nsresult
+nsGlobalModalWindow::SetNewDocument(nsIDocument *aDocument,
+                                    nsISupports *aState,
+                                    PRBool aClearScopeHint)
+{
+  // If we're loading a new document into a modal dialog, clear the
+  // return value that was set, if any, by the current document.
+  if (aDocument) {
+    mReturnValue = nsnull;
+  }
+
+  return nsGlobalWindow::SetNewDocument(aDocument, aState, aClearScopeHint);
+}
+
 //*****************************************************************************
 // nsGlobalWindow: Creator Function (This should go away)
 //*****************************************************************************
 
 nsresult
 NS_NewScriptGlobalObject(PRBool aIsChrome, PRBool aIsModalContentWindow,
                          nsIScriptGlobalObject **aResult)
 {
--- a/dom/base/nsGlobalWindow.h
+++ b/dom/base/nsGlobalWindow.h
@@ -256,17 +256,16 @@ public:
   virtual void *GetScriptGlobal(PRUint32 lang);
 
   // Set a new script language context for this global.  The native global
   // for the context is created by the context's GetNativeGlobal() method.
   virtual nsresult SetScriptContext(PRUint32 lang, nsIScriptContext *aContext);
   
   virtual void OnFinalize(PRUint32 aLangID, void *aScriptGlobal);
   virtual void SetScriptsEnabled(PRBool aEnabled, PRBool aFireTimeouts);
-  virtual nsresult SetNewArguments(nsIArray *aArguments);
 
   // nsIScriptObjectPrincipal
   virtual nsIPrincipal* GetPrincipal();
 
   // nsIDOMWindow
   NS_DECL_NSIDOMWINDOW
 
   // nsIDOMWindow2
@@ -336,18 +335,18 @@ public:
                                                      const nsIID& aIID);
   virtual NS_HIDDEN_(nsresult) RemoveEventListenerByIID(nsIDOMEventListener *aListener,
                                                         const nsIID& aIID);
   virtual NS_HIDDEN_(nsresult) GetSystemEventGroup(nsIDOMEventGroup** aGroup);
   virtual NS_HIDDEN_(nsIScriptContext*) GetContextForEventHandlers(nsresult* aRv);
 
   virtual NS_HIDDEN_(void) SetDocShell(nsIDocShell* aDocShell);
   virtual NS_HIDDEN_(nsresult) SetNewDocument(nsIDocument *aDocument,
-                                  nsISupports *aState,
-                                  PRBool aClearScopeHint);
+                                              nsISupports *aState,
+                                              PRBool aClearScopeHint);
   virtual NS_HIDDEN_(void) SetOpenerWindow(nsIDOMWindowInternal *aOpener,
                                            PRBool aOriginalOpener);
   virtual NS_HIDDEN_(void) EnsureSizeUpToDate();
 
   virtual NS_HIDDEN_(void) EnterModalState();
   virtual NS_HIDDEN_(void) LeaveModalState();
 
   virtual NS_HIDDEN_(void) SetHasOrientationEventListener();
@@ -445,32 +444,34 @@ public:
   virtual NS_HIDDEN_(void)
     CacheXBLPrototypeHandler(nsXBLPrototypeHandler* aKey,
                              nsScriptObjectHolder& aHandler);
 
   virtual PRBool TakeFocus(PRBool aFocus, PRUint32 aFocusMethod);
   virtual void SetReadyForFocus();
   virtual void PageHidden();
   virtual nsresult DispatchAsyncHashchange();
+  virtual nsresult SetArguments(nsIArray *aArguments, nsIPrincipal *aOrigin);
 
   static PRBool DOMWindowDumpEnabled();
 
 protected:
   // Object Management
   virtual ~nsGlobalWindow();
   void CleanUp();
   void ClearControllers();
 
   void FreeInnerObjects(PRBool aClearScope);
   nsGlobalWindow *CallerInnerWindow();
 
   nsresult SetNewDocument(nsIDocument *aDocument,
                           nsISupports *aState,
                           PRBool aClearScopeHint,
                           PRBool aIsInternalCall);
+  nsresult DefineArgumentsProperty(nsIArray *aArguments);
 
   // Get the parent, returns null if this is a toplevel window
   nsIDOMWindowInternal *GetParentInternal();
 
   // popup tracking
   PRBool IsPopupSpamWindow()
   {
     if (IsInnerWindow() && !mOuterWindow) {
@@ -720,16 +721,17 @@ protected:
   // Indicates whether this window is getting acceleration change events
   PRPackedBool           mHasAcceleration  : 1;
 
   nsCOMPtr<nsIScriptContext>    mContext;
   nsWeakPtr                     mOpener;
   nsCOMPtr<nsIControllers>      mControllers;
   nsCOMPtr<nsIArray>            mArguments;
   nsCOMPtr<nsIArray>            mArgumentsLast;
+  nsCOMPtr<nsIPrincipal>        mArgumentsOrigin;
   nsRefPtr<nsNavigator>         mNavigator;
   nsRefPtr<nsScreen>            mScreen;
   nsRefPtr<nsHistory>           mHistory;
   nsRefPtr<nsDOMWindowList>     mFrames;
   nsRefPtr<nsBarProp>           mMenubar;
   nsRefPtr<nsBarProp>           mToolbar;
   nsRefPtr<nsBarProp>           mLocationbar;
   nsRefPtr<nsBarProp>           mPersonalbar;
@@ -841,16 +843,20 @@ public:
     mIsModalContentWindow = PR_TRUE;
   }
 
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_NSIDOMMODALCONTENTWINDOW
 
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsGlobalModalWindow, nsGlobalWindow)
 
+  virtual NS_HIDDEN_(nsresult) SetNewDocument(nsIDocument *aDocument,
+                                              nsISupports *aState,
+                                              PRBool aClearScopeHint);
+
 protected:
   nsCOMPtr<nsIVariant> mReturnValue;
 };
 
 
 //*****************************************************************************
 // nsNavigator: Script "navigator" object
 //*****************************************************************************
--- a/dom/base/nsIScriptGlobalObject.h
+++ b/dom/base/nsIScriptGlobalObject.h
@@ -96,23 +96,22 @@ struct JSObject; // until we finally rem
 // aStatus will be filled in with the status.
 PRBool
 NS_HandleScriptError(nsIScriptGlobalObject *aScriptGlobal,
                      nsScriptErrorEvent *aErrorEvent,
                      nsEventStatus *aStatus);
 
 
 #define NS_ISCRIPTGLOBALOBJECT_IID \
-{ /* {6afecd40-0b9a-4cfd-8c42-0f645cd91829} */ \
-  0x6afecd40, 0x0b9a, 0x4cfd, \
-  { 0x8c, 0x42, 0x0f, 0x64, 0x5c, 0xd9, 0x18, 0x29 } }
+{ 0xe9f3f2c1, 0x2d94, 0x4722, \
+  { 0xbb, 0xd4, 0x2b, 0xf6, 0xfd, 0xf4, 0x2f, 0x48 } }
 
 /**
-+  * The global object which keeps a script context for each supported script
-+  * language. This often used to store per-window global state.
+  * The global object which keeps a script context for each supported script
+  * language. This often used to store per-window global state.
  */
 
 class nsIScriptGlobalObject : public nsISupports
 {
 public:
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_ISCRIPTGLOBALOBJECT_IID)
 
   /**
@@ -161,25 +160,18 @@ public:
 
   virtual void OnFinalize(PRUint32 aLangID, void *aScriptGlobal) = 0;
 
   /**
    * Called to enable/disable scripts.
    */
   virtual void SetScriptsEnabled(PRBool aEnabled, PRBool aFireTimeouts) = 0;
 
-  /** Set a new arguments object for this window. This will be set on
-   * the window right away (if there's an existing document) and it
-   * will also be installed on the window when the next document is
-   * loaded.  Each language impl is responsible for converting to
-   * an array of args as appropriate for that language.
-   */
-  virtual nsresult SetNewArguments(nsIArray *aArguments) = 0;
-
-  /** Handle a script error.  Generally called by a script context.
+  /**
+   * Handle a script error.  Generally called by a script context.
    */
   virtual nsresult HandleScriptError(nsScriptErrorEvent *aErrorEvent,
                                      nsEventStatus *aEventStatus) {
     return NS_HandleScriptError(this, aErrorEvent, aEventStatus);
   }
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsIScriptGlobalObject,
--- a/dom/base/nsPIDOMWindow.h
+++ b/dom/base/nsPIDOMWindow.h
@@ -72,20 +72,21 @@ class nsIDocShell;
 class nsIFocusController;
 class nsIContent;
 class nsIDocument;
 class nsIScriptTimeoutHandler;
 class nsPresContext;
 struct nsTimeout;
 class nsScriptObjectHolder;
 class nsXBLPrototypeHandler;
+class nsIArray;
 
 #define NS_PIDOMWINDOW_IID \
-{ 0x249423c9, 0x42a6, 0x8243, \
-  { 0x49, 0x45, 0x71, 0x7f, 0x8d, 0x28, 0x84, 0x43 } }
+{ 0x70c9f57f, 0xf7b3, 0x4a37, \
+  { 0xbe, 0x36, 0xbb, 0xb2, 0xd7, 0xe9, 0x40, 0x13 } }
 
 class nsPIDOMWindow : public nsIDOMWindowInternal
 {
 public:
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_PIDOMWINDOW_IID)
 
   virtual nsPIDOMWindow* GetPrivateRoot() = 0;
 
@@ -465,16 +466,25 @@ public:
   virtual nsresult DispatchAsyncHashchange() = 0;
 
 
   /**
    * Tell this window that there is an observer for orientation changes
    */
   virtual void SetHasOrientationEventListener() = 0;
 
+  /**
+   * Set a arguments for this window. This will be set on the window
+   * right away (if there's an existing document) and it will also be
+   * installed on the window when the next document is loaded. Each
+   * language impl is responsible for converting to an array of args
+   * as appropriate for that language.
+   */
+  virtual nsresult SetArguments(nsIArray *aArguments, nsIPrincipal *aOrigin) = 0;
+
 protected:
   // The nsPIDOMWindow constructor. The aOuterWindow argument should
   // be null if and only if the created window itself is an outer
   // window. In all other cases aOuterWindow should be the outer
   // window for the inner window that is being created.
   nsPIDOMWindow(nsPIDOMWindow *aOuterWindow)
     : mFrameElement(nsnull), mDocShell(nsnull), mModalStateDepth(0),
       mRunningTimeout(nsnull), mMutationBits(0), mIsDocumentLoaded(PR_FALSE),
--- a/dom/tests/mochitest/bugs/Makefile.in
+++ b/dom/tests/mochitest/bugs/Makefile.in
@@ -95,12 +95,14 @@ include $(topsrcdir)/config/rules.mk
 		test_bug459848.html \
 		test_bug463000.html \
 		iframe_bug463000.html \
 		test_bug465263.html \
 		test_bug479143.html \
 		test_bug484775.html \
 		test_bug427744.html \
 		test_bug495219.html \
+		test_bug504862.html \
+		file_bug504862.html \
 		$(NULL)
 
 libs:: 	$(_TEST_FILES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir)
--- a/embedding/components/windowwatcher/src/nsWindowWatcher.cpp
+++ b/embedding/components/windowwatcher/src/nsWindowWatcher.cpp
@@ -55,16 +55,17 @@
 #include "nsIDocShellTreeItem.h"
 #include "nsIDocShellTreeOwner.h"
 #include "nsIDocumentLoader.h"
 #include "nsIDocument.h"
 #include "nsIDOMDocument.h"
 #include "nsIDOMWindow.h"
 #include "nsIDOMChromeWindow.h"
 #include "nsIDOMWindowInternal.h"
+#include "nsIDOMModalContentWindow.h"
 #include "nsIScriptObjectPrincipal.h"
 #include "nsIScreen.h"
 #include "nsIScreenManager.h"
 #include "nsIScriptContext.h"
 #include "nsIGenericFactory.h"
 #include "nsIJSContextStack.h"
 #include "nsIObserverService.h"
 #include "nsIScriptGlobalObject.h"
@@ -568,21 +569,31 @@ nsWindowWatcher::OpenWindowJSInternal(ns
     windowIsModalContentDialog = PR_TRUE;
 
     chromeFlags |= nsIWebBrowserChrome::CHROME_MODAL;
   }
 
   SizeSpec sizeSpec;
   CalcSizeSpec(features.get(), sizeSpec);
 
-  PRBool isCallerChrome = PR_FALSE;
   nsCOMPtr<nsIScriptSecurityManager>
     sm(do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID));
-  if (sm)
-    sm->SubjectPrincipalIsSystem(&isCallerChrome);
+
+  // Remember who's calling us. This code used to assume a null
+  // subject principal if it failed to get the principal, but that's
+  // just not safe, so bail on errors here.
+  nsCOMPtr<nsIPrincipal> callerPrincipal;
+  rv = sm->GetSubjectPrincipal(getter_AddRefs(callerPrincipal));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  PRBool isCallerChrome = PR_TRUE;
+  if (callerPrincipal) {
+    rv = sm->IsSystemPrincipal(callerPrincipal, &isCallerChrome);
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
 
   JSContext *cx = GetJSContextFromWindow(aParent);
 
   if (isCallerChrome && !chromeParent && cx) {
     // open() is called from chrome on a non-chrome window, push
     // the context of the callee onto the context stack to
     // prevent the caller's priveleges from leaking into code
     // that runs while opening the new window.
@@ -751,19 +762,20 @@ nsWindowWatcher::OpenWindowJSInternal(ns
       newDocShellItem->GetTreeOwner(getter_AddRefs(newTreeOwner));
       if (newTreeOwner)
         newTreeOwner->SetPersistence(PR_FALSE, PR_FALSE, PR_FALSE);
     }
   }
 
   if ((aDialog || windowIsModalContentDialog) && argv) {
     // Set the args on the new window.
-    nsCOMPtr<nsIScriptGlobalObject> scriptGlobal(do_QueryInterface(*_retval));
-    NS_ENSURE_TRUE(scriptGlobal, NS_ERROR_UNEXPECTED);
-    rv = scriptGlobal->SetNewArguments(argv);
+    nsCOMPtr<nsPIDOMWindow> piwin(do_QueryInterface(*_retval));
+    NS_ENSURE_TRUE(piwin, NS_ERROR_UNEXPECTED);
+
+    rv = piwin->SetArguments(argv, callerPrincipal);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   /* allow a window that we found by name to keep its name (important for cases
      like _self where the given name is different (and invalid)).  Also, _blank
      is not a window name. */
   if (windowNeedsName)
     newDocShellItem->SetName(nameSpecified &&