Jelajahi Sumber

Fix #3189: Fix pre-init Intl tainting of Map and Object.defineProperty.

* Expose and use platform.Map
* Use ObjectDefineProperty instead of Object.defineProperty

Fixes #3189
Doug Ilijev 8 tahun lalu
induk
melakukan
0f2f8b4f81

+ 1 - 0
lib/Runtime/Library/EngineInterfaceObjectBuiltIns.h

@@ -9,6 +9,7 @@ GlobalBuiltInConstructor(RegExp)
 GlobalBuiltInConstructor(String)
 GlobalBuiltInConstructor(Date)
 GlobalBuiltInConstructor(Error) /*This was added back in to allow assert errors*/
+GlobalBuiltInConstructor(Map)
 
 GlobalBuiltIn(Math,Abs)
 GlobalBuiltIn(Math,Floor)

+ 8 - 8
lib/Runtime/Library/InJavascript/Intl.js

@@ -8,10 +8,10 @@
 (function (EngineInterface, InitType) {
     var platform = EngineInterface.Intl;
     if (platform.localeLookupCache === undefined) {
-        platform.localeLookupCache = new Map();
+        platform.localeLookupCache = new platform.Map();
     }
     if (platform.localeBestFitCache === undefined) {
-        platform.localeBestFitCache = new Map();
+        platform.localeBestFitCache = new platform.Map();
     }
 
     // constants
@@ -30,6 +30,7 @@
     var String = platform.String;
     var Date = platform.Date;
     var Error = platform.Error;
+    var Map = platform.Map;
 
     var RaiseAssert = platform.raiseAssert;
 
@@ -40,16 +41,15 @@
         pow: platform.builtInMathPow
     }, null);
 
-    var objectDefineProperty = platform.builtInJavascriptObjectEntryDefineProperty;
     var ObjectGetPrototypeOf = platform.builtInJavascriptObjectEntryGetPrototypeOf;
     var ObjectIsExtensible = platform.builtInJavascriptObjectEntryIsExtensible;
     var ObjectGetOwnPropertyNames = platform.builtInJavascriptObjectEntryGetOwnPropertyNames;
     var ObjectInstanceHasOwnProperty = platform.builtInJavascriptObjectEntryHasOwnProperty;
-
     // Because we don't keep track of the attributes object, and neither does the internals of Object.defineProperty;
     // We don't need to restore it's prototype.
+    var _objectDefineProperty = platform.builtInJavascriptObjectEntryDefineProperty;
     var ObjectDefineProperty = function (obj, prop, attributes) {
-        objectDefineProperty(obj, prop, setPrototype(attributes, null));
+        _objectDefineProperty(obj, prop, setPrototype(attributes, null));
     };
 
     var ArrayInstanceForEach = platform.builtInJavascriptArrayEntryForEach;
@@ -381,9 +381,9 @@
     // When https://github.com/Microsoft/ChakraCore/issues/637 is fixed and we have a way
     // to make built-in functions non-constructible, we can remove the call to
     // Function.prototype.bind and just rely on tagging instead of setting the "name" manually.
-    Object.defineProperty(collator_supportedLocalesOf, 'name', { value: 'supportedLocalesOf' });
-    Object.defineProperty(numberFormat_supportedLocalesOf, 'name', { value: 'supportedLocalesOf' });
-    Object.defineProperty(dateTimeFormat_supportedLocalesOf, 'name', { value: 'supportedLocalesOf' });
+    ObjectDefineProperty(collator_supportedLocalesOf, 'name', { value: 'supportedLocalesOf' });
+    ObjectDefineProperty(numberFormat_supportedLocalesOf, 'name', { value: 'supportedLocalesOf' });
+    ObjectDefineProperty(dateTimeFormat_supportedLocalesOf, 'name', { value: 'supportedLocalesOf' });
 
     // If an empty string is encountered for the value of the property; that means that is by default.
     // So in the case of zh-TW; "default" and "stroke" are the same.

+ 1 - 0
test/Intl/IntlTaintingPreInitTests.baseline

@@ -0,0 +1 @@
+Passed pre-init tainting!

+ 105 - 0
test/Intl/IntlTaintingPreInitTests.js

@@ -0,0 +1,105 @@
+//-------------------------------------------------------------------------------------------------------
+// Copyright (C) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
+//-------------------------------------------------------------------------------------------------------
+
+try {
+    var failed = false;
+    function getErrorFunction(global) {
+        return function () {
+            failed = true;
+            WScript.Echo("Error when tainting '" + global + "'!");
+        }
+    }
+
+    function generalTainting() {
+        // tainting built-in object constructors and functions
+        Date = getErrorFunction("Date");
+        Object = getErrorFunction("Object");
+        Number = getErrorFunction("Number");
+        RegExp = getErrorFunction("RegExp");
+        String = getErrorFunction("String");
+        Boolean = getErrorFunction("Boolean");
+        Error = getErrorFunction("Error");
+        TypeError = getErrorFunction("TypeError");
+        RangeError = getErrorFunction("RangeError");
+        Map = getErrorFunction("Map");
+
+        Math = {
+            abs: getErrorFunction("Math.abs"),
+            floor: getErrorFunction("Math.floor"),
+            max: getErrorFunction("Math.max"),
+            pow: getErrorFunction("Math.pow")
+        };
+
+        isFinite = getErrorFunction("isFinite");
+        isNaN = getErrorFunction("isNaN");
+    }
+
+    function objectTainting() {
+        Object.create = getErrorFunction("Object.create");
+        Object.defineProperty = getErrorFunction("Object.defineProperty");
+        Object.getPrototypeOf = getErrorFunction("Object.getPrototypeOf");
+        Object.isExtensible = getErrorFunction("Object.isExtensible");
+        Object.getOwnPropertyNames = getErrorFunction("Object.getOwnPropertyNames");
+        Object.prototype.hasOwnProperty = getErrorFunction("Object.prototype.hasOwnProperty");
+    }
+
+    function arrayTainting() {
+        Array.prototype.forEach = getErrorFunction("Array.prototype.forEach");
+        Array.prototype.indexOf = getErrorFunction("Array.prototype.indexOf");
+        Array.prototype.push = getErrorFunction("Array.prototype.push");
+        Array.prototype.join = getErrorFunction("Array.prototype.join");
+    }
+
+    function stringTainting() {
+        String.prototype.match = getErrorFunction("String.prototype.match");
+        String.prototype.replace = getErrorFunction("String.prototype.replace");
+        String.prototype.toLowerCase = getErrorFunction("String.prototype.toLowerCase");
+        String.prototype.toUpperCase = getErrorFunction("String.prototype.toUpperCase");
+    }
+
+    function otherProtototypeTainting() {
+        Function.prototype.bind = getErrorFunction("Function.prototype.bind");
+        Date.prototype.getDate = getErrorFunction("Date.prototype.getDate");
+        RegExp.prototype.test = getErrorFunction("RegExp.prototype.test");
+    }
+
+    function runTests() {
+        failed = false;
+
+        new Intl.NumberFormat().format(5);
+        new Intl.DateTimeFormat().format(5);
+        new Intl.Collator().compare(null, "");
+
+        new Intl.NumberFormat().format(5);
+        new Intl.DateTimeFormat().format(5);
+        new Intl.Collator().compare(null, "");
+
+        new Intl.NumberFormat().format(5);
+        new Intl.DateTimeFormat("en", { month: "short" }).format(5);
+        new Intl.Collator().compare("en", "");
+
+        new Intl.NumberFormat().format(5);
+        new Intl.DateTimeFormat("en", { month: "short" }).format(5);
+        new Intl.Collator().compare("en", "");
+
+        new Intl.NumberFormat().format(5);
+        new Intl.DateTimeFormat("en", { month: "short" }).format(5);
+        new Intl.Collator().compare("en", "");
+
+        if (failed === false) {
+            WScript.Echo("Passed pre-init tainting!");
+        }
+    }
+
+    objectTainting();
+    arrayTainting();
+    stringTainting();
+    otherProtototypeTainting();
+    generalTainting();
+    runTests();
+
+} catch (e) {
+    WScript.Echo(e);
+}

+ 1 - 0
test/Intl/IntlTaintingTests.js

@@ -52,6 +52,7 @@ try {
         Error = getErrorFunction("Error");
         TypeError = getErrorFunction("TypeError");
         RangeError = getErrorFunction("RangeError");
+        Map = getErrorFunction("Map");
 
         Math = {
             abs: getErrorFunction("Math.abs"),

+ 7 - 0
test/Intl/rlexe.xml

@@ -80,6 +80,13 @@
       <tags>Intl,exclude_winglob</tags>
     </default>
   </test>
+  <test>
+    <default>
+      <files>IntlTaintingPreInitTests.js</files>
+      <baseline>IntlTaintingPreInitTests.baseline</baseline>
+      <tags>Intl,exclude_winglob</tags>
+    </default>
+  </test>
 
   <test>
     <default>