Be more careful about what filename we propagate to compiled setTimeout functions. bug 411092, r+sr=jst
authormrbkap@gmail.com
Tue, 29 Jan 2008 18:11:48 -0800
changeset 10986 2974b7f0b06cc195b987f1b3f302452b1aa473be
parent 10985 baba618bf0985a08d89a67af91c25be2530e5c3d
child 10987 40e2910e343d1803cf461867c64bfc9f1f42f0e5
push idunknown
push userunknown
push dateunknown
bugs411092
milestone1.9b3pre
Be more careful about what filename we propagate to compiled setTimeout functions. bug 411092, r+sr=jst
dom/src/base/nsGlobalWindow.cpp
dom/src/base/nsGlobalWindow.h
dom/src/base/nsJSTimeoutHandler.cpp
dom/src/base/nsJSUtils.cpp
dom/src/base/nsJSUtils.h
--- a/dom/src/base/nsGlobalWindow.cpp
+++ b/dom/src/base/nsGlobalWindow.cpp
@@ -7350,17 +7350,17 @@ nsGlobalWindow::SetTimeoutOrInterval(PRB
 
     FORWARD_TO_INNER(SetTimeoutOrInterval, (aIsInterval, aReturn),
                      NS_ERROR_NOT_INITIALIZED);
   }
 
   PRInt32 interval = 0;
   PRBool isInterval = aIsInterval;
   nsCOMPtr<nsIScriptTimeoutHandler> handler;
-  nsresult rv = NS_CreateJSTimeoutHandler(GetContextInternal(),
+  nsresult rv = NS_CreateJSTimeoutHandler(this,
                                           &isInterval,
                                           &interval,
                                           getter_AddRefs(handler));
   if (NS_FAILED(rv))
     return (rv == NS_ERROR_DOM_TYPE_ERR) ? NS_OK : rv;
 
   return SetTimeoutOrInterval(handler, interval, isInterval, aReturn);
 }
--- a/dom/src/base/nsGlobalWindow.h
+++ b/dom/src/base/nsGlobalWindow.h
@@ -133,17 +133,17 @@ class nsDOMOfflineLoadStatusList;
 // permissible values for CheckOpenAllow
 enum OpenAllowValue {
   allowNot = 0,     // the window opening is denied
   allowNoAbuse,     // allowed: not a popup
   allowWhitelisted  // allowed: it's whitelisted or popup blocking is disabled
 };
 
 extern nsresult
