Bug 911864 - Only expose XBL members which have the exposeToUntrustedContent attribute set. r=smaug
authorBobby Holley <bobbyholley@gmail.com>
Fri, 01 Nov 2013 15:31:58 +0100
changeset 153066 2662a96f83ef7aa73a4ed44476f86a8a284d8244
parent 153065 8a56460b9110deccc90e14e79cb56eaaac337d2b
child 153067 fa28da03e7d9fde3c52e9c6d64f53bb1a65875e2
push id25566
push userryanvm@gmail.com
push dateFri, 01 Nov 2013 18:40:05 +0000
treeherdermozilla-central@5bb07c1ae9f5 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs911864
milestone28.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 911864 - Only expose XBL members which have the exposeToUntrustedContent attribute set. r=smaug
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" />