Selaa lähdekoodia

CVE-2018-8551

Taylor Woll 7 vuotta sitten
vanhempi
sitoutus
6199b5e19a
4 muutettua tiedostoa jossa 76 lisäystä ja 4 poistoa
  1. 14 3
      lib/Parser/Scan.cpp
  2. 1 1
      lib/Parser/Scan.h
  3. 55 0
      test/Bugs/bug_5585.js
  4. 6 0
      test/Bugs/rlexe.xml

+ 14 - 3
lib/Parser/Scan.cpp

@@ -193,13 +193,16 @@ void Scanner<EncodingPolicy>::PrepareForBackgroundParse(Js::ScriptContext *scrip
 // This is used to determine a length of BSTR, which can't contain a NUL character.
 //-----------------------------------------------------------------------------
 template <typename EncodingPolicy>
-charcount_t Scanner<EncodingPolicy>::LineLength(EncodedCharPtr first, EncodedCharPtr last)
+charcount_t Scanner<EncodingPolicy>::LineLength(EncodedCharPtr first, EncodedCharPtr last, size_t* cb)
 {
+    Assert(cb != nullptr);
+
     charcount_t result = 0;
     EncodedCharPtr p = first;
 
     for (;;)
     {
+        EncodedCharPtr prev = p;
         switch( this->template ReadFull<false>(p, last) )
         {
             case kchNWL: // _C_NWL
@@ -207,6 +210,13 @@ charcount_t Scanner<EncodingPolicy>::LineLength(EncodedCharPtr first, EncodedCha
             case kchLS:
             case kchPS:
             case kchNUL: // _C_NUL
+                // p is now advanced past the line terminator character.
+                // We need to know the number of bytes making up the line, not including the line terminator character.
+                // To avoid subtracting a variable number of bytes because the line terminator characters are different
+                // number of bytes long (plus there may be multiple valid encodings for these characters) just keep
+                // track of the first byte of the line terminator character in prev.
+                Assert(prev >= first);
+                *cb = prev - first;
                 return result;
         }
         result++;
@@ -2313,10 +2323,11 @@ HRESULT Scanner<EncodingPolicy>::SysAllocErrorLine(int32 ichMinLine, __out BSTR*
     typename EncodingPolicy::EncodedCharPtr pStart = static_cast<size_t>(ichMinLine) == IchMinLine() ? m_pchMinLine : m_pchBase + this->CharacterOffsetToUnitOffset(m_pchBase, m_currentCharacter, m_pchLast, ichMinLine);
 
     // Determine the length by scanning for the next newline
-    charcount_t cch = LineLength(pStart, m_pchLast);
+    size_t cb = 0;
+    charcount_t cch = LineLength(pStart, m_pchLast, &cb);
     Assert(cch <= LONG_MAX);
 
-    typename EncodingPolicy::EncodedCharPtr pEnd = static_cast<size_t>(ichMinLine) == IchMinLine() ? m_pchMinLine + cch : m_pchBase + this->CharacterOffsetToUnitOffset(m_pchBase, m_currentCharacter, m_pchLast, cch);
+    typename EncodingPolicy::EncodedCharPtr pEnd = static_cast<size_t>(ichMinLine) == IchMinLine() ? m_pchMinLine + cb : m_pchBase + this->CharacterOffsetToUnitOffset(m_pchBase, m_currentCharacter, m_pchLast, cch);
 
     *pbstrLine = SysAllocStringLen(NULL, cch);
     if (!*pbstrLine)

+ 1 - 1
lib/Parser/Scan.h

@@ -780,7 +780,7 @@ private:
 
     void ScanNewLine(uint ch);
     void NotifyScannedNewLine();
-    charcount_t LineLength(EncodedCharPtr first, EncodedCharPtr last);
+    charcount_t LineLength(EncodedCharPtr first, EncodedCharPtr last, size_t* cb);
 
     tokens ScanIdentifier(bool identifyKwds, EncodedCharPtr *pp);
     BOOL FastIdentifierContinue(EncodedCharPtr&p, EncodedCharPtr last);

+ 55 - 0
test/Bugs/bug_5585.js

@@ -0,0 +1,55 @@
+//-------------------------------------------------------------------------------------------------------
+// Copyright (C) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
+//-------------------------------------------------------------------------------------------------------
+
+WScript.LoadScriptFile("..\\UnitTestFramework\\UnitTestFramework.js");
+
+let line = 't("摩"2)';
+let module_name = 'temp.js';
+WScript.RegisterModuleSource(module_name, line);
+
+var tests = [
+    {
+        name: "Syntax error thrown parsing dynamic module",
+        body: function () {
+            let source = `import(module_name)
+            .then(v => {
+                assert.fail("Parsing this module should not succeed");
+            }, e => {
+                assert.areEqual(line, e.source, "Source line causing compile error");
+            }).catch(e => {
+                console.log('fail: ' + e);
+                throw e;
+            });`
+
+            testRunner.LoadModule(source, 'samethread', true, false);
+        }
+    },
+    {
+        name: "Syntax error thrown parsing module code",
+        body: function () {
+            try {
+                WScript.LoadScriptFile(module_name, 'module');
+                assert.fail("Parsing this module should not succeed");
+            } catch(e) {
+                assert.areEqual(line, e.source, "Source line causing compile error");
+            }
+        }
+    },
+    {
+        name: "Error line which contains multi-byte UTF-8 sequence which is an end-of-line character",
+        body: function () {
+            WScript.RegisterModuleSource('temp2.js', 't("\u2028"2)');
+
+            try {
+                WScript.LoadScriptFile('temp2.js', 'module');
+                assert.fail("Parsing this module should not succeed");
+            } catch(e) {
+                assert.areEqual('t("', e.source, "Source line causing compile error");
+            }
+        }
+    }
+];
+
+testRunner.runTests(tests, { verbose: WScript.Arguments[0] != "summary" });

+ 6 - 0
test/Bugs/rlexe.xml

@@ -530,4 +530,10 @@
       <tags>exclude_jshost</tags>
     </default>
   </test>
+  <test>
+    <default>
+      <files>bug_5585.js</files>
+      <compile-flags>-esdynamicimport -mutehosterrormsg -args summary -endargs</compile-flags>
+    </default>
+  </test>
 </regress-exe>