Named property confusion with __proto__
authorabarth@webkit.org <abarth@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 19 Sep 2011 22:56:22 +0000 (22:56 +0000)
committerabarth@webkit.org <abarth@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 19 Sep 2011 22:56:22 +0000 (22:56 +0000)
https://bugs.webkit.org/show_bug.cgi?id=68221

Reviewed by Eric Seidel.

Source/WebCore:

The __proto__ property is super magical because it's not a real named
property and it has higher precedence than even interceptors.  This
confuses this check, which is meant to detech which names will get
handled by our interceptor.

Test: http/tests/security/window-named-proto.html

* bindings/v8/custom/V8DOMWindowCustom.cpp:
(WebCore::V8DOMWindow::namedSecurityCheck):

LayoutTests:

* http/tests/security/resources/innocent-victim-with-iframe.html: Added.
* http/tests/security/window-named-proto-expected.txt: Added.
* http/tests/security/window-named-proto.html: Added.

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@95488 268f45cc-cd09-0410-ab3c-d52691b4dbfc

LayoutTests/ChangeLog
LayoutTests/http/tests/security/resources/innocent-victim-with-iframe.html [new file with mode: 0644]
LayoutTests/http/tests/security/window-named-proto-expected.txt [new file with mode: 0644]
LayoutTests/http/tests/security/window-named-proto.html [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/bindings/v8/custom/V8DOMWindowCustom.cpp

index 87d349d..c24aeba 100644 (file)
@@ -1,3 +1,14 @@
+2011-09-19  Adam Barth  <abarth@webkit.org>
+
+        Named property confusion with __proto__
+        https://bugs.webkit.org/show_bug.cgi?id=68221
+
+        Reviewed by Eric Seidel.
+
+        * http/tests/security/resources/innocent-victim-with-iframe.html: Added.
+        * http/tests/security/window-named-proto-expected.txt: Added.
+        * http/tests/security/window-named-proto.html: Added.
+
 2011-09-19  John Bauman  <jbauman@chromium.org>
 
         Fix nonpremultiplied webgl toDataURL to jpeg
diff --git a/LayoutTests/http/tests/security/resources/innocent-victim-with-iframe.html b/LayoutTests/http/tests/security/resources/innocent-victim-with-iframe.html
new file mode 100644 (file)
index 0000000..28bc2b9
--- /dev/null
@@ -0,0 +1,6 @@
+<html>
+<body>
+This page doesn't do anything special except have an iframe:<br>
+<iframe src="about:blank"></iframe>
+</body>
+</html>
diff --git a/LayoutTests/http/tests/security/window-named-proto-expected.txt b/LayoutTests/http/tests/security/window-named-proto-expected.txt
new file mode 100644 (file)
index 0000000..b004f97
--- /dev/null
@@ -0,0 +1,4 @@
+CONSOLE MESSAGE: line 1: Unsafe JavaScript attempt to access frame with URL http://localhost:8080/security/resources/innocent-victim-with-iframe.html from frame with URL data:text/html,<script>(function () {            setTimeout(function() {                if (window.layoutTestController)                    layoutTestController.notifyDone();            }, 0);            window.name = "__proto__";            parent.__proto__.alert.constructor("alert(document.body.innerHTML)")();        })()</script>. Domains, protocols and ports must match.
+
+CONSOLE MESSAGE: line 1: Uncaught TypeError: Cannot read property 'alert' of undefined
+
diff --git a/LayoutTests/http/tests/security/window-named-proto.html b/LayoutTests/http/tests/security/window-named-proto.html
new file mode 100644 (file)
index 0000000..66c463b
--- /dev/null
@@ -0,0 +1,26 @@
+<script>
+if (window.layoutTestController) {
+    layoutTestController.dumpAsText();
+    layoutTestController.waitUntilDone();
+}
+
+window.onload = function()
+{
+    frame = document.body.appendChild(document.createElement("iframe"));
+    frame.src = "http://localhost:8080/security/resources/innocent-victim-with-iframe.html";
+    frame.onload = function() {
+        frame.onload = null;
+
+        frame.contentWindow[0].location = "data:text/html,<script>(" + function() {
+
+            setTimeout(function() {
+                if (window.layoutTestController)
+                    layoutTestController.notifyDone();
+            }, 0);
+
+            window.name = "__proto__";
+            parent.__proto__.alert.constructor("alert(document.body.innerHTML)")();
+        } + ")()</scr" + "ipt>";
+    }
+}
+</script>
index 30b300f..14d7f89 100644 (file)
@@ -1,5 +1,22 @@
 2011-09-19  Adam Barth  <abarth@webkit.org>
 
+        Named property confusion with __proto__
+        https://bugs.webkit.org/show_bug.cgi?id=68221
+
+        Reviewed by Eric Seidel.
+
+        The __proto__ property is super magical because it's not a real named
+        property and it has higher precedence than even interceptors.  This
+        confuses this check, which is meant to detech which names will get
+        handled by our interceptor.
+
+        Test: http/tests/security/window-named-proto.html
+
+        * bindings/v8/custom/V8DOMWindowCustom.cpp:
+        (WebCore::V8DOMWindow::namedSecurityCheck):
+
+2011-09-19  Adam Barth  <abarth@webkit.org>
+
         Rename ENABLE(OPENTYPE_SANITIZER) to USE(OPENTYPE_SANITIZER)
         https://bugs.webkit.org/show_bug.cgi?id=68292
 
index cc0404e..d54b702 100644 (file)
@@ -560,12 +560,17 @@ bool V8DOMWindow::namedSecurityCheck(v8::Local<v8::Object> host, v8::Local<v8::V
         return false;
 
     if (key->IsString()) {
+        DEFINE_STATIC_LOCAL(AtomicString, nameOfProtoProperty, ("__proto__"));
+
         String name = toWebCoreString(key);
         // Notice that we can't call HasRealNamedProperty for ACCESS_HAS
         // because that would generate infinite recursion.
         if (type == v8::ACCESS_HAS && target->tree()->child(name))
             return true;
-        if (type == v8::ACCESS_GET && target->tree()->child(name) && !host->HasRealNamedProperty(key->ToString()))
+        // We need to explicitly compare against nameOfProtoProperty because
+        // V8's JSObject::LocalLookup finds __proto__ before
+        // interceptors and even when __proto__ isn't a "real named property".
+        if (type == v8::ACCESS_GET && target->tree()->child(name) && !host->HasRealNamedProperty(key->ToString()) && name != nameOfProtoProperty)
             return true;
     }