-NS_CreateJSTimeoutHandler(nsIScriptContext *aContext,
+NS_CreateJSTimeoutHandler(nsGlobalWindow *aWindow,
                           PRBool *aIsInterval,
                           PRInt32 *aInterval,
                           nsIScriptTimeoutHandler **aRet);
 
 /*
  * Timeout struct that holds information about each script
  * timeout.  Holds a strong reference to an nsIScriptTimeoutHandler, which
  * abstracts the language specific cruft.
--- a/dom/src/base/nsJSTimeoutHandler.cpp
+++ b/dom/src/base/nsJSTimeoutHandler.cpp
@@ -44,16 +44,17 @@
 #include "nsIXPConnect.h"
 #include "nsIJSRuntimeService.h"
 #include "nsJSUtils.h"
 #include "nsDOMJSUtils.h"
 #include "nsContentUtils.h"
 #include "nsJSEnvironment.h"
 #include "nsServiceManagerUtils.h"
 #include "nsDOMError.h"
+#include "nsGlobalWindow.h"
 
 static const char kSetIntervalStr[] = "setInterval";
 static const char kSetTimeoutStr[] = "setTimeout";
 
 // Our JS nsIScriptTimeoutHandler implementation.
 class nsJSScriptTimeoutHandler: public nsIScriptTimeoutHandler
 {
 public:
@@ -82,17 +83,17 @@ public:
 
   virtual nsIArray *GetArgv() {
     return mArgv;
   }
   // Called by the timeout mechanism so the secret 'lateness' arg can be
   // added.
   virtual void SetLateness(PRIntervalTime aHowLate);
 
-  nsresult Init(nsIScriptContext *aContext, PRBool *aIsInterval,
+  nsresult Init(nsGlobalWindow *aWindow, PRBool *aIsInterval,
                 PRInt32 *aInterval);
 
   void ReleaseJSObjects();
 
 private:
 
   nsCOMPtr<nsIScriptContext> mContext;
 
@@ -160,28 +161,27 @@ nsJSScriptTimeoutHandler::ReleaseJSObjec
       mFunObj = nsnull;
     } else {
       NS_WARNING("No func and no expr - roots may not have been removed");
     }
   }
 }
 
 nsresult
-nsJSScriptTimeoutHandler::Init(nsIScriptContext *aContext, PRBool *aIsInterval,
+nsJSScriptTimeoutHandler::Init(nsGlobalWindow *aWindow, PRBool *aIsInterval,
                                PRInt32 *aInterval)
 {
-  if (!aContext) {
+  mContext = aWindow->GetContextInternal();
+  if (!mContext) {
     // This window was already closed, or never properly initialized,
     // don't let a timer be scheduled on such a window.
 
     return NS_ERROR_NOT_INITIALIZED;
   }
 
-  mContext = aContext;
-
   nsAXPCNativeCallContext *ncc = nsnull;
   nsresult rv = nsContentUtils::XPConnect()->
     GetCurrentNativeCallContext(&ncc);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (!ncc)
     return NS_ERROR_NOT_AVAILABLE;
 
@@ -248,21 +248,28 @@ nsJSScriptTimeoutHandler::Init(nsIScript
   }
 
   if (expr) {
     rv = NS_HOLD_JS_OBJECTS(this, nsJSScriptTimeoutHandler);
     NS_ENSURE_SUCCESS(rv, rv);
 
     mExpr = expr;
 
+    nsIPrincipal *prin = aWindow->GetPrincipal();
+    JSPrincipals *jsprins;
+    rv = prin->GetJSPrincipals(cx, &jsprins);
+    NS_ENSURE_SUCCESS(rv, rv);
+
     // Get the calling location.
     const char *filename;
-    if (nsJSUtils::GetCallingLocation(cx, &filename, &mLineNo)) {
+    if (nsJSUtils::GetCallingLocation(cx, &filename, &mLineNo, jsprins)) {
       mFileName.Assign(filename);
     }
+
+    JSPRINCIPALS_DROP(cx, jsprins);
   } else if (funobj) {
     rv = NS_HOLD_JS_OBJECTS(this, nsJSScriptTimeoutHandler);
     NS_ENSURE_SUCCESS(rv, rv);
 
     mFunObj = funobj;
 
     // Create our arg array - leave an extra slot for a secret final argument
     // that indicates to the called function how "late" the timeout is.  We
@@ -310,27 +317,27 @@ void nsJSScriptTimeoutHandler::SetLatene
 const PRUnichar *
 nsJSScriptTimeoutHandler::GetHandlerText()
 {
   NS_ASSERTION(mExpr, "No expression, so no handler text!");
   return reinterpret_cast<const PRUnichar *>
                          (::JS_GetStringChars(mExpr));
 }
 
-nsresult NS_CreateJSTimeoutHandler(nsIScriptContext *aContext,
+nsresult NS_CreateJSTimeoutHandler(nsGlobalWindow *aWindow,
                                    PRBool *aIsInterval,
                                    PRInt32 *aInterval,
                                    nsIScriptTimeoutHandler **aRet)
 {
   *aRet = nsnull;
   nsJSScriptTimeoutHandler *handler = new nsJSScriptTimeoutHandler();
   if (!handler)
     return NS_ERROR_OUT_OF_MEMORY;
 
-  nsresult rv = handler->Init(aContext, aIsInterval, aInterval);
+  nsresult rv = handler->Init(aWindow, aIsInterval, aInterval);
   if (NS_FAILED(rv)) {
     delete handler;
     return rv;
   }
 
   NS_ADDREF(*aRet = handler);
 
   return NS_OK;
--- a/dom/src/base/nsJSUtils.cpp
+++ b/dom/src/base/nsJSUtils.cpp
@@ -1,9 +1,10 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 sw=2 et tw=78: */
 /* ***** BEGIN LICENSE BLOCK *****
  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  *
  * The contents of this file are subject to the Mozilla Public License Version
  * 1.1 (the "License"); you may not use this file except in compliance with
  * the License. You may obtain a copy of the License at
  * http://www.mozilla.org/MPL/
  *
@@ -55,30 +56,44 @@
 #include "nsIXPConnect.h"
 #include "nsCOMPtr.h"
 #include "nsContentUtils.h"
 
 #include "nsDOMJSUtils.h" // for GetScriptContextFromJSContext
 
 JSBool
 nsJSUtils::GetCallingLocation(JSContext* aContext, const char* *aFilename,
-                              PRUint32 *aLineno)
+                              PRUint32* aLineno, JSPrincipals* aPrincipals)
 {
   // Get the current filename and line number
   JSStackFrame* frame = nsnull;
   JSScript* script = nsnull;
   do {
     frame = ::JS_FrameIterator(aContext, &frame);
 
     if (frame) {
       script = ::JS_GetFrameScript(aContext, frame);
     }
   } while (frame && !script);
 
   if (script) {
+    // If aPrincipals is non-null then our caller is asking us to ensure
+    // that the filename we return does not have elevated privileges.
+    if (aPrincipals) {
+      JSPrincipals* scriptPrins = JS_GetScriptPrincipals(aContext, script);
+
+      // Return the weaker of the two principals if they differ.
+      if (scriptPrins != aPrincipals &&
+          scriptPrins->subsume(scriptPrins, aPrincipals)) {
+        *aFilename = aPrincipals->codebase;
+        *aLineno = 0;
+        return JS_TRUE;
+      }
+    }
+
     const char* filename = ::JS_GetScriptFilename(aContext, script);
 
     if (filename) {
       PRUint32 lineno = 0;
       jsbytecode* bytecode = ::JS_GetFramePC(aContext, frame);
 
       if (bytecode) {
         lineno = ::JS_PCToLineNumber(aContext, script, bytecode);
--- a/dom/src/base/nsJSUtils.h
+++ b/dom/src/base/nsJSUtils.h
@@ -52,17 +52,17 @@
 class nsIDOMEventListener;
 class nsIScriptContext;
 class nsIScriptGlobalObject;
 
 class nsJSUtils
 {
 public:
   static JSBool GetCallingLocation(JSContext* aContext, const char* *aFilename,
-                                   PRUint32 *aLineno);
+                                   PRUint32* aLineno, JSPrincipals* aPrincipals);
 
   static jsval ConvertStringToJSVal(const nsString& aProp,
                                     JSContext* aContext);
 
   static void ConvertJSValToString(nsAString& aString,
                                    JSContext* aContext, jsval aValue);
 
   static PRBool ConvertJSValToUint32(PRUint32* aProp, JSContext* aContext,