Bug 911864 - Only expose XBL members which have the exposeToUntrustedContent attribute set. r=smaug, a=bajaj
authorBobby Holley <bobbyholley@gmail.com>
Fri, 01 Nov 2013 15:31:58 +0100
changeset 161305 48545fba1c3c1e357b2a993250a60d9f10be333e
parent 161304 efe11f1a745210be3d3d458b38a6f73e827af6c8
child 161306 9e1c21d8987c4879999c25a676ff06c7a8d642de
push id4600
push userryanvm@gmail.com
push dateTue, 12 Nov 2013 17:09:20 +0000
treeherdermozilla-aurora@9e1c21d8987c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug, bajaj
bugs911864
milestone27.0a2
Bug 911864 - Only expose XBL members which have the exposeToUntrustedContent attribute set. r=smaug, a=bajaj
content/xbl/src/nsXBLProtoImpl.cpp
content/xbl/test/file_bug821850.xhtml
--- a/content/xbl/src/nsXBLProtoImpl.cpp
+++ b/content/xbl/src/nsXBLProtoImpl.cpp
@@ -15,16 +15,17 @@
 #include "nsIXPConnect.h"
 #include "nsIServiceManager.h"
 #include "nsIDOMNode.h"
 #include "nsXBLPrototypeBinding.h"
 #include "nsXBLProtoImplProperty.h"
 #include "nsIURI.h"
 #include "mozilla/dom/XULElementBinding.h"
 #include "xpcpublic.h"
+#include "js/CharacterEncoding.h"
 
 using namespace mozilla;
 using js::GetGlobalForObjectCrossCompartment;
 using js::AssertSameCompartment;
 
 nsresult
 nsXBLProtoImpl::InstallImplementation(nsXBLPrototypeBinding* aPrototypeBinding,
                                       nsXBLBinding* aBinding)
@@ -111,24 +112,32 @@ nsXBLProtoImpl::InstallImplementation(ns
        curr;
        curr = curr->GetNext())
     curr->InstallMember(cx, propertyHolder);
 
   // From here on out, work in the scope of the bound element.
   JSAutoCompartment ac2(cx, targetClassObject);
 
   // Now, if we're using a separate XBL scope, enter the compartment of the
-  // bound node and copy the properties to the prototype there. This rewraps
-  // them appropriately, which should result in cross-compartment function
-  // wrappers.
+  // bound node and copy exposable properties to the prototype there. This
+  // rewraps them appropriately, which should result in cross-compartment
+  // function wrappers.
   if (propertyHolder != targetClassObject) {
     AssertSameCompartment(propertyHolder, scopeObject);
     AssertSameCompartment(targetClassObject, globalObject);
-    bool ok = JS_CopyPropertiesFrom(cx, targetClassObject, propertyHolder);
-    NS_ENSURE_TRUE(ok, NS_ERROR_UNEXPECTED);
+    for (nsXBLProtoImplMember* curr = mMembers; curr; curr = curr->GetNext()) {
+      if (curr->ShouldExposeToUntrustedContent()) {
+        JS::Rooted<jsid> id(cx);
+        JS::TwoByteChars chars(curr->GetName(), NS_strlen(curr->GetName()));
+        bool ok = JS_CharsToId(cx, chars, &id);
+        NS_ENSURE_TRUE(ok, NS_ERROR_UNEXPECTED);
+        JS_CopyPropertyFrom(cx, id, targetClassObject, propertyHolder);
+        NS_ENSURE_TRUE(ok, NS_ERROR_UNEXPECTED);
+      }
+    }
   }
 
   // Install all of our field accessors.
   for (nsXBLProtoImplField* curr = mFields;
        curr;
        curr = curr->GetNext())
     curr->InstallAccessors(cx, targetClassObject);
 
--- a/content/xbl/test/file_bug821850.xhtml
+++ b/content/xbl/test/file_bug821850.xhtml
@@ -38,16 +38,26 @@ https://bugzilla.mozilla.org/show_bug.cg
 
           var bound = document.getElementById('bound');
           ok(bound, "bound is non-null");
           is(bound.method('baz'), "method:baz", "Xray methods work");
           is(bound.prop, "propVal", "Property Xrays work");
           is(bound.primitiveField, undefined, "Xrays don't show fields");
           is(bound.wrappedJSObject.primitiveField, 2, "Waiving Xrays show fields");
 
+          // Check exposure behavior.
+          is(typeof bound.unexposedMethod, 'function',
+             "Unexposed method should be visible to XBL");
+          is(typeof bound.wrappedJSObject.unexposedMethod, 'undefined',
+             "Unexposed method should not be defined in content");
+          is(typeof bound.unexposedProperty, 'number',
+             "Unexposed property should be visible to XBL");
+          is(typeof bound.wrappedJSObject.unexposedProperty, 'undefined',
+             "Unexposed property should not be defined in content");
+
           // Check that here document.QueryInterface works
           ok("QueryInterface" in document,
              "Should have a document.QueryInterface here");
           is(document.QueryInterface(Components.interfaces.nsIDOMDocument),
              document, "Should be able to QI the document");
 
           // This gets invoked by an event handler.
           window.finish = function() {
@@ -60,16 +70,18 @@ https://bugzilla.mozilla.org/show_bug.cg
 
             SimpleTest.finish();
           }
 
           // Hand things off to content. Content will call us back.
           win.go();
         </constructor>
         <field name="primitiveField">2</field>
+        <method name="unexposedMethod"><body></body></method>
+        <property name="unexposedProperty" onget="return 2;" readonly="true"></property>
         <method name="method" exposeToUntrustedContent="true">
           <parameter name="arg" />
           <body>
             return "method:" + arg;
           </body>
         </method>
         <method name="passMeAJSObject" exposeToUntrustedContent="true">
           <parameter name="arg" />