Backed out changeset 86128d3eac88 (bug 916939) for breaking the web. r=me
authorBobby Holley <bobbyholley@gmail.com>
Fri, 20 Sep 2013 10:32:32 -0700
changeset 148116 db5f948bbb133854a71c5c76250b26a3cd6d55f5
parent 148115 7cd26d910cc2e70499a70f878f9d6171b6c1a039
child 148117 32025f35568ff66c0c9cdbc204854bbd6d633e86
push id34109
push userbobbyholley@gmail.com
push dateFri, 20 Sep 2013 17:33:29 +0000
treeherdermozilla-inbound@db5f948bbb13 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersme
bugs916939
milestone27.0a1
backs out86128d3eac885dc034eae05f4e8974006fe712e5
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
Backed out changeset 86128d3eac88 (bug 916939) for breaking the web. r=me
docshell/test/navigation/NavigationUtils.js
docshell/test/navigation/test_bug13871.html
docshell/test/navigation/test_grandchild.html
docshell/test/navigation/test_sibling-off-domain.html
dom/tests/mochitest/bugs/iframe_bug440572.html
dom/tests/mochitest/bugs/test_bug850517.html
dom/tests/mochitest/whatwg/postMessage_onOther.html
js/xpconnect/tests/mochitest/test_sameOriginPolicy.html
js/xpconnect/wrappers/AccessCheck.cpp
--- a/docshell/test/navigation/NavigationUtils.js
+++ b/docshell/test/navigation/NavigationUtils.js
@@ -88,20 +88,16 @@ function isInaccessible(wnd, message) {
   try {
     wnd.document.body.innerHTML;
     ok(false, message);
   } catch(ex) {
     ok(true, message);
   }
 }
 
