Device motion and orientation should only be visible from the main frame's security...
authordino@apple.com <dino@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 13 Oct 2015 21:46:10 +0000 (21:46 +0000)
committerdino@apple.com <dino@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 13 Oct 2015 21:46:10 +0000 (21:46 +0000)
https://bugs.webkit.org/show_bug.cgi?id=150072
<rdar://problem/23082036>

Reviewed by Brent Fulgham.

.:

Add a manual test for cross-origin device orientation events, while
we're waiting on the mock client to be supported everywhere.

* ManualTests/deviceorientation-child-frame.html: Added.
* ManualTests/deviceorientation-main-frame-only.html: Added.

Source/WebCore:

There are reports that gyroscope and accelerometer information can
be used to detect keyboard entry. One initial step to reduce the
risk is to forbid device motion and orientation events from
being fired in frames that are a different security origin from the main page.

Manual test: deviceorientation-main-frame-only.html

* page/DOMWindow.cpp:
(WebCore::DOMWindow::isSameSecurityOriginAsMainFrame): New helper function.
(WebCore::DOMWindow::addEventListener): Check if we are the main frame, or the
same security origin as the main frame. If not, don't add the event
listeners.

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

ChangeLog
ManualTests/deviceorientation-child-frame.html [new file with mode: 0644]
ManualTests/deviceorientation-main-frame-only.html [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/page/DOMWindow.cpp
Source/WebCore/page/DOMWindow.h

index 1a9b89b..3cc11ec 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,17 @@
+2015-10-13  Dean Jackson  <dino@apple.com>
+
+        Device motion and orientation should only be visible from the main frame's security origin
+        https://bugs.webkit.org/show_bug.cgi?id=150072
+        <rdar://problem/23082036>
+
+        Reviewed by Brent Fulgham.
+
+        Add a manual test for cross-origin device orientation events, while
+        we're waiting on the mock client to be supported everywhere.
+
+        * ManualTests/deviceorientation-child-frame.html: Added.
+        * ManualTests/deviceorientation-main-frame-only.html: Added.
+
 2015-10-12  Philip Chimento  <philip.chimento@gmail.com>
 
         [GTK] OSX linker doesn't understand --whole-archive
diff --git a/ManualTests/deviceorientation-child-frame.html b/ManualTests/deviceorientation-child-frame.html
new file mode 100644 (file)
index 0000000..2321f7c
--- /dev/null
@@ -0,0 +1,23 @@
+<html>
+<head>
+    <script>
+    var results = null;
+
+    function run() {
+        results = document.getElementById("results");
+        window.addEventListener("deviceorientation", handleDeviceOrientation, false);
+    }
+
+    function handleDeviceOrientation(event) {
+        results.textContent = "ERROR: Saw event in child frame.";
+        window.removeEventListener("deviceorientation", handleDeviceOrientation);
+    }
+
+    window.addEventListener("load", run, false);
+    </script>
+</head>
+<body>
+    <p>We should not see an event in here.</p>
+    <p id="results">Child frame has not seen event - this is ok.</p>
+</body>
+</html>
diff --git a/ManualTests/deviceorientation-main-frame-only.html b/ManualTests/deviceorientation-main-frame-only.html
new file mode 100644 (file)
index 0000000..761600d
--- /dev/null
@@ -0,0 +1,26 @@
+<html>
+<head>
+    <script>
+    var results = null;
+
+    function run() {
+        results = document.getElementById("results");
+        window.addEventListener("deviceorientation", handleDeviceOrientation, false);
+    }
+
+    function handleDeviceOrientation(event) {
+        results.textContent = "Saw event in the main frame - this is ok";
+        window.removeEventListener("deviceorientation", handleDeviceOrientation);
+    }
+
+    window.addEventListener("load", run, false);
+    </script>
+</head>
+<body>
+    <p>This tests that deviceorientation events are not dispatched in different origin iframes.</p>
+    <p><b>REMEMBER TO CHANGE THE SRC OF THE IFRAME TO BE CROSS-ORIGIN</b></p>
+    <p>We should be able to detect the event in the main page, but not in the frame.</p>
+    <p id="results">Main page has not seen event.</p>
+    <iframe id="frameA" src="http://127.0.0.1/device-orientation-child-frame.html"></iframe>
+</body>
+</html>
index 158a08c..e93113f 100644 (file)
@@ -1,3 +1,24 @@
+2015-10-13  Dean Jackson  <dino@apple.com>
+
+        Device motion and orientation should only be visible from the main frame's security origin
+        https://bugs.webkit.org/show_bug.cgi?id=150072
+        <rdar://problem/23082036>
+
+        Reviewed by Brent Fulgham.
+
+        There are reports that gyroscope and accelerometer information can
+        be used to detect keyboard entry. One initial step to reduce the
+        risk is to forbid device motion and orientation events from
+        being fired in frames that are a different security origin from the main page.
+
+        Manual test: deviceorientation-main-frame-only.html
+
+        * page/DOMWindow.cpp:
+        (WebCore::DOMWindow::isSameSecurityOriginAsMainFrame): New helper function.
+        (WebCore::DOMWindow::addEventListener): Check if we are the main frame, or the
+        same security origin as the main frame. If not, don't add the event
+        listeners.
+
 2015-10-12  Dean Jackson  <dino@apple.com>
 
         ASSERT(m_motionManager) on emgn.com page
index 6d0a736..4342f13 100644 (file)
@@ -1691,6 +1691,22 @@ static void didAddStorageEventListener(DOMWindow* window)
     window->sessionStorage(IGNORE_EXCEPTION);
 }
 
