Bug 911864 - Introduce an explicit opt-in attribute for exposing methods and properties to untrusted content. r=smaug, a=bajaj
authorBobby Holley <bobbyholley@gmail.com>
Fri, 01 Nov 2013 15:31:56 +0100
changeset 167438 ba7bbbeadf7b5660bac8b488e8d1b0498f788e88
parent 167437 601188bdcabf6c3c83ce5a2c91a71dd95719fc33
child 167439 68fdfda73db11b9e4354545b8992aa0099534d84
push id428
push userbbajaj@mozilla.com
push dateTue, 28 Jan 2014 00:16:25 +0000
treeherdermozilla-release@cd72a7ff3a75 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug, bajaj
bugs911864
milestone27.0a2
Bug 911864 - Introduce an explicit opt-in attribute for exposing methods and properties to untrusted content. r=smaug, a=bajaj
content/base/src/nsGkAtomList.h
content/xbl/src/nsXBLContentSink.cpp
content/xbl/src/nsXBLProtoImplMember.h
--- a/content/base/src/nsGkAtomList.h
+++ b/content/base/src/nsGkAtomList.h
@@ -168,16 +168,17 @@ GK_ATOM(charoff, "charoff")
 GK_ATOM(charset, "charset")
 GK_ATOM(checkbox, "checkbox")
 GK_ATOM(checked, "checked")
 GK_ATOM(child, "child")
 GK_ATOM(children, "children")
 GK_ATOM(choose, "choose")
 GK_ATOM(chromemargin, "chromemargin")
 GK_ATOM(chromeOnlyContent, "chromeOnlyContent")
+GK_ATOM(exposeToUntrustedContent, "exposeToUntrustedContent")
 GK_ATOM(circ, "circ")
 GK_ATOM(circle, "circle")
 GK_ATOM(cite, "cite")
 GK_ATOM(_class, "class")
 GK_ATOM(classid, "classid")
 GK_ATOM(clear, "clear")
 GK_ATOM(click, "click")
 GK_ATOM(clickcount, "clickcount")
--- a/content/xbl/src/nsXBLContentSink.cpp
+++ b/content/xbl/src/nsXBLContentSink.cpp
@@ -783,16 +783,17 @@ nsXBLContentSink::ConstructField(const P
 
 void
 nsXBLContentSink::ConstructProperty(const PRUnichar **aAtts, uint32_t aLineNumber)
 {
   const PRUnichar* name     = nullptr;
   const PRUnichar* readonly = nullptr;
   const PRUnichar* onget    = nullptr;
   const PRUnichar* onset    = nullptr;
+  bool exposeToUntrustedContent = false;
 
   nsCOMPtr<nsIAtom> prefix, localName;
   for (; *aAtts; aAtts += 2) {
     int32_t nameSpaceID;
     nsContentUtils::SplitExpatName(aAtts[0], getter_AddRefs(prefix),
                                    getter_AddRefs(localName), &nameSpaceID);
 
     if (nameSpaceID != kNameSpaceID_None) {
@@ -807,36 +808,48 @@ nsXBLContentSink::ConstructProperty(cons
       readonly = aAtts[1];
     }
     else if (localName == nsGkAtoms::onget) {
       onget = aAtts[1];
     }
     else if (localName == nsGkAtoms::onset) {
       onset = aAtts[1];
     }
+    else if (localName == nsGkAtoms::exposeToUntrustedContent &&
+             nsDependentString(aAtts[1]).EqualsLiteral("true"))
+    {
+      exposeToUntrustedContent = true;
+    }
   }
 
   if (name) {
     // All of our pointers are now filled in. Construct our property with all of
     // these parameters.
     mProperty = new nsXBLProtoImplProperty(name, onget, onset, readonly, aLineNumber);
-    if (mProperty) {
-      AddMember(mProperty);
+    if (exposeToUntrustedContent) {
+      mProperty->SetExposeToUntrustedContent(true);
     }
+    AddMember(mProperty);
   }
 }
 
 void
 nsXBLContentSink::ConstructMethod(const PRUnichar **aAtts)
 {
   mMethod = nullptr;
 
   const PRUnichar* name = nullptr;
+  const PRUnichar* expose = nullptr;
   if (FindValue(aAtts, nsGkAtoms::name, &name)) {
     mMethod = new nsXBLProtoImplMethod(name);
+    if (FindValue(aAtts, nsGkAtoms::exposeToUntrustedContent, &expose) &&
+        nsDependentString(expose).EqualsLiteral("true"))
+    {
+      mMethod->SetExposeToUntrustedContent(true);
+    }
   }
 
   if (mMethod) {
     AddMember(mMethod);
   }
 }
 
 void
--- a/content/xbl/src/nsXBLProtoImplMember.h
+++ b/content/xbl/src/nsXBLProtoImplMember.h
@@ -56,24 +56,31 @@ struct nsXBLTextWithLineNumber
   uint32_t GetLineNumber() {
     return mLineNumber;
   }
 };
 
 class nsXBLProtoImplMember
 {
 public:
-  nsXBLProtoImplMember(const PRUnichar* aName) :mNext(nullptr) { mName = ToNewUnicode(nsDependentString(aName)); }
+  nsXBLProtoImplMember(const PRUnichar* aName)
+    : mNext(nullptr)
+    , mExposeToUntrustedContent(false)
+  {
+    mName = ToNewUnicode(nsDependentString(aName));
+  }
   virtual ~nsXBLProtoImplMember() {
     nsMemory::Free(mName);
     NS_CONTENT_DELETE_LIST_MEMBER(nsXBLProtoImplMember, this, mNext);
   }
 
   nsXBLProtoImplMember* GetNext() { return mNext; }
   void SetNext(nsXBLProtoImplMember* aNext) { mNext = aNext; }
+  bool ShouldExposeToUntrustedContent() { return mExposeToUntrustedContent; }
+  void SetExposeToUntrustedContent(bool aExpose) { mExposeToUntrustedContent = aExpose; }
   const PRUnichar* GetName() { return mName; }
 
   virtual nsresult InstallMember(JSContext* aCx,
                                  JS::Handle<JSObject*> aTargetClassObject) = 0;
   virtual nsresult CompileMember(const nsCString& aClassStr,
                                  JS::Handle<JSObject*> aClassObject) = 0;
 
   virtual void Trace(const TraceCallbacks& aCallbacks, void *aClosure) = 0;
@@ -81,11 +88,16 @@ public:
   virtual nsresult Write(nsIObjectOutputStream* aStream)
   {
     return NS_OK;
   }
 
 protected:
   nsXBLProtoImplMember* mNext;  // The members of an implementation are chained.
   PRUnichar* mName;               // The name of the field, method, or property.
+
+  bool mExposeToUntrustedContent; // If this binding is installed on an element
+                                  // in an untrusted scope, should this
+                                  // implementation member be accessible to the
+                                  // content?
 };
 
 #endif // nsXBLProtoImplMember_h__