-function getSubframe(win, i) {
-  return SpecialPowers.unwrap(SpecialPowers.wrap(win)[i]);
-}
-
 ///////////////////////////////////////////////////////////////////////////
 // Functions that require UniversalXPConnect privilege
 ///////////////////////////////////////////////////////////////////////////
 
 function xpcEnumerateContentWindows(callback) {
 
   var Ci = SpecialPowers.Ci;
   var ww = SpecialPowers.Cc["@mozilla.org/embedcomp/window-watcher;1"]
--- a/docshell/test/navigation/test_bug13871.html
+++ b/docshell/test/navigation/test_bug13871.html
@@ -4,28 +4,27 @@
     <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>        
     <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
     <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
     <script type="text/javascript" src="NavigationUtils.js"></script>        
     <style type="text/css">
       iframe { width: 90%; height: 50px; }
     </style>
 <script>
-
 window.onload = function () {
-  navigateByLocation(getSubframe(window0, 0));
+  navigateByLocation(window0.frames[0]);
   navigateByOpen("window1_child0");
   navigateByForm("window2_child0");
   navigateByHyperlink("window3_child0");
 
   xpcWaitForFinishedFrames(function() {
-    isInaccessible(getSubframe(window0, 0), "Should not be able to navigate off-domain frame by setting location.");
-    isInaccessible(getSubframe(window1, 0), "Should not be able to navigate off-domain frame by calling window.open.");
-    isInaccessible(getSubframe(window2, 0), "Should not be able to navigate off-domain frame by submitting form.");
-    isInaccessible(getSubframe(window3, 0), "Should not be able to navigate off-domain frame by targeted hyperlink.");
+    isInaccessible(window0.frames[0], "Should not be able to navigate off-domain frame by setting location.");
+    isInaccessible(window1.frames[0], "Should not be able to navigate off-domain frame by calling window.open.");
+    isInaccessible(window2.frames[0], "Should not be able to navigate off-domain frame by submitting form.");
+    isInaccessible(window3.frames[0], "Should not be able to navigate off-domain frame by targeted hyperlink.");
 
     window0.close();
     window1.close();
     window2.close();
     window3.close();
 
     xpcCleanupWindows();
     SimpleTest.finish();
--- a/docshell/test/navigation/test_grandchild.html
+++ b/docshell/test/navigation/test_grandchild.html
@@ -9,26 +9,26 @@
       iframe { width: 90%; height: 200px; }
     </style>
 <script>
 if (!navigator.platform.startsWith("Win")) {
   SimpleTest.expectAssertions(0, 1);
 }
 
 window.onload = function () {
-  navigateByLocation(getSubframe(getSubframe(frames, 0), 0));
+  navigateByLocation(frames[0].frames[0]);
   navigateByOpen("child1_child0");
   navigateByForm("child2_child0");
   navigateByHyperlink("child3_child0");
 
   xpcWaitForFinishedFrames(function() {
-    isNavigated(getSubframe(getSubframe(frames, 0), 0), "Should be able to navigate off-domain grandchild by setting location.");
-    isNavigated(getSubframe(getSubframe(frames, 1), 0), "Should be able to navigate off-domain grandchild by calling window.open.");
-    isNavigated(getSubframe(getSubframe(frames, 2), 0), "Should be able to navigate off-domain grandchild by submitting form.");
-    isNavigated(getSubframe(getSubframe(frames, 3), 0), "Should be able to navigate off-domain grandchild by targeted hyperlink.");
+    isNavigated(frames[0].frames[0], "Should be able to navigate off-domain grandchild by setting location.");
+    isNavigated(frames[1].frames[0], "Should be able to navigate off-domain grandchild by calling window.open.");
+    isNavigated(frames[2].frames[0], "Should be able to navigate off-domain grandchild by submitting form.");
+    isNavigated(frames[3].frames[0], "Should be able to navigate off-domain grandchild by targeted hyperlink.");
 
     xpcCleanupWindows();
     SimpleTest.finish();
   }, 4);
 }
 </script>
 </head>
 <body>
--- a/docshell/test/navigation/test_sibling-off-domain.html
+++ b/docshell/test/navigation/test_sibling-off-domain.html
@@ -6,17 +6,17 @@
     <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
     <script type="text/javascript" src="NavigationUtils.js"></script>        
     <style type="text/css">
       iframe { width: 90%; height: 50px; }
     </style>
 <script>
 window.onload = function () {
   document.getElementById('active').innerHTML =
-      '<iframe src="http://test1.example.org:80/tests/docshell/test/navigation/navigate.html#SpecialPowers.unwrap(SpecialPowers.wrap(parent).frames[0]),location"></iframe>' +
+      '<iframe src="http://test1.example.org:80/tests/docshell/test/navigation/navigate.html#parent.frames[0],location"></iframe>' +
       '<iframe src="http://test1.example.org:80/tests/docshell/test/navigation/navigate.html#child1,open"></iframe>' +
       '<iframe src="http://test1.example.org:80/tests/docshell/test/navigation/navigate.html#child2,form"></iframe>' +
       '<iframe src="http://test1.example.org:80/tests/docshell/test/navigation/navigate.html#child3,hyperlink"></iframe>';
 
   xpcWaitForFinishedFrames(function() {
     isBlank(frames[0], "Should not be able to navigate off-domain sibling by setting location.");
     isBlank(frames[1], "Should not be able to navigate off-domain sibling by calling window.open.");
     isBlank(frames[2], "Should not be able to navigate off-domain sibling by submitting form.");
--- a/dom/tests/mochitest/bugs/iframe_bug440572.html
+++ b/dom/tests/mochitest/bugs/iframe_bug440572.html
@@ -1,16 +1,16 @@
 <html>
 <body>
 <script>
 
 var success = 0;
 
 try {
-  SpecialPowers.unwrap(SpecialPowers.wrap(parent)[name]).success = 1;
+  parent[name].success = 1;
 } catch (e) {
   parent.postMessage(e, "http://mochi.test:8888");
 }
 
 parent.postMessage(success ? "success" : "failure", "http://mochi.test:8888");
 </script>
 <p>Move on, nothing to see here...</p>
 </body>
--- a/dom/tests/mochitest/bugs/test_bug850517.html
+++ b/dom/tests/mochitest/bugs/test_bug850517.html
@@ -11,27 +11,28 @@ https://bugzilla.mozilla.org/show_bug.cg
   <script type="application/javascript">
 
   /** Test for live updating of named child resolution. **/
   SimpleTest.waitForExplicitFinish();
 
   function go() {
     var ifrA = $('a');
     var ifrB = $('b');
-    var sb = new SpecialPowers.Cu.Sandbox(SpecialPowers.Services.scriptSecurityManager.getSystemPrincipal());
+    var sb = new SpecialPowers.Cu.Sandbox('http://www.example.com');
     sb.win = window;
     sb.childA = ifrA.contentWindow;
     sb.childB = ifrB.contentWindow;
     sb.is = is;
     sb.ok = ok;
     is(window.theoneandonly.frameElement, ifrA, "Named child resolution works");
     SpecialPowers.Cu.evalInSandbox('is(win.theoneandonly, childA, "Named child resolution works via Xray");', sb);
     ifrA.removeAttribute('name');
     is(typeof window.theoneandonly, 'undefined', "Revocation works");
-    SpecialPowers.Cu.evalInSandbox('is(typeof win.theoneandonly, "undefined", "Revocation works via Xray");', sb);
+    SpecialPowers.Cu.evalInSandbox('try { win.theoneandonly; ok(false, "Should have thrown"); } ' +
+                                   'catch (e) {ok(!!/denied/.exec(e) && !!/theoneandonly/.exec(e), "Revocation works via Xray");};', sb);
     ifrB.setAttribute('name', 'theoneandonly');
     is(window.theoneandonly.frameElement, ifrB, "Another mule kicking in the same old stall");
     SpecialPowers.Cu.evalInSandbox('is(win.theoneandonly, childB, "Another mule via Xray");', sb);
     SimpleTest.finish();
   }
 
   </script>
 </head>
--- a/dom/tests/mochitest/whatwg/postMessage_onOther.html
+++ b/dom/tests/mochitest/whatwg/postMessage_onOther.html
@@ -45,55 +45,52 @@
     //   http://test1.example.com
     //
     // and not
     //
     //   http://example.com
 
     function receiveSubDomain(evt)
     {
-      var topframe =
-        SpecialPowers.unwrap(SpecialPowers.wrap(window).parent.topDomainFrame);
       if (evt.origin !== "http://mochi.test:8888")
       {
         fail("wrong top-domain origin: " + evt.origin);
         return;
       }
       if (evt.data !== "start-test")
       {
         fail("wrong top-domain message: " + evt.origin);
         return;
       }
 
       document.domain = "example.com";
-      topframe.postMessage("domain-switch", "http://example.com");
+      window.parent.topDomainFrame.postMessage("domain-switch",
+                                               "http://example.com");
     }
     
     function receiveTopDomain(evt)
     {
-      var subframe =
-        SpecialPowers.unwrap(SpecialPowers.wrap(window).parent.subDomainFrame);
       if (evt.origin !== "http://test1.example.com")
       {
         fail("wrong subdomain origin: " + evt.origin);
         return;
       }
       if (evt.data !== "domain-switch")
       {
         fail("wrong subdomain message: " + evt.origin);
         return;
       }
-      if (evt.source !== subframe)
+      if (evt.source !== window.parent.subDomainFrame)
       {
         fail("wrong source on message from subdomain");
         return;
       }
 
       document.domain = "example.com";
-      subframe.testSiblingPostMessage();
+      window.parent.subDomainFrame.testSiblingPostMessage();
     }
 
     function testSiblingPostMessage()
     {
       window.parent.postMessage("test-finished", "http://mochi.test:8888");
     }
 
     function setup()
--- a/js/xpconnect/tests/mochitest/test_sameOriginPolicy.html
+++ b/js/xpconnect/tests/mochitest/test_sameOriginPolicy.html
@@ -35,17 +35,19 @@ function check(obj, prop, allowed, write
     accessed = true;
   } catch (e) {}
   is(accessed, allowed, prop + " is correctly (in)accessible for " + (write ? 'write' : 'read'));
 }
 
 var crossOriginReadableWindowProps = ['blur', 'close', 'closed', 'focus',
                                       'frames', 'location', 'length',
                                       'opener', 'parent', 'postMessage',
-                                      'self', 'top', 'window'];
+                                      'self', 'top', 'window',
+                                      /* indexed and named accessors */
+                                      '0', 'subframe'];
 
 function isCrossOriginReadable(obj, prop) {
   if (obj == "Window")
     return crossOriginReadableWindowProps.indexOf(prop) != -1;
   if (obj == "Location")
     return prop == 'replace';
   return false;
 }
--- a/js/xpconnect/wrappers/AccessCheck.cpp
+++ b/js/xpconnect/wrappers/AccessCheck.cpp
@@ -160,16 +160,59 @@ IsPermitted(const char *name, JSFlatStri
     return false;
 }
 
 #undef NAME
 #undef RW
 #undef R
 #undef W
 
+static bool
+IsFrameId(JSContext *cx, JSObject *objArg, jsid idArg)
+{
+    RootedObject obj(cx, objArg);
+    RootedId id(cx, idArg);
+
+    obj = JS_ObjectToInnerObject(cx, obj);
+    MOZ_ASSERT(!js::IsWrapper(obj));
+    XPCWrappedNative *wn = IS_WN_REFLECTOR(obj) ? XPCWrappedNative::Get(obj)
+                                                : nullptr;
+    if (!wn) {
+        return false;
+    }
+
+    nsCOMPtr<nsIDOMWindow> domwin(do_QueryWrappedNative(wn));
+    if (!domwin) {
+        return false;
+    }
+
+    nsCOMPtr<nsIDOMWindowCollection> col;
+    domwin->GetFrames(getter_AddRefs(col));
+    if (!col) {
+        return false;
+    }
+
+    if (JSID_IS_INT(id)) {
+        col->Item(JSID_TO_INT(id), getter_AddRefs(domwin));
+    } else if (JSID_IS_STRING(id)) {
+        nsAutoString str(JS_GetInternedStringChars(JSID_TO_STRING(id)));
+        col->NamedItem(str, getter_AddRefs(domwin));
+    } else {
+        return false;
+    }
+
+    return domwin != nullptr;
+}
+
+static bool
+IsWindow(const char *name)
+{
+    return name[0] == 'W' && !strcmp(name, "Window");
+}
+
 bool
 AccessCheck::isCrossOriginAccessPermitted(JSContext *cx, JSObject *wrapperArg, jsid idArg,
                                           Wrapper::Action act)
 {
     if (!XPCWrapper::GetSecurityManager())
         return true;
 
     if (act == Wrapper::CALL)
@@ -195,16 +238,32 @@ AccessCheck::isCrossOriginAccessPermitte
     else
         name = clasp->name;
 
     if (JSID_IS_STRING(id)) {
         if (IsPermitted(name, JSID_TO_FLAT_STRING(id), act == Wrapper::SET))
             return true;
     }
 
+    if (act != Wrapper::GET)
+        return false;
+
+    // Check for frame IDs. If we're resolving named frames, make sure to only
+    // resolve ones that don't shadow native properties. See bug 860494.
+    if (IsWindow(name)) {
+        if (JSID_IS_STRING(id) && !XrayUtils::IsXrayResolving(cx, wrapper, id)) {
+            bool wouldShadow = false;
+            if (!XrayUtils::HasNativeProperty(cx, wrapper, id, &wouldShadow) ||
+                wouldShadow)
+            {
+                return false;
+            }
+        }
+        return IsFrameId(cx, obj, id);
+    }
     return false;
 }
 
 bool
 AccessCheck::needsSystemOnlyWrapper(JSObject *obj)
 {
     JSObject* wrapper = obj;
     if (dom::GetSameCompartmentWrapperForDOMBinding(wrapper))