From 54d6d085987e2c399863940179db67b594d7f0a3 Mon Sep 17 00:00:00 2001 From: Satheesh Ravindranath Date: Mon, 27 Feb 2017 12:40:57 -0800 Subject: [PATCH 1/2] [CVE-2017-0208] Fix integer overflow in string.repeat When using repeat API on javascript strings, we aren't checking for the upper cap of the length property. Fix: Instead of directly setting the length property in the constructor - We are now calling SetLength() - which also checks for the upper cap and throws OOM. i --- lib/Runtime/Library/JavascriptString.cpp | 8 ++++---- lib/Runtime/Library/JavascriptString.h | 4 ++-- test/Strings/repeatBug.js | 21 +++++++++++++++++++++ test/Strings/rlexe.xml | 6 ++++++ 4 files changed, 33 insertions(+), 6 deletions(-) create mode 100644 test/Strings/repeatBug.js diff --git a/lib/Runtime/Library/JavascriptString.cpp b/lib/Runtime/Library/JavascriptString.cpp index 0db870d0c85..53914b1b6ac 100644 --- a/lib/Runtime/Library/JavascriptString.cpp +++ b/lib/Runtime/Library/JavascriptString.cpp @@ -199,10 +199,10 @@ namespace Js } JavascriptString::JavascriptString(StaticType * type, charcount_t charLength, const char16* szValue) - : RecyclableObject(type), m_charLength(charLength), m_pszValue(szValue) + : RecyclableObject(type), m_pszValue(szValue) { Assert(type->GetTypeId() == TypeIds_String); - AssertMsg(IsValidCharCount(charLength), "String length is out of range"); + SetLength(charLength); } _Ret_range_(m_charLength, m_charLength) @@ -3353,7 +3353,7 @@ namespace Js return builder.ToString(); } - int JavascriptString::IndexOfUsingJmpTable(JmpTable jmpTable, const char16* inputStr, int len, const char16* searchStr, int searchLen, int position) + int JavascriptString::IndexOfUsingJmpTable(JmpTable jmpTable, const char16* inputStr, charcount_t len, const char16* searchStr, int searchLen, int position) { int result = -1; @@ -3400,7 +3400,7 @@ namespace Js return result; } - int JavascriptString::LastIndexOfUsingJmpTable(JmpTable jmpTable, const char16* inputStr, int len, const char16* searchStr, int searchLen, int position) + int JavascriptString::LastIndexOfUsingJmpTable(JmpTable jmpTable, const char16* inputStr, charcount_t len, const char16* searchStr, charcount_t searchLen, charcount_t position) { const char16 searchFirst = searchStr[0]; uint32 lMatchedJump = searchLen; diff --git a/lib/Runtime/Library/JavascriptString.h b/lib/Runtime/Library/JavascriptString.h index b9b8bcdbc43..40141dffcf4 100644 --- a/lib/Runtime/Library/JavascriptString.h +++ b/lib/Runtime/Library/JavascriptString.h @@ -157,8 +157,8 @@ namespace Js char16* GetSzCopy(); // get a copy of the inner string without compacting the chunks static Var ToCaseCore(JavascriptString* pThis, ToCase toCase); - static int IndexOfUsingJmpTable(JmpTable jmpTable, const char16* inputStr, int len, const char16* searchStr, int searchLen, int position); - static int LastIndexOfUsingJmpTable(JmpTable jmpTable, const char16* inputStr, int len, const char16* searchStr, int searchLen, int position); + static int IndexOfUsingJmpTable(JmpTable jmpTable, const char16* inputStr, charcount_t len, const char16* searchStr, int searchLen, int position); + static int LastIndexOfUsingJmpTable(JmpTable jmpTable, const char16* inputStr, charcount_t len, const char16* searchStr, charcount_t searchLen, charcount_t position); static bool BuildLastCharForwardBoyerMooreTable(JmpTable jmpTable, const char16* searchStr, int searchLen); static bool BuildFirstCharBackwardBoyerMooreTable(JmpTable jmpTable, const char16* searchStr, int searchLen); static charcount_t ConvertToIndex(Var varIndex, ScriptContext *scriptContext); diff --git a/test/Strings/repeatBug.js b/test/Strings/repeatBug.js new file mode 100644 index 00000000000..1ed7740f4cb --- /dev/null +++ b/test/Strings/repeatBug.js @@ -0,0 +1,21 @@ +//------------------------------------------------------------------------------------------------------- +// 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 str = "+".repeat(0x80000000); + str = str.replace(str, "+"); + + WScript.Echo("FAIL: Was expecting Out of Memory exception."); +} +catch (e) +{ + if(e.number == -2146828281) //Out of Memory + WScript.Echo("PASS"); + else + WScript.Echo("FAIL: Got the wrong exception code."); +} + + diff --git a/test/Strings/rlexe.xml b/test/Strings/rlexe.xml index 7fcb113051e..ac6393757ea 100644 --- a/test/Strings/rlexe.xml +++ b/test/Strings/rlexe.xml @@ -242,4 +242,10 @@ exclude_win7 + + + repeatBug.js + exclude_chk, Slow + + From 303d997b65faf5a4eebb08a98c52b8ee3fb72287 Mon Sep 17 00:00:00 2001 From: Michael Ferris Date: Thu, 26 Jan 2017 15:46:54 -0800 Subject: [PATCH 2/2] [CVE-2017-0093] Type confusion in asm.js arguments When calling eval we pass an additional argument to the function. If we've assigned an asm.js function to eval, then we need to remove that additional argument before getting the arguments --- lib/Runtime/Language/AsmJsUtils.cpp | 3 ++- test/AsmJs/evalbug.js | 18 ++++++++++++++++++ test/AsmJs/rlexe.xml | 5 +++++ 3 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 test/AsmJs/evalbug.js diff --git a/lib/Runtime/Language/AsmJsUtils.cpp b/lib/Runtime/Language/AsmJsUtils.cpp index 410d296c690..09290913f21 100644 --- a/lib/Runtime/Language/AsmJsUtils.cpp +++ b/lib/Runtime/Language/AsmJsUtils.cpp @@ -217,7 +217,8 @@ namespace Js AsmJsModuleInfo::EnsureHeapAttached(func); - uint actualArgCount = callInfo.Count - 1; // -1 for ScriptFunction + ArgumentReader reader(&callInfo, origArgs); + uint actualArgCount = reader.Info.Count - 1; // -1 for ScriptFunction argDst = argDst + MachPtr; // add one first so as to skip the ScriptFunction argument for (ArgSlot i = 0; i < info->GetArgCount(); i++) { diff --git a/test/AsmJs/evalbug.js b/test/AsmJs/evalbug.js new file mode 100644 index 00000000000..5372beab079 --- /dev/null +++ b/test/AsmJs/evalbug.js @@ -0,0 +1,18 @@ +//------------------------------------------------------------------------------------------------------- +// Copyright (C) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. +//------------------------------------------------------------------------------------------------------- + +function asm() { + "use asm" + function f(a, b) { + a = a|0; + b = b|0; + return a|0; + } + return f; +} + +eval = asm(); +eval("some string"); +print("PASSED"); diff --git a/test/AsmJs/rlexe.xml b/test/AsmJs/rlexe.xml index 7a1c1221611..2181f7a5cac 100644 --- a/test/AsmJs/rlexe.xml +++ b/test/AsmJs/rlexe.xml @@ -536,6 +536,11 @@ -testtrace:asmjs -simdjs + + + evalbug.js + + constTest.js