Skip to content

Commit

Permalink
[CVE-2017-11802] Chakra - JIT RegexHelper::StringReplace must call th…
Browse files Browse the repository at this point in the history
…e callback function with updating ImplicitCallFlags.

JIT inline string.prototype.replace for case a.replace(b,c) if 'a' and 'c' are strings and 'b' is a regex and calls helper for other cases. If c is a function RegexHelper::StringReplace will call c, this should be marked as implicit call so that JIT can bailout on implicit call check.
  • Loading branch information
agarwal-sandeep committed Oct 10, 2017
1 parent d234b08 commit b7dcda0
Show file tree
Hide file tree
Showing 3 changed files with 25 additions and 4 deletions.
3 changes: 3 additions & 0 deletions lib/Common/ConfigFlagsList.h
Original file line number Diff line number Diff line change
Expand Up @@ -1057,6 +1057,9 @@ FLAGPR_REGOVR_EXP(Boolean, ES6, ES6RegExPrototypeProperties, "Enable ES6 propert
#ifndef COMPILE_DISABLE_ES6RegExSymbols
#define COMPILE_DISABLE_ES6RegExSymbols 0
#endif

// When we enable ES6RegExSymbols check all String and Regex built-ins which are inlined in JIT and make sure the helper
// sets implicit call flag before calling into script
FLAGPR_REGOVR_EXP(Boolean, ES6, ES6RegExSymbols , "Enable ES6 RegExp symbols" , DEFAULT_CONFIG_ES6RegExSymbols)

FLAGPR (Boolean, ES6, ES6HasInstance , "Enable ES6 @@hasInstance symbol" , DEFAULT_CONFIG_ES6HasInstance)
Expand Down
9 changes: 8 additions & 1 deletion lib/Runtime/Library/JavascriptArray.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11991,7 +11991,14 @@ namespace Js
Js::Var constructorArgs[] = { constructor, JavascriptNumber::ToVar(length, scriptContext) };
Js::CallInfo constructorCallInfo(Js::CallFlags_New, _countof(constructorArgs));

return RecyclableObject::FromVar(JavascriptOperators::NewScObject(constructor, Js::Arguments(constructorCallInfo, constructorArgs), scriptContext));
AssertOrFailFast(Js::RecyclableObject::Is(constructor));
ThreadContext* threadContext = scriptContext->GetThreadContext();
Var scObject = threadContext->ExecuteImplicitCall((RecyclableObject*)constructor, ImplicitCall_Accessor, [&]()->Js::Var
{
return JavascriptOperators::NewScObject(constructor, Js::Arguments(constructorCallInfo, constructorArgs), scriptContext);
});

return RecyclableObject::FromVar(scObject);
}
/*static*/
PropertyId const JavascriptArray::specialPropertyIds[] =
Expand Down
17 changes: 14 additions & 3 deletions lib/Runtime/Library/RegexHelper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1259,9 +1259,16 @@ namespace Js

// WARNING: We go off into script land here, which way in turn invoke a regex operation, even on the
// same regex.
JavascriptString* replace = JavascriptConversion::ToString(replacefn->CallFunction(Arguments(CallInfo((ushort)(numGroups + 3)), replaceArgs)), scriptContext);

ThreadContext* threadContext = scriptContext->GetThreadContext();
Var replaceVar = threadContext->ExecuteImplicitCall(replacefn, ImplicitCall_Accessor, [=]()->Js::Var
{
return replacefn->CallFunction(Arguments(CallInfo((ushort)(numGroups + 3)), replaceArgs));
});
JavascriptString* replace = JavascriptConversion::ToString(replaceVar, scriptContext);
concatenated.Append(input, offset, lastActualMatch.offset - offset);
concatenated.Append(replace);

if (lastActualMatch.length == 0)
{
if (lastActualMatch.offset < inputLength)
Expand Down Expand Up @@ -1397,8 +1404,12 @@ namespace Js

if (indexMatched != CharCountFlag)
{
Var pThis = scriptContext->GetLibrary()->GetUndefined();
Var replaceVar = CALL_FUNCTION(scriptContext->GetThreadContext(), replacefn, CallInfo(4), pThis, match, JavascriptNumber::ToVar((int)indexMatched, scriptContext), input);
ThreadContext* threadContext = scriptContext->GetThreadContext();
Var replaceVar = threadContext->ExecuteImplicitCall(replacefn, ImplicitCall_Accessor, [=]()->Js::Var
{
Var pThis = scriptContext->GetLibrary()->GetUndefined();
return CALL_FUNCTION(threadContext, replacefn, CallInfo(4), pThis, match, JavascriptNumber::ToVar((int)indexMatched, scriptContext), input);
});
JavascriptString* replace = JavascriptConversion::ToString(replaceVar, scriptContext);
const char16* inputStr = input->GetString();
const char16* prefixStr = inputStr;
Expand Down

0 comments on commit b7dcda0

Please sign in to comment.