+bool DOMWindow::isSameSecurityOriginAsMainFrame() const
+{
+    if (!m_frame || !m_frame->page() || !document())
+        return false;
+
+    if (m_frame->isMainFrame())
+        return true;
+
+    Document* mainFrameDocument = m_frame->mainFrame().document();
+
+    if (mainFrameDocument && document()->securityOrigin()->canAccess(mainFrameDocument->securityOrigin()))
+        return true;
+
+    return false;
+}
+
 bool DOMWindow::addEventListener(const AtomicString& eventType, RefPtr<EventListener>&& listener, bool useCapture)
 {
     if (!EventTarget::addEventListener(eventType, WTF::move(listener), useCapture))
@@ -1712,17 +1728,28 @@ bool DOMWindow::addEventListener(const AtomicString& eventType, RefPtr<EventList
         addBeforeUnloadEventListener(this);
 #if ENABLE(DEVICE_ORIENTATION)
 #if PLATFORM(IOS)
-    else if (eventType == eventNames().devicemotionEvent && document())
-        document()->deviceMotionController()->addDeviceEventListener(this);
-    else if (eventType == eventNames().deviceorientationEvent && document())
-        document()->deviceOrientationController()->addDeviceEventListener(this);
+    else if ((eventType == eventNames().devicemotionEvent || eventType == eventNames().deviceorientationEvent) && document()) {
+        if (isSameSecurityOriginAsMainFrame()) {
+            if (eventType == eventNames().deviceorientationEvent)
+                document()->deviceOrientationController()->addDeviceEventListener(this);
+            else
+                document()->deviceMotionController()->addDeviceEventListener(this);
+        } else if (document())
+            document()->addConsoleMessage(MessageSource::JS, MessageLevel::Warning, ASCIILiteral("Blocked attempt add device motion or orientation listener from child frame that wasn't the same security origin as the main page."));
+    }
 #else
     else if (eventType == eventNames().devicemotionEvent && RuntimeEnabledFeatures::sharedFeatures().deviceMotionEnabled()) {
-        if (DeviceMotionController* controller = DeviceMotionController::from(page()))
-            controller->addDeviceEventListener(this);
+        if (isSameSecurityOriginAsMainFrame()) {
+            if (DeviceMotionController* controller = DeviceMotionController::from(page()))
+                controller->addDeviceEventListener(this);
+        } else if (document())
+            document()->addConsoleMessage(MessageSource::JS, MessageLevel::Warning, ASCIILiteral("Blocked attempt add device motion listener from child frame that wasn't the same security origin as the main page."));
     } else if (eventType == eventNames().deviceorientationEvent && RuntimeEnabledFeatures::sharedFeatures().deviceOrientationEnabled()) {
-        if (DeviceOrientationController* controller = DeviceOrientationController::from(page()))
-            controller->addDeviceEventListener(this);
+        if (isSameSecurityOriginAsMainFrame()) {
+            if (DeviceOrientationController* controller = DeviceOrientationController::from(page()))
+                controller->addDeviceEventListener(this);
+        } else if (document())
+            document()->addConsoleMessage(MessageSource::JS, MessageLevel::Warning, ASCIILiteral("Blocked attempt add device orientation listener from child frame that wasn't the same security origin as the main page."));
     }
 #endif // PLATFORM(IOS)
 #endif // ENABLE(DEVICE_ORIENTATION)
index e49322e..0d8d953 100644 (file)
@@ -361,6 +361,8 @@ namespace WebCore {
         void reconnectDOMWindowProperties();
         void willDestroyDocumentInFrame();
 
+        bool isSameSecurityOriginAsMainFrame() const;
+
 #if ENABLE(GAMEPAD)
         void incrementGamepadEventListenerCount();
         void decrementGamepadEventListenerCount();