Bug 1226977, non-string types are only needed for chrome contexts, r=smaug
authorNeil Deakin <neil@mozilla.com>
Thu, 21 Apr 2016 14:11:13 -0400
changeset 332235 eb1d405b1239f342187201225a6cac0ff21440c2
parent 332234 1b2c3cc8c06f7e257a8040c04086a99889356b2d
child 332236 4cbc83f4c4b1d7cd3bf9758247dce1f54318fb62
push id6048
push userkmoir@mozilla.com
push dateMon, 06 Jun 2016 19:02:08 +0000
treeherdermozilla-beta@46d72a56c57d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs1226977
milestone48.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 1226977, non-string types are only needed for chrome contexts, r=smaug
dom/events/DataTransfer.cpp
dom/events/test/test_dragstart.html
dom/tests/mochitest/general/mochitest.ini
dom/tests/mochitest/general/test_clipboard_disallowed.html
--- a/dom/events/DataTransfer.cpp
+++ b/dom/events/DataTransfer.cpp
@@ -705,22 +705,30 @@ DataTransfer::SetDataAtInternal(const ns
 
   // Only the first item is valid for clipboard events
   if (aIndex > 0 &&
       (mEventMessage == eCut || mEventMessage == eCopy ||
        mEventMessage == ePaste)) {
     return NS_ERROR_DOM_INDEX_SIZE_ERR;
   }
 
-  // don't allow non-chrome to add file data
-  // XXX perhaps this should also limit any non-string type as well
-  if ((aFormat.EqualsLiteral("application/x-moz-file-promise") ||
-       aFormat.EqualsLiteral("application/x-moz-file")) &&
-       !nsContentUtils::IsSystemPrincipal(aSubjectPrincipal)) {
-    return NS_ERROR_DOM_SECURITY_ERR;
+  // Don't allow non-chrome to add non-string or file data. We'll block file
+  // promises as well which are used internally for drags to the desktop.
+  if (!nsContentUtils::IsSystemPrincipal(aSubjectPrincipal)) {
+    if (aFormat.EqualsLiteral("application/x-moz-file-promise") ||
+        aFormat.EqualsLiteral("application/x-moz-file")) {
+      return NS_ERROR_DOM_SECURITY_ERR;
+    }
+
+    uint16_t type;
+    aData->GetDataType(&type);
+    if (type == nsIDataType::VTYPE_INTERFACE ||
+        type == nsIDataType::VTYPE_INTERFACE_IS) {
+      return NS_ERROR_DOM_SECURITY_ERR;
+    }
   }
 
   return SetDataWithPrincipal(aFormat, aData, aIndex, aSubjectPrincipal);
 }
 
 void
 DataTransfer::MozSetDataAt(JSContext* aCx, const nsAString& aFormat,
                            JS::Handle<JS::Value> aData,
--- a/dom/events/test/test_dragstart.html
+++ b/dom/events/test/test_dragstart.html
@@ -308,39 +308,39 @@ function test_DataTransfer(dt)
 
   dt.setData("text/html", "Changed with setData");
   is(dt.mozItemCount, 2, "changed with setData");
   checkOneDataItem(dt, ["text/plain", "text/html"],
                    ["First Item", "Changed with setData"], 0, "changed with setData item at index 0");
   checkOneDataItem(dt, ["text/plain", "text/html"],
                    ["Changed Second Item", "<em>Second Item</em>"], 1, "changed with setData item at index 1");
 
-  dt.mozSetDataAt("application/-moz-node", draggable, 2);
+  dt.mozSetDataAt("application/-moz-node", "draggable", 2);
   is(dt.mozItemCount, 3, "setDataAt node itemCount");
-  checkOneDataItem(dt, ["application/-moz-node"], [draggable], 2, "setDataAt node item at index 2");
+  checkOneDataItem(dt, ["application/-moz-node"], ["draggable"], 2, "setDataAt node item at index 2");
 
   dt.mozClearDataAt("text/html", 1);
   is(dt.mozItemCount, 3, "clearDataAt itemCount");
   checkOneDataItem(dt, ["text/plain", "text/html"],
                    ["First Item", "Changed with setData"], 0, "clearDataAt item at index 0");
   checkOneDataItem(dt, ["text/plain"], ["Changed Second Item"], 1, "clearDataAt item at index 1");
 
   dt.mozClearDataAt("text/plain", 1);
   is(dt.mozItemCount, 2, "clearDataAt last type itemCount");
   checkOneDataItem(dt, ["text/plain", "text/html"],
                    ["First Item", "Changed with setData"], 0, "clearDataAt last type at index 0");
-  checkOneDataItem(dt, ["application/-moz-node"], [draggable], 1, "clearDataAt last type item at index 2");
+  checkOneDataItem(dt, ["application/-moz-node"], ["draggable"], 1, "clearDataAt last type item at index 2");
   expectError(() => dt.mozGetDataAt("text/plain", 2),
               "IndexSizeError", "getDataAt after item removed index too high");
 
   dt.mozSetDataAt("text/unknown", "Unknown type", 2);
   dt.mozSetDataAt("text/unknown", "Unknown type", 1);
   is(dt.mozItemCount, 3, "add unknown type");
   checkOneDataItem(dt, ["application/-moz-node", "text/unknown"],
-                   [draggable, "Unknown type"], 1, "add unknown type item at index 1");
+                   ["draggable", "Unknown type"], 1, "add unknown type item at index 1");
   checkOneDataItem(dt, ["text/unknown"], ["Unknown type"], 2, "add unknown type item at index 2");
 
   dt.mozClearDataAt("", 1);
   is(dt.mozItemCount, 2, "clearDataAt empty string");
   checkOneDataItem(dt, ["text/plain", "text/html"],
                    ["First Item", "Changed with setData"], 0, "clearDataAt empty string item at index 0");
   checkOneDataItem(dt, ["text/unknown"],
                    ["Unknown type"], 1, "clearDataAt empty string item at index 1");
--- a/dom/tests/mochitest/general/mochitest.ini
+++ b/dom/tests/mochitest/general/mochitest.ini
@@ -59,16 +59,17 @@ skip-if = ((buildapp == 'mulet' || build
 [test_bug628069_1.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
 [test_bug628069_2.html]
 [test_bug631440.html]
 skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
 [test_bug653364.html]
 [test_bug861217.html]
 [test_clientRects.html]
+[test_clipboard_disallowed.html]
 [test_clipboard_events.html]
 skip-if = buildapp == 'b2g' # b2g(clipboard undefined) b2g-debug(clipboard undefined) b2g-desktop(clipboard undefined)
 [test_consoleAPI.html]
 [test_DOMMatrix.html]
 [test_domWindowUtils.html]
 [test_domWindowUtils_scrollXY.html]
 [test_domWindowUtils_scrollbarSize.html]
 [test_donottrack.html]
new file mode 100644
--- /dev/null
+++ b/dom/tests/mochitest/general/test_clipboard_disallowed.html
@@ -0,0 +1,61 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Test for Clipboard Events</title>
+  <script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<p id="display"></p>
+<input id="input" value="INPUT TEXT" oncopy="checkAllowed(event)">
+
+<script>
+function doTest()
+{
+  document.getElementById("input").focus();
+  synthesizeKey("c", {accelKey: 1});
+}
+
+function checkAllowed(event)
+{
+  let clipboardData = event.clipboardData;
+
+  let exception;
+  try {
+    clipboardData.mozSetDataAt("text/customdata", document.getElementById("input"), 0);
+  } catch(ex) {
+    exception = ex;
+  }
+  is(String(exception).indexOf("SecurityError"), 0, "Cannot set non-string");
+
+  exception = null;
+  try {
+    clipboardData.mozSetDataAt("application/x-moz-file", "Test", 0);
+  } catch(ex) {
+    exception = ex;
+  }
+  is(String(exception).indexOf("SecurityError"), 0, "Cannot set file");
+
+  exception = null;
+  try {
+    clipboardData.mozSetDataAt("application/x-moz-file-promise", "Test", 0);
+  } catch(ex) {
+    exception = ex;
+  }
+  is(String(exception).indexOf("SecurityError"), 0, "Cannot set file promise");
+
+  exception = null;
+  try {
+    clipboardData.mozSetDataAt("application/something", "This is data", 0);
+  } catch(ex) {
+    exception = ex;
+  }
+  is(exception, null, "Can set custom data to a string");
+  SimpleTest.finish();
+}
+
+SimpleTest.waitForExplicitFinish();
+SimpleTest.waitForFocus(doTest);
+</script>