Bug 795275 - Introduce an explicit mechanism for determining if a script is from XBL. r=mrbkap
authorBobby Holley <bobbyholley@gmail.com>
Wed, 03 Oct 2012 11:44:18 +0200
changeset 115328 fb8bb92771523f9a59d125b6775b403ef7a29906
parent 115327 00d03da9049aaaf8527e604070109a1e4f36cc3e
child 115329 43de19945cb1beacc8d20595627216e7b76f4954
push id1708
push userakeybl@mozilla.com
push dateMon, 19 Nov 2012 21:10:21 +0000
treeherdermozilla-beta@27b14fe50103 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmrbkap
bugs795275
milestone18.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 795275 - Introduce an explicit mechanism for determining if a script is from XBL. r=mrbkap We want this right now so that we can avoid the scary warning when content Components access happens in XBL (which we're allowing going forward). This patch would be overkill just for that, but I also have plans to introduce a SOW-like protection of the Components wrapper filtering policy. I can't just do the filename hack for that though, because real- world XBL filenames might be all over the place. So let's just be safe here.
content/events/src/nsEventListenerManager.cpp
content/xbl/src/nsXBLProtoImplMethod.cpp
content/xbl/src/nsXBLProtoImplProperty.cpp
content/xbl/src/nsXBLPrototypeHandler.cpp
dom/base/nsIScriptContext.h
dom/base/nsJSEnvironment.cpp
dom/base/nsJSEnvironment.h
js/src/jsdbgapi.cpp
js/src/jsdbgapi.h
js/src/jsscript.cpp
js/src/jsscript.h
js/xpconnect/wrappers/AccessCheck.cpp
js/xpconnect/wrappers/AccessCheck.h
--- a/content/events/src/nsEventListenerManager.cpp
+++ b/content/events/src/nsEventListenerManager.cpp
@@ -817,16 +817,17 @@ nsEventListenerManager::CompileEventHand
                                      aListenerStruct->mTypeAtom,
                                      &argCount, &argNames);
 
     result = context->CompileEventHandler(aListenerStruct->mTypeAtom,
                                           argCount, argNames,
                                           *body,
                                           url.get(), lineNo,
                                           SCRIPTVERSION_DEFAULT, // for now?
+                                          /* aIsXBL = */ false,
                                           handler);
     if (result == NS_ERROR_ILLEGAL_VALUE) {
       NS_WARNING("Probably a syntax error in the event handler!");
       return NS_SUCCESS_LOSS_OF_INSIGNIFICANT_DATA;
     }
     NS_ENSURE_SUCCESS(result, result);
   }
 
--- a/content/xbl/src/nsXBLProtoImplMethod.cpp
+++ b/content/xbl/src/nsXBLProtoImplMethod.cpp
@@ -201,17 +201,18 @@ nsXBLProtoImplMethod::CompileMember(nsIS
   nsresult rv = aContext->CompileFunction(aClassObject,
                                           cname,
                                           paramCount,
                                           const_cast<const char**>(args),
                                           body, 
                                           functionUri.get(),
                                           uncompiledMethod->mBodyText.GetLineNumber(),
                                           JSVERSION_LATEST,
-                                          true,
+                                          /* aShared = */ true,
+                                          /* aIsXBL = */ true,
                                           &methodObject);
 
   // Destroy our uncompiled method and delete our arg list.
   delete uncompiledMethod;
   delete [] args;
   if (NS_FAILED(rv)) {
     SetUncompiledMethod(nullptr);
     return rv;
--- a/content/xbl/src/nsXBLProtoImplProperty.cpp
+++ b/content/xbl/src/nsXBLProtoImplProperty.cpp
@@ -212,17 +212,18 @@ nsXBLProtoImplProperty::CompileMember(ns
                                      NS_LITERAL_CSTRING("get_") +
                                      NS_ConvertUTF16toUTF8(mName),
                                      0,
                                      nullptr,
                                      getter, 
                                      functionUri.get(),
                                      mGetterText->GetLineNumber(),
                                      JSVERSION_LATEST,
-                                     true,
+                                     /* aShared = */ true,
+                                     /* aIsXBL = */ true,
                                      &getterObject);
 
       // Make sure we free mGetterText here before setting mJSGetterObject, since
       // that'll overwrite mGetterText
       delete mGetterText;
       deletedGetter = true;
       mJSGetterObject = getterObject;
     
@@ -262,17 +263,18 @@ nsXBLProtoImplProperty::CompileMember(ns
                                      NS_LITERAL_CSTRING("set_") +
                                      NS_ConvertUTF16toUTF8(mName),
                                      1,
                                      gPropertyArgs,
                                      setter, 
                                      functionUri.get(),
                                      mSetterText->GetLineNumber(),
                                      JSVERSION_LATEST,
-                                     true,
+                                     /* aShared = */ true,
+                                     /* aIsXBL = */ true,
                                      &setterObject);
 
       // Make sure we free mSetterText here before setting mJSGetterObject, since
       // that'll overwrite mSetterText
       delete mSetterText;
       deletedSetter = true;
       mJSSetterObject = setterObject;
 
--- a/content/xbl/src/nsXBLPrototypeHandler.cpp
+++ b/content/xbl/src/nsXBLPrototypeHandler.cpp
@@ -335,17 +335,19 @@ nsXBLPrototypeHandler::EnsureEventHandle
   uint32_t argCount;
   const char **argNames;
   nsContentUtils::GetEventArgNames(kNameSpaceID_XBL, aName, &argCount,
                                    &argNames);
   nsresult rv = aBoundContext->CompileEventHandler(aName, argCount, argNames,
                                                    handlerText,
                                                    bindingURI.get(), 
                                                    mLineNumber,
-                                                   JSVERSION_LATEST, aHandler);
+                                                   JSVERSION_LATEST,
+                                                   /* aIsXBL = */ true,
+                                                   aHandler);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (pWindow) {
     pWindow->CacheXBLPrototypeHandler(this, aHandler);
   }
 
   return NS_OK;
 }
--- a/dom/base/nsIScriptContext.h
+++ b/dom/base/nsIScriptContext.h
@@ -176,16 +176,17 @@ public:
    */
   virtual nsresult CompileEventHandler(nsIAtom* aName,
                                        uint32_t aArgCount,
                                        const char** aArgNames,
                                        const nsAString& aBody,
                                        const char* aURL,
                                        uint32_t aLineNo,
                                        uint32_t aVersion,
+                                       bool aIsXBL,
                                        nsScriptObjectHolder<JSObject>& aHandler) = 0;
 
   /**
    * Call the function object with given args and return its boolean result,
    * or true if the result isn't boolean.
    *
    * @param aTarget the event target
    * @param aScript an object telling the scope in which to call the compiled
@@ -236,16 +237,17 @@ public:
                                    const nsACString& aName,
                                    uint32_t aArgCount,
                                    const char** aArgArray,
                                    const nsAString& aBody,
                                    const char* aURL,
                                    uint32_t aLineNo,
                                    uint32_t aVersion,
                                    bool aShared,
+                                   bool aIsXBL,
                                    JSObject** aFunctionObject) = 0;
 
   /**
    * Return the global object.
    *
    **/
   virtual nsIScriptGlobalObject *GetGlobalObject() = 0;
 
--- a/dom/base/nsJSEnvironment.cpp
+++ b/dom/base/nsJSEnvironment.cpp
@@ -53,16 +53,17 @@
 #include "prmem.h"
 #include "WrapperFactory.h"
 #include "nsGlobalWindow.h"
 #include "nsScriptNameSpaceManager.h"
 #include "StructuredCloneTags.h"
 #include "mozilla/dom/ImageData.h"
 
 #include "nsJSPrincipals.h"
+#include "jsdbgapi.h"
 
 #ifdef XP_MACOSX
 // AssertMacros.h defines 'check' and conflicts with AccessCheck.h
 #undef check
 #endif
 #include "AccessCheck.h"
 
 #ifdef MOZ_JSDEBUGGER
@@ -1725,16 +1726,17 @@ nsJSContext::JSObjectFromInterface(nsISu
 
 nsresult
 nsJSContext::CompileEventHandler(nsIAtom *aName,
                                  uint32_t aArgCount,
                                  const char** aArgNames,
                                  const nsAString& aBody,
                                  const char *aURL, uint32_t aLineNo,
                                  uint32_t aVersion,
+                                 bool aIsXBL,
                                  nsScriptObjectHolder<JSObject>& aHandler)
 {
   NS_ENSURE_TRUE(mIsInitialized, NS_ERROR_NOT_INITIALIZED);
 
   NS_PRECONDITION(AtomIsEventHandlerName(aName), "Bad event name");
   NS_PRECONDITION(!::JS_IsExceptionPending(mContext),
                   "Why are we being called with a pending exception?");
 
@@ -1768,32 +1770,38 @@ nsJSContext::CompileEventHandler(nsIAtom
                                         aArgCount, aArgNames,
                                         PromiseFlatString(aBody).get(), aBody.Length());
 
   if (!fun) {
     ReportPendingException();
     return NS_ERROR_ILLEGAL_VALUE;
   }
 
+  // If this is an XBL function, make a note to that effect on its script.
+  if (aIsXBL) {
+    JS_SetScriptUserBit(JS_GetFunctionScript(mContext, fun), true);
+  }
+
   JSObject *handler = ::JS_GetFunctionObject(fun);
   return aHandler.set(handler);
 }
 
 // XXX - note that CompileFunction doesn't yet play the nsScriptObjectHolder
 // game - caller must still ensure JS GC root.
 nsresult
 nsJSContext::CompileFunction(JSObject* aTarget,
                              const nsACString& aName,
                              uint32_t aArgCount,
                              const char** aArgArray,
                              const nsAString& aBody,
                              const char* aURL,
                              uint32_t aLineNo,
                              uint32_t aVersion,
                              bool aShared,
+                             bool aIsXBL,
                              JSObject** aFunctionObject)
 {
   NS_ABORT_IF_FALSE(aFunctionObject,
     "Shouldn't call CompileFunction with null return value.");
 
   NS_ENSURE_TRUE(mIsInitialized, NS_ERROR_NOT_INITIALIZED);
 
   // Don't compile if aVersion is unknown.  Since the caller is responsible for
@@ -1827,16 +1835,21 @@ nsJSContext::CompileFunction(JSObject* a
   JSFunction* fun = JS::CompileFunction(mContext, target,
                                         options, PromiseFlatCString(aName).get(),
                                         aArgCount, aArgArray,
                                         PromiseFlatString(aBody).get(), aBody.Length());
 
   if (!fun)
     return NS_ERROR_FAILURE;
 
+  // If this is an XBL function, make a note to that effect on its script.
+  if (aIsXBL) {
+    JS_SetScriptUserBit(JS_GetFunctionScript(mContext, fun), true);
+  }
+
   *aFunctionObject = JS_GetFunctionObject(fun);
   return NS_OK;
 }
 
 nsresult
 nsJSContext::CallEventHandler(nsISupports* aTarget, JSObject* aScope,
                               JSObject* aHandler, nsIArray* aargv,
                               nsIVariant** arv)
--- a/dom/base/nsJSEnvironment.h
+++ b/dom/base/nsJSEnvironment.h
@@ -80,16 +80,17 @@ public:
                                  bool* aIsUndefined);
 
   virtual nsresult CompileEventHandler(nsIAtom *aName,
                                        uint32_t aArgCount,
                                        const char** aArgNames,
                                        const nsAString& aBody,
                                        const char *aURL, uint32_t aLineNo,
                                        uint32_t aVersion,
+                                       bool aIsXBL,
                                        nsScriptObjectHolder<JSObject>& aHandler);
   virtual nsresult CallEventHandler(nsISupports* aTarget, JSObject* aScope,
                                     JSObject* aHandler,
                                     nsIArray *argv, nsIVariant **rv);
   virtual nsresult BindCompiledEventHandler(nsISupports *aTarget,
                                             JSObject *aScope,
                                             JSObject* aHandler,
                                             nsScriptObjectHolder<JSObject>& aBoundHandler);
@@ -97,16 +98,17 @@ public:
                                    const nsACString& aName,
                                    uint32_t aArgCount,
                                    const char** aArgArray,
                                    const nsAString& aBody,
                                    const char* aURL,
                                    uint32_t aLineNo,
                                    uint32_t aVersion,
                                    bool aShared,
+                                   bool aIsXBL,
                                    JSObject** aFunctionObject);
 
   virtual nsIScriptGlobalObject *GetGlobalObject();
   inline nsIScriptGlobalObject *GetGlobalObjectRef() { return mGlobalObjectRef; };
 
   virtual JSContext* GetNativeContext();
   virtual JSObject* GetNativeGlobal();
   virtual nsresult InitContext();
--- a/js/src/jsdbgapi.cpp
+++ b/js/src/jsdbgapi.cpp
@@ -694,16 +694,28 @@ JS_GetScriptLineExtent(JSContext *cx, JS
 }
 
 JS_PUBLIC_API(JSVersion)
 JS_GetScriptVersion(JSContext *cx, JSScript *script)
 {
     return VersionNumber(script->getVersion());
 }
 
+JS_PUBLIC_API(bool)
+JS_GetScriptUserBit(JSScript *script)
+{
+    return script->userBit;
+}
+
+JS_PUBLIC_API(void)
+JS_SetScriptUserBit(JSScript *script, bool b)
+{
+    script->userBit = b;
+}
+
 /***************************************************************************/
 
 JS_PUBLIC_API(void)
 JS_SetNewScriptHook(JSRuntime *rt, JSNewScriptHook hook, void *callerdata)
 {
     rt->debugHooks.newScriptHook = hook;
     rt->debugHooks.newScriptHookData = callerdata;
 }
--- a/js/src/jsdbgapi.h
+++ b/js/src/jsdbgapi.h
@@ -287,16 +287,22 @@ extern JS_PUBLIC_API(unsigned)
 JS_GetScriptBaseLineNumber(JSContext *cx, JSScript *script);
 
 extern JS_PUBLIC_API(unsigned)
 JS_GetScriptLineExtent(JSContext *cx, JSScript *script);
 
 extern JS_PUBLIC_API(JSVersion)
 JS_GetScriptVersion(JSContext *cx, JSScript *script);
 
+extern JS_PUBLIC_API(bool)
+JS_GetScriptUserBit(JSScript *script);
+
+extern JS_PUBLIC_API(void)
+JS_SetScriptUserBit(JSScript *script, bool b);
+
 /************************************************************************/
 
 /*
  * Hook setters for script creation and destruction, see jsprvtd.h for the
  * typedefs.  These macros provide binary compatibility and newer, shorter
  * synonyms.
  */
 #define JS_SetNewScriptHook     JS_SetNewScriptHookProc
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -2200,16 +2200,17 @@ js::CloneScript(JSContext *cx, HandleObj
     dst->strictModeCode = src->strictModeCode;
     dst->explicitUseStrict = src->explicitUseStrict;
     dst->bindingsAccessedDynamically = src->bindingsAccessedDynamically;
     dst->funHasExtensibleScope = src->funHasExtensibleScope;
     dst->funHasAnyAliasedFormal = src->funHasAnyAliasedFormal;
     dst->hasSingletons = src->hasSingletons;
     dst->isGenerator = src->isGenerator;
     dst->isGeneratorExp = src->isGeneratorExp;
+    dst->userBit = src->userBit;
 
     /*
      * initScriptCounts updates scriptCountsMap if necessary. The other script
      * maps in JSCompartment are populated lazily.
      */
     if (cx->hasRunOption(JSOPTION_PCCOUNT))
         (void) dst->initScriptCounts(cx);
 
--- a/js/src/jsscript.h
+++ b/js/src/jsscript.h
@@ -477,16 +477,17 @@ struct JSScript : public js::gc::Cell
     bool            isGenerator:1;    /* is a generator */
     bool            isGeneratorExp:1; /* is a generator expression */
     bool            hasScriptCounts:1;/* script has an entry in
                                          JSCompartment::scriptCountsMap */
     bool            hasDebugScript:1; /* script has an entry in
                                          JSCompartment::debugScriptMap */
     bool            hasFreezeConstraints:1; /* freeze constraints for stack
                                              * type sets have been generated */
+    bool            userBit:1; /* Opaque, used by the embedding. */
 
   private:
     /* See comments below. */
     bool            argsHasVarBinding_:1;
     bool            needsArgsAnalysis_:1;
     bool            needsArgsObj_:1;
 
     //
--- a/js/xpconnect/wrappers/AccessCheck.cpp
+++ b/js/xpconnect/wrappers/AccessCheck.cpp
@@ -253,16 +253,25 @@ AccessCheck::isCrossOriginAccessPermitte
         if (IsPermitted(name, JSID_TO_FLAT_STRING(id), act == Wrapper::SET))
             return true;
     }
 
     return IsWindow(name) && IsFrameId(cx, obj, id);
 }
 
 bool
+AccessCheck::callerIsXBL(JSContext *cx)
+{
+    JSScript *script;
+    if (!JS_DescribeScriptedCaller(cx, &script, nullptr) || !script)
+        return false;
+    return JS_GetScriptUserBit(script);
+}
+
+bool
 AccessCheck::isSystemOnlyAccessPermitted(JSContext *cx)
 {
     MOZ_ASSERT(cx == nsContentUtils::GetCurrentJSContext());
     if (callerIsChrome())
         return true;
 
     // Allow any code loaded from chrome://global/ to touch us, even if it was
     // cloned into a less privileged context.
--- a/js/xpconnect/wrappers/AccessCheck.h
+++ b/js/xpconnect/wrappers/AccessCheck.h
@@ -22,16 +22,17 @@ class AccessCheck {
     static bool wrapperSubsumes(JSObject *wrapper);
     static bool subsumesIgnoringDomain(JSCompartment *a, JSCompartment *b);
     static bool isChrome(JSCompartment *compartment);
     static bool isChrome(JSObject *obj);
     static bool callerIsChrome();
     static nsIPrincipal *getPrincipal(JSCompartment *compartment);
     static bool isCrossOriginAccessPermitted(JSContext *cx, JSObject *obj, jsid id,
                                              js::Wrapper::Action act);
+    static bool callerIsXBL(JSContext *cx);
     static bool isSystemOnlyAccessPermitted(JSContext *cx);
     static bool isLocationObjectSameOrigin(JSContext *cx, JSObject *wrapper);
 
     static bool needsSystemOnlyWrapper(JSObject *obj);
 
     static bool isScriptAccessOnly(JSContext *cx, JSObject *wrapper);
 
     static void deny(JSContext *cx, jsid id);