Don't assume that chrome:// implies system principals. bug 419848, r=brendan sr=jst
authormrbkap@gmail.com
Thu, 06 Mar 2008 14:52:58 -0800
changeset 12690 0cfc352be6b13903efa69c07bbb909c58b1ebaca
parent 12689 a430406b9ef2f92f59e94b9eeb5c54bffe7a2f12
child 12691 80fa3e80e67141b1da34626935113a64b1b43230
push idunknown
push userunknown
push dateunknown
reviewersbrendan, jst
bugs419848
milestone1.9b5pre
Don't assume that chrome:// implies system principals. bug 419848, r=brendan sr=jst
dom/src/base/nsJSTimeoutHandler.cpp
dom/src/base/nsJSUtils.cpp
dom/src/base/nsJSUtils.h
js/src/jsfun.c
js/src/jsobj.c
js/src/jsobj.h
js/src/jsscript.c
--- a/dom/src/base/nsJSTimeoutHandler.cpp
+++ b/dom/src/base/nsJSTimeoutHandler.cpp
@@ -249,27 +249,22 @@ nsJSScriptTimeoutHandler::Init(nsGlobalW
 
   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, jsprins)) {
+    if (nsJSUtils::GetCallingLocation(cx, &filename, &mLineNo, prin)) {
       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
--- a/dom/src/base/nsJSUtils.cpp
+++ b/dom/src/base/nsJSUtils.cpp
@@ -57,58 +57,50 @@
 #include "nsCOMPtr.h"
 #include "nsContentUtils.h"
 #include "nsIScriptSecurityManager.h"
 
 #include "nsDOMJSUtils.h" // for GetScriptContextFromJSContext
 
 JSBool
 nsJSUtils::GetCallingLocation(JSContext* aContext, const char* *aFilename,
-                              PRUint32* aLineno, JSPrincipals* aPrincipals)
+                              PRUint32* aLineno, nsIPrincipal* aPrincipal)
 {
   // 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) {
-      // The principals might not be in the script, but we can always
-      // find the right principals in the frame's callee.
-      JSPrincipals* scriptPrins = JS_GetScriptPrincipals(aContext, script);
-      if (!scriptPrins) {
-        JSObject *callee = JS_GetFrameCalleeObject(aContext, frame);
-        nsCOMPtr<nsIPrincipal> prin;
+    if (aPrincipal) {
+      uint32 flags = JS_GetScriptFilenameFlags(script);
+
+      // Use the principal for the filename if it shouldn't be receiving
+      // implicit XPCNativeWrappers.
+      PRBool system;
+      if (flags & JSFILENAME_PROTECTED) {
         nsIScriptSecurityManager *ssm = nsContentUtils::GetSecurityManager();
-        if (NS_FAILED(ssm->GetObjectPrincipal(aContext, callee,
-                                              getter_AddRefs(prin))) ||
-            !prin) {
-          return JS_FALSE;
+
+        if (NS_FAILED(ssm->IsSystemPrincipal(aPrincipal, &system)) || !system) {
+          JSPrincipals* jsprins;
+          aPrincipal->GetJSPrincipals(aContext, &jsprins);
+
+          *aFilename = jsprins->codebase;
+          *aLineno = 0;
+          JSPRINCIPALS_DROP(aContext, jsprins);
+          return JS_TRUE;
         }
-
-        prin->GetJSPrincipals(aContext, &scriptPrins);
-
-        // The script has a reference to the principals.
-        JSPRINCIPALS_DROP(aContext, scriptPrins);
-      }
-
-      // 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);
--- a/dom/src/base/nsJSUtils.h
+++ b/dom/src/base/nsJSUtils.h
@@ -47,22 +47,23 @@
 
 #include "nsISupports.h"
 #include "jsapi.h"
 #include "nsString.h"
 
 class nsIDOMEventListener;
 class nsIScriptContext;
 class nsIScriptGlobalObject;
+class nsIPrincipal;
 
 class nsJSUtils
 {
 public:
   static JSBool GetCallingLocation(JSContext* aContext, const char* *aFilename,
-                                   PRUint32* aLineno, JSPrincipals* aPrincipals);
+                                   PRUint32* aLineno, nsIPrincipal* aPrincipal);
 
   static jsval ConvertStringToJSVal(const nsString& aProp,
                                     JSContext* aContext);
 
   static void ConvertJSValToString(nsAString& aString,
                                    JSContext* aContext, jsval aValue);
 
   static PRBool ConvertJSValToUint32(PRUint32* aProp, JSContext* aContext,
--- a/js/src/jsfun.c
+++ b/js/src/jsfun.c
@@ -1753,23 +1753,17 @@ Function(JSContext *cx, JSObject *obj, u
      * Find the scripted caller, possibly skipping other native frames such as
      * are built for Function.prototype.call or .apply activations that invoke
      * Function indirectly from a script.
      */
     JS_ASSERT(!fp->script && fp->fun && fp->fun->u.n.native == Function);
     caller = JS_GetScriptedCaller(cx, fp);
     if (caller) {
         principals = JS_EvalFramePrincipals(cx, fp, caller);
-        if (principals == caller->script->principals) {
-            filename = caller->script->filename;
-            lineno = js_PCToLineNumber(cx, caller->script, caller->pc);
-        } else {
-            filename = principals->codebase;
-            lineno = 0;
-        }
+        filename = js_ComputeFilename(cx, caller, principals, &lineno);
     } else {
         filename = NULL;
         lineno = 0;
         principals = NULL;
     }
 
     /* Belt-and-braces: check that the caller has access to parent. */
     if (!js_CheckPrincipalsAccess(cx, parent, principals,
--- a/js/src/jsobj.c
+++ b/js/src/jsobj.c
@@ -1128,16 +1128,33 @@ js_CheckScopeChainValidity(JSContext *cx
     return inner;
 
 bad:
     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
                          JSMSG_BAD_INDIRECT_CALL, caller);
     return NULL;
 }
 
+const char *
+js_ComputeFilename(JSContext *cx, JSStackFrame *caller,
+                   JSPrincipals *principals, uintN *linenop)
+{
+    uint32 flags;
+
+    flags = JS_GetScriptFilenameFlags(caller->script);
+    if ((flags & JSFILENAME_PROTECTED) &&
+        strcmp(principals->codebase, "[System Principal]")) {
+        *linenop = 0;
+        return principals->codebase;
+    }
+
+    *linenop = js_PCToLineNumber(cx, caller->script, caller->pc);
+    return caller->script->filename;
+}
+
 static JSBool
 obj_eval(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
 {
     JSStackFrame *fp, *caller;
     JSBool indirectCall;
     JSObject *scopeobj;
     JSString *str;
     const char *file;
@@ -1266,23 +1283,17 @@ obj_eval(JSContext *cx, JSObject *obj, u
     if (!scopeobj) {
         ok = JS_FALSE;
         goto out;
     }
 
     str = JSVAL_TO_STRING(argv[0]);
     if (caller) {
         principals = JS_EvalFramePrincipals(cx, fp, caller);
-        if (principals == caller->script->principals) {
-            file = caller->script->filename;
-            line = js_PCToLineNumber(cx, caller->script, caller->pc);
-        } else {
-            file = principals->codebase;
-            line = 0;
-        }
+        file = js_ComputeFilename(cx, caller, principals, &line);
     } else {
         file = NULL;
         line = 0;
         principals = NULL;
     }
 
     /*
      * Set JSFRAME_EVAL on fp and any frames (e.g., fun_call if eval.call was
--- a/js/src/jsobj.h
+++ b/js/src/jsobj.h
@@ -694,11 +694,15 @@ js_CheckScopeChainValidity(JSContext *cx
 extern JSBool
 js_CheckPrincipalsAccess(JSContext *cx, JSObject *scopeobj,
                          JSPrincipals *principals, JSAtom *caller);
 
 /* Infallible -- returns its argument if there is no wrapped object. */
 extern JSObject *
 js_GetWrappedObject(JSContext *cx, JSObject *obj);
 
+/* NB: Infallible. */
+extern const char *
+js_ComputeFilename(JSContext *cx, JSStackFrame *caller,
+                   JSPrincipals *principals, uintN *linenop);
 JS_END_EXTERN_C
 
 #endif /* jsobj_h___ */
--- a/js/src/jsscript.c
+++ b/js/src/jsscript.c
@@ -236,19 +236,18 @@ script_compile_sub(JSContext *cx, JSObje
     if (caller) {
         if (!scopeobj) {
             scopeobj = js_GetScopeChain(cx, caller);
             if (!scopeobj)
                 return JS_FALSE;
             fp->scopeChain = scopeobj;  /* for the compiler's benefit */
         }
 
-        file = caller->script->filename;
-        line = js_PCToLineNumber(cx, caller->script, caller->pc);
         principals = JS_EvalFramePrincipals(cx, fp, caller);
+        file = js_ComputeFilename(cx, caller, principals, &line);
     } else {
         file = NULL;
         line = 0;
         principals = NULL;
     }
 
     /* Ensure we compile this script with the right (inner) principals. */
     scopeobj = js_CheckScopeChainValidity(cx, scopeobj, js_script_compile_str);