Bug 1040181 - Use an opaque wrapper rather than failing in Rewrap. r=gabor
authorBobby Holley <bobbyholley@gmail.com>
Sun, 20 Jul 2014 10:03:58 -0600
changeset 217118 6fb5b8d67c005acef313d3f91f2cf1d6414976e5
parent 217117 333460ebc613fb2cac809e8ea8a85a9eff0a515b
child 217119 df134a5be8fb86a29813c7c403e1106b3faa5bba
push id515
push userraliiev@mozilla.com
push dateMon, 06 Oct 2014 12:51:51 +0000
treeherdermozilla-release@267c7a481bef [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgabor
bugs1040181
milestone33.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 1040181 - Use an opaque wrapper rather than failing in Rewrap. r=gabor
js/xpconnect/tests/chrome/test_documentdomain.xul
js/xpconnect/tests/mochitest/file_documentdomain.html
js/xpconnect/tests/unit/test_bug976151.js
js/xpconnect/wrappers/WrapperFactory.cpp
--- a/js/xpconnect/tests/chrome/test_documentdomain.xul
+++ b/js/xpconnect/tests/chrome/test_documentdomain.xul
@@ -14,16 +14,17 @@ https://bugzilla.mozilla.org/show_bug.cg
      target="_blank">Mozilla Bug 601277</a>
   </body>
 
   <!-- test code goes here -->
   <script type="application/javascript">
   <![CDATA[
   /** Tests for document.domain. **/
 
+  const Cu = Components.utils;
   SimpleTest.waitForExplicitFinish();
 
   // Wait for the frames to load.
   var gFramesLoaded = 0;
   function frameLoaded() {
     gFramesLoaded++;
     if (gFramesLoaded == document.getElementsByTagName('iframe').length)
       startTest();
@@ -45,26 +46,32 @@ https://bugzilla.mozilla.org/show_bug.cg
        "Cross-origin windows should not grant access");
     ok(!win1A.tryToAccess(winBase),
        "Subdomain windows should not receive access");
 
     // Store references now, while test1A and test1B are same-origin.
     win1A.storeReference(win1B);
     win1B.storeReference(win1A);
     ok(win1A.tryToAccessStored(), "Stored references work when same-origin");
+    win1A.evalFromB = Cu.unwaiveXrays(win1B.eval); // Crashtest for bug 1040181.
+    win1B.functionFromA = Cu.unwaiveXrays(win1A.Function); // Crashtest for bug 1040181.
+    ok(!win1A.invokingFunctionThrowsSecurityException('evalFromB'), "Should allow before document.domain");
+    ok(!win1B.invokingFunctionThrowsSecurityException('functionFromA'), "Should allow before document.domain");
 
     // Set document.domain on test1A. This should grant no access, since nobody
     // else set it.
     win1A.setDomain('example.org');
     ok(!win1A.tryToAccess(winBase), "base must collaborate too");
     ok(!winBase.tryToAccess(win1A), "base must collaborate too");
     ok(!win1A.tryToAccess(win1B), "No longer same-origin");
     ok(!win1A.tryToAccessStored(), "No longer same-origin");
     ok(!win1B.tryToAccess(win1A), "No longer same-origin");
     ok(!win1B.tryToAccessStored(), "No longer same-origin");
+    ok(win1A.invokingFunctionThrowsSecurityException('evalFromB'), "No longer same-origin");
+    ok(win1B.invokingFunctionThrowsSecurityException('functionFromA'), "No longer same-origin");
 
     // Set document.domain on test1B. Now we're cooking with gas.
     win1B.setDomain('example.org');
     ok(!win1B.tryToAccess(winBase), "base must collaborate too");
     ok(!winBase.tryToAccess(win1B), "base must collaborate too");
     ok(win1A.tryToAccess(win1B), "same-origin");
     ok(win1A.tryToAccessStored(), "same-origin");
     ok(win1B.tryToAccess(win1A), "same-origin");
--- a/js/xpconnect/tests/mochitest/file_documentdomain.html
+++ b/js/xpconnect/tests/mochitest/file_documentdomain.html
@@ -20,15 +20,22 @@
   }
 
   function tryToAccessStored() {
     try {
       return /Better Late/.exec(gRef.innerHTML);
     } catch (e) { return false; }
   }
 
+  function invokingFunctionThrowsSecurityException(name) {
+    try {
+      window[name]();
+      return false;
+    } catch (e) { return /insecure|denied/.test(e); }
+  }
+
 
 </script>
 </head>
 <body>
 <span id="foo">Better Late than Never</span>
 </body>
 </html>
--- a/js/xpconnect/tests/unit/test_bug976151.js
+++ b/js/xpconnect/tests/unit/test_bug976151.js
@@ -1,24 +1,24 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 const Cu = Components.utils;
 function run_test() {
   let unprivilegedSb = new Cu.Sandbox('http://www.example.com');
-  function checkCantWrap(val) {
+  function checkOpaqueWrapper(val) {
+    unprivilegedSb.prop = val;
     try {
-      unprivilegedSb.prop = val;
-      do_check_true(false);
+      Cu.evalInSandbox('prop();', sb);
     } catch (e) {
       do_check_true(/denied|insecure|/.test(e));
     }
   }
   let xoSb = new Cu.Sandbox('http://www.example.net');
   let epSb = new Cu.Sandbox(['http://www.example.com']);
-  checkCantWrap(eval);
-  checkCantWrap(xoSb.eval);
-  checkCantWrap(epSb.eval);
-  checkCantWrap(Function);
-  checkCantWrap(xoSb.Function);
-  checkCantWrap(epSb.Function);
+  checkOpaqueWrapper(eval);
+  checkOpaqueWrapper(xoSb.eval);
+  checkOpaqueWrapper(epSb.eval);
+  checkOpaqueWrapper(Function);
+  checkOpaqueWrapper(xoSb.Function);
+  checkOpaqueWrapper(epSb.Function);
 }
--- a/js/xpconnect/wrappers/WrapperFactory.cpp
+++ b/js/xpconnect/wrappers/WrapperFactory.cpp
@@ -520,21 +520,20 @@ WrapperFactory::Rewrap(JSContext *cx, Ha
         // then we try to "upgrade" the wrapper to an interposing one.
         if (CompartmentPrivate::Get(target)->scope->HasInterposition())
             wrapper = SelectAddonWrapper(cx, obj, wrapper);
     }
 
     if (!targetSubsumesOrigin) {
         // Do a belt-and-suspenders check against exposing eval()/Function() to
         // non-subsuming content.
-        JSFunction *fun = JS_GetObjectFunction(obj);
-        if (fun) {
+        if (JSFunction *fun = JS_GetObjectFunction(obj)) {
             if (JS_IsBuiltinEvalFunction(fun) || JS_IsBuiltinFunctionConstructor(fun)) {
-                JS_ReportError(cx, "Permission denied to expose eval or Function to non-subsuming content");
-                return nullptr;
+                NS_WARNING("Trying to expose eval or Function to non-subsuming content!");
+                wrapper = &FilteringWrapper<CrossCompartmentSecurityWrapper, Opaque>::singleton;
             }
         }
     }
 
     DEBUG_CheckUnwrapSafety(obj, wrapper, origin, target);
 
     if (existing)
         return Wrapper::Renew(cx, existing, obj, wrapper);