Skip to content

Commit

Permalink
[MERGE #6016 @pleath] ChakraCore Servicing Release for 1903
Browse files Browse the repository at this point in the history
Merge pull request #6016 from pleath:servicing/1903

Addresses the following issue:

CVE-2019-0592
CVE-2019-0609
CVE-2019-0611
CVE-2019-0639
CVE-2019-0746
CVE-2019-0769
CVE-2019-0773
CVE-2019-0771
  • Loading branch information
pleath committed Mar 12, 2019
2 parents d4fb4df + b116253 commit f61a97a
Show file tree
Hide file tree
Showing 23 changed files with 190 additions and 75 deletions.
33 changes: 25 additions & 8 deletions lib/Backend/BailOut.cpp
Expand Up @@ -1403,6 +1403,7 @@ BailOutRecord::BailOutHelper(Js::JavascriptCallStackLayout * layout, Js::ScriptF
//
Js::Arguments generatorArgs = generator->GetArguments();
Js::InterpreterStackFrame::Setup setup(function, generatorArgs, true, isInlinee);
Assert(setup.GetStackAllocationVarCount() == 0);
size_t varAllocCount = setup.GetAllocationVarCount();
size_t varSizeInBytes = varAllocCount * sizeof(Js::Var);
DWORD_PTR stackAddr = reinterpret_cast<DWORD_PTR>(&generator); // as mentioned above, use any stack address from this frame to ensure correct debugging functionality
Expand All @@ -1415,11 +1416,14 @@ BailOutRecord::BailOutHelper(Js::JavascriptCallStackLayout * layout, Js::ScriptF
// Allocate invalidVar on GC instead of stack since this InterpreterStackFrame will out live the current real frame
Js::Var invalidVar = (Js::RecyclableObject*)RecyclerNewPlusLeaf(functionScriptContext->GetRecycler(), sizeof(Js::RecyclableObject), Js::Var);
memset(invalidVar, 0xFE, sizeof(Js::RecyclableObject));
newInstance = setup.InitializeAllocation(allocation, false, false, loopHeaderArray, stackAddr, invalidVar);
#else
newInstance = setup.InitializeAllocation(allocation, false, false, loopHeaderArray, stackAddr);
#endif

newInstance = setup.InitializeAllocation(allocation, nullptr, false, false, loopHeaderArray, stackAddr
#if DBG
, invalidVar
#endif
);

newInstance->m_reader.Create(executeFunction);

generator->SetFrame(newInstance, varSizeInBytes);
Expand All @@ -1429,18 +1433,28 @@ BailOutRecord::BailOutHelper(Js::JavascriptCallStackLayout * layout, Js::ScriptF
{
Js::InterpreterStackFrame::Setup setup(function, args, true, isInlinee);
size_t varAllocCount = setup.GetAllocationVarCount();
size_t varSizeInBytes = varAllocCount * sizeof(Js::Var);
size_t stackVarAllocCount = setup.GetStackAllocationVarCount();
size_t varSizeInBytes;
Js::Var *stackAllocation = nullptr;

// If the locals area exceeds a certain limit, allocate it from a private arena rather than
// this frame. The current limit is based on an old assert on the number of locals we would allow here.
if (varAllocCount > Js::InterpreterStackFrame::LocalsThreshold)
if ((varAllocCount + stackVarAllocCount) > Js::InterpreterStackFrame::LocalsThreshold)
{
ArenaAllocator *tmpAlloc = nullptr;
fReleaseAlloc = functionScriptContext->EnsureInterpreterArena(&tmpAlloc);
varSizeInBytes = varAllocCount * sizeof(Js::Var);
allocation = (Js::Var*)tmpAlloc->Alloc(varSizeInBytes);
if (stackVarAllocCount != 0)
{
size_t stackVarSizeInBytes = stackVarAllocCount * sizeof(Js::Var);
PROBE_STACK_PARTIAL_INITIALIZED_BAILOUT_FRAME(functionScriptContext, Js::Constants::MinStackInterpreter + stackVarSizeInBytes, returnAddress);
stackAllocation = (Js::Var*)_alloca(stackVarSizeInBytes);
}
}
else
{
varSizeInBytes = (varAllocCount + stackVarAllocCount) * sizeof(Js::Var);
PROBE_STACK_PARTIAL_INITIALIZED_BAILOUT_FRAME(functionScriptContext, Js::Constants::MinStackInterpreter + varSizeInBytes, returnAddress);
allocation = (Js::Var*)_alloca(varSizeInBytes);
}
Expand All @@ -1465,11 +1479,14 @@ BailOutRecord::BailOutHelper(Js::JavascriptCallStackLayout * layout, Js::ScriptF
#if DBG
Js::Var invalidStackVar = (Js::RecyclableObject*)_alloca(sizeof(Js::RecyclableObject));
memset(invalidStackVar, 0xFE, sizeof(Js::RecyclableObject));
newInstance = setup.InitializeAllocation(allocation, false, false, loopHeaderArray, frameStackAddr, invalidStackVar);
#else
newInstance = setup.InitializeAllocation(allocation, false, false, loopHeaderArray, frameStackAddr);
#endif

newInstance = setup.InitializeAllocation(allocation, stackAllocation, false, false, loopHeaderArray, frameStackAddr
#if DBG
, invalidStackVar
#endif
);

newInstance->m_reader.Create(executeFunction);
}

Expand Down
2 changes: 1 addition & 1 deletion lib/Backend/EmitBuffer.cpp
Expand Up @@ -414,7 +414,7 @@ bool EmitBufferManager<TAlloc, TPreReservedAlloc, SyncObject>::ProtectBufferWith
template <typename TAlloc, typename TPreReservedAlloc, class SyncObject>
bool EmitBufferManager<TAlloc, TPreReservedAlloc, SyncObject>::CommitBufferForInterpreter(TEmitBufferAllocation* allocation, _In_reads_bytes_(bufferSize) BYTE* pBuffer, _In_ size_t bufferSize)
{
Assert(this->criticalSection.IsLocked());
AutoRealOrFakeCriticalSection<SyncObject> autoCs(&this->criticalSection);

Assert(allocation != nullptr);
allocation->bytesUsed += bufferSize;
Expand Down
2 changes: 1 addition & 1 deletion lib/Backend/FlowGraph.cpp
Expand Up @@ -5266,7 +5266,7 @@ BasicBlock::MergePredBlocksValueMaps(GlobOpt* globOpt)
}
if(symsRequiringCompensationToMergedValueInfoMap.Count() != 0)
{
globOpt->InsertValueCompensation(pred, &symsRequiringCompensationToMergedValueInfoMap);
globOpt->InsertValueCompensation(pred, this, &symsRequiringCompensationToMergedValueInfoMap);
}
}
} NEXT_PREDECESSOR_EDGE_EDITING;
Expand Down
7 changes: 5 additions & 2 deletions lib/Backend/GlobOpt.cpp
Expand Up @@ -601,7 +601,7 @@ GlobOpt::OptBlock(BasicBlock *block)

if (block->loop->symsRequiringCompensationToMergedValueInfoMap)
{
InsertValueCompensation(block, block->loop->symsRequiringCompensationToMergedValueInfoMap);
InsertValueCompensation(block, succ, block->loop->symsRequiringCompensationToMergedValueInfoMap);
}

// Now that we're done with the liveFields within this loop, trim the set to those syms
Expand Down Expand Up @@ -1156,9 +1156,12 @@ void GlobOpt::FieldPRE(Loop *loop)

void GlobOpt::InsertValueCompensation(
BasicBlock *const predecessor,
BasicBlock *const successor,
const SymToValueInfoMap *symsRequiringCompensationToMergedValueInfoMap)
{
Assert(predecessor);
Assert(successor);
AssertOrFailFast(predecessor != successor);
Assert(symsRequiringCompensationToMergedValueInfoMap->Count() != 0);

IR::Instr *insertBeforeInstr = predecessor->GetLastInstr();
Expand All @@ -1182,7 +1185,7 @@ void GlobOpt::InsertValueCompensation(
}

GlobOptBlockData &predecessorBlockData = predecessor->globOptData;
GlobOptBlockData &successorBlockData = *CurrentBlockData();
GlobOptBlockData &successorBlockData = successor->globOptData;
struct DelayChangeValueInfo
{
Value* predecessorValue;
Expand Down
2 changes: 1 addition & 1 deletion lib/Backend/GlobOpt.h
Expand Up @@ -737,7 +737,7 @@ class GlobOpt
void PreLowerCanonicalize(IR::Instr *instr, Value **pSrc1Val, Value **pSrc2Val);
void ProcessKills(IR::Instr *instr);
void InsertCloneStrs(BasicBlock *toBlock, GlobOptBlockData *toData, GlobOptBlockData *fromData);
void InsertValueCompensation(BasicBlock *const predecessor, const SymToValueInfoMap *symsRequiringCompensationToMergedValueInfoMap);
void InsertValueCompensation(BasicBlock *const predecessor, BasicBlock *const successor, const SymToValueInfoMap *symsRequiringCompensationToMergedValueInfoMap);
IR::Instr * ToVarUses(IR::Instr *instr, IR::Opnd *opnd, bool isDst, Value *val);
void ToVar(BVSparse<JitArenaAllocator> *bv, BasicBlock *block);
IR::Instr * ToVar(IR::Instr *instr, IR::RegOpnd *regOpnd, BasicBlock *block, Value *val, bool needsUpdate);
Expand Down
15 changes: 15 additions & 0 deletions lib/Backend/GlobOptFields.cpp
Expand Up @@ -450,9 +450,24 @@ GlobOpt::ProcessFieldKills(IR::Instr *instr, BVSparse<JitArenaAllocator> *bv, bo
break;

case IR::JnHelperMethod::HelperRegExp_Exec:
case IR::JnHelperMethod::HelperRegExp_ExecResultNotUsed:
case IR::JnHelperMethod::HelperRegExp_ExecResultUsed:
case IR::JnHelperMethod::HelperRegExp_ExecResultUsedAndMayBeTemp:
case IR::JnHelperMethod::HelperRegExp_MatchResultNotUsed:
case IR::JnHelperMethod::HelperRegExp_MatchResultUsed:
case IR::JnHelperMethod::HelperRegExp_MatchResultUsedAndMayBeTemp:
case IR::JnHelperMethod::HelperRegExp_ReplaceStringResultUsed:
case IR::JnHelperMethod::HelperRegExp_ReplaceStringResultNotUsed:
case IR::JnHelperMethod::HelperRegExp_SplitResultNotUsed:
case IR::JnHelperMethod::HelperRegExp_SplitResultUsed:
case IR::JnHelperMethod::HelperRegExp_SplitResultUsedAndMayBeTemp:
case IR::JnHelperMethod::HelperRegExp_SymbolSearch:
case IR::JnHelperMethod::HelperString_Match:
case IR::JnHelperMethod::HelperString_Search:
case IR::JnHelperMethod::HelperString_Split:
case IR::JnHelperMethod::HelperString_Replace:
// Consider: We may not need to kill all fields here.
// We need to kill all the built-in properties that can be written, though, and there are a lot of those.
this->KillAllFields(bv);
break;
}
Expand Down
6 changes: 5 additions & 1 deletion lib/Backend/GlobOptIntBounds.cpp
Expand Up @@ -2985,7 +2985,11 @@ void GlobOpt::DetermineArrayBoundCheckHoistability(
{
// The loop count is constant, fold (indexOffset + loopCountMinusOne * maxMagnitudeChange)
TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 3, _u("Loop count is constant, folding\n"));
if(Int32Math::Mul(loopCount->LoopCountMinusOneConstantValue(), maxMagnitudeChange, &offset) ||

int loopCountMinusOnePlusOne = 0;

if (Int32Math::Add(loopCount->LoopCountMinusOneConstantValue(), 1, &loopCountMinusOnePlusOne) ||
Int32Math::Mul(loopCountMinusOnePlusOne, maxMagnitudeChange, &offset) ||
Int32Math::Add(offset, indexOffset, &offset))
{
TRACE_PHASE_VERBOSE(Js::Phase::BoundCheckHoistPhase, 4, _u("Folding failed\n"));
Expand Down
4 changes: 2 additions & 2 deletions lib/Backend/IRBuilder.cpp
Expand Up @@ -1758,7 +1758,7 @@ IRBuilder::BuildReg1(Js::OpCode newOpcode, uint32 offset, Js::RegSlot R0)
}

case Js::OpCode::NewScObjectSimple:
dstValueType = ValueType::GetObject(ObjectType::UninitializedObject);
dstValueType = ValueType::GetObject(ObjectType::Object);
// fall-through
case Js::OpCode::LdFuncExpr:
m_func->DisableCanDoInlineArgOpt();
Expand Down Expand Up @@ -5050,7 +5050,7 @@ IRBuilder::BuildAuxiliary(Js::OpCode newOpcode, uint32 offset)
// lower take it from there...
srcOpnd = IR::IntConstOpnd::New(auxInsn->Offset, TyUint32, m_func);
dstOpnd = this->BuildDstOpnd(dstRegSlot);
dstOpnd->SetValueType(ValueType::GetObject(ObjectType::UninitializedObject));
dstOpnd->SetValueType(ValueType::GetObject(ObjectType::Object));
instr = IR::Instr::New(newOpcode, dstOpnd, srcOpnd, m_func);

// Because we're going to be making decisions based off the value, we have to defer
Expand Down
9 changes: 6 additions & 3 deletions lib/Backend/ServerScriptContext.cpp
Expand Up @@ -312,6 +312,7 @@ ServerScriptContext::IsClosed() const
void
ServerScriptContext::AddToDOMFastPathHelperMap(intptr_t funcInfoAddr, IR::JnHelperMethod helper)
{
AutoCriticalSection cs(&m_cs);
m_domFastPathHelperMap->Add(funcInfoAddr, helper);
}

Expand All @@ -327,7 +328,7 @@ ServerScriptContext::DecommitEmitBufferManager(bool asmJsManager)
GetEmitBufferManager(asmJsManager)->Decommit();
}

OOPEmitBufferManager *
OOPEmitBufferManagerWithLock *
ServerScriptContext::GetEmitBufferManager(bool asmJsManager)
{
if (asmJsManager)
Expand All @@ -343,11 +344,11 @@ ServerScriptContext::GetEmitBufferManager(bool asmJsManager)
IR::JnHelperMethod
ServerScriptContext::GetDOMFastPathHelper(intptr_t funcInfoAddr)
{
AutoCriticalSection cs(&m_cs);

IR::JnHelperMethod helper = IR::HelperInvalid;

m_domFastPathHelperMap->LockResize();
m_domFastPathHelperMap->TryGetValue(funcInfoAddr, &helper);
m_domFastPathHelperMap->UnlockResize();

return helper;
}
Expand Down Expand Up @@ -392,6 +393,7 @@ ServerScriptContext::GetCodeGenAllocators()
Field(Js::Var)*
ServerScriptContext::GetModuleExportSlotArrayAddress(uint moduleIndex, uint slotIndex)
{
AutoCriticalSection cs(&m_cs);
AssertOrFailFast(m_moduleRecords.ContainsKey(moduleIndex));
auto record = m_moduleRecords.Item(moduleIndex);
return record->localExportSlotsAddr;
Expand All @@ -406,6 +408,7 @@ ServerScriptContext::SetIsPRNGSeeded(bool value)
void
ServerScriptContext::AddModuleRecordInfo(unsigned int moduleId, __int64 localExportSlotsAddr)
{
AutoCriticalSection cs(&m_cs);
Js::ServerSourceTextModuleRecord* record = HeapNewStructZ(Js::ServerSourceTextModuleRecord);
record->moduleId = moduleId;
record->localExportSlotsAddr = (Field(Js::Var)*)localExportSlotsAddr;
Expand Down
7 changes: 4 additions & 3 deletions lib/Backend/ServerScriptContext.h
Expand Up @@ -80,7 +80,7 @@ class ServerScriptContext : public ScriptContextInfo
void SetIsPRNGSeeded(bool value);
void AddModuleRecordInfo(unsigned int moduleId, __int64 localExportSlotsAddr);
void UpdateGlobalObjectThisAddr(intptr_t globalThis);
OOPEmitBufferManager * GetEmitBufferManager(bool asmJsManager);
OOPEmitBufferManagerWithLock * GetEmitBufferManager(bool asmJsManager);
void DecommitEmitBufferManager(bool asmJsManager);
#ifdef PROFILE_EXEC
Js::ScriptContextProfiler* GetCodeGenProfiler(_In_ PageAllocator* pageAllocator);
Expand All @@ -100,10 +100,11 @@ class ServerScriptContext : public ScriptContextInfo
Js::ScriptContextProfiler * codeGenProfiler;
CriticalSection profilerCS;
#endif
CriticalSection m_cs;
ArenaAllocator m_sourceCodeArena;

OOPEmitBufferManager m_interpreterThunkBufferManager;
OOPEmitBufferManager m_asmJsInterpreterThunkBufferManager;
OOPEmitBufferManagerWithLock m_interpreterThunkBufferManager;
OOPEmitBufferManagerWithLock m_asmJsInterpreterThunkBufferManager;

ScriptContextDataIDL m_contextData;
intptr_t m_globalThisAddr;
Expand Down
19 changes: 16 additions & 3 deletions lib/JITIDL/ChakraJIT.acf
Expand Up @@ -3,13 +3,26 @@
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
//-------------------------------------------------------------------------------------------------------

typedef [context_handle_noserialize] PTHREADCONTEXT_HANDLE;
typedef [context_handle_noserialize] PSCRIPTCONTEXT_HANDLE;

[
type_strict_context_handle
]
interface IChakraJIT
{
UpdatePropertyRecordMap([context_handle_noserialize] threadContextInfoAddress);
AddDOMFastPathHelper([context_handle_noserialize] scriptContextInfoAddress);
AddModuleRecordInfo([context_handle_noserialize] scriptContextInfoAddress);
SetWellKnownHostTypeId([context_handle_noserialize] threadContextInfoAddress);
CloseScriptContext([context_handle_noserialize] scriptContextInfoAddress);
FreeAllocation([context_handle_noserialize] scriptContextInfoAddress);
NewInterpreterThunkBlock([context_handle_noserialize] scriptContextInfoAddress);
DecommitInterpreterBufferManager([context_handle_noserialize] scriptContextInfoAddress);
IsNativeAddr([context_handle_noserialize] threadContextInfoAddress);
SetIsPRNGSeeded([context_handle_noserialize] scriptContextInfoAddress);
RemoteCodeGen([context_handle_noserialize] scriptContextInfoAddress);

#if DBG
IsInterpreterThunkAddr([context_handle_noserialize] scriptContextInfoAddress);
#endif

typedef [encode, decode] pCodeGenWorkItemIDL;
}
4 changes: 2 additions & 2 deletions lib/JITServer/JITServer.cpp
Expand Up @@ -502,7 +502,7 @@ ServerNewInterpreterThunkBlock(
ServerThreadContext * threadContext;
} localAlloc(threadContext);

OOPEmitBufferManager * emitBufferManager = scriptContext->GetEmitBufferManager(thunkInput->asmJsThunk != FALSE);
OOPEmitBufferManagerWithLock * emitBufferManager = scriptContext->GetEmitBufferManager(thunkInput->asmJsThunk != FALSE);

BYTE* runtimeAddress;
EmitBufferAllocation<SectionAllocWrapper, PreReservedSectionAllocWrapper> * alloc = emitBufferManager->AllocateBuffer(InterpreterThunkEmitter::BlockSize, &runtimeAddress);
Expand Down Expand Up @@ -573,7 +573,7 @@ ServerIsInterpreterThunkAddr(
*result = false;
return RPC_S_INVALID_ARG;
}
OOPEmitBufferManager * manager = context->GetEmitBufferManager(asmjsThunk != FALSE);
OOPEmitBufferManagerWithLock * manager = context->GetEmitBufferManager(asmjsThunk != FALSE);
if (manager == nullptr)
{
*result = false;
Expand Down
5 changes: 5 additions & 0 deletions lib/Runtime/Base/ScriptContext.cpp
Expand Up @@ -1485,6 +1485,11 @@ namespace Js
this->GetThreadContext()->RegisterScriptContext(this);
}

bool ScriptContext::ExceedsStackNestedFuncCount(uint count)
{
return count >= (InterpreterStackFrame::LocalsThreshold / (sizeof(StackScriptFunction) / sizeof(Var)));
}

#ifdef ENABLE_SCRIPT_DEBUGGING
ArenaAllocator* ScriptContext::AllocatorForDiagnostics()
{
Expand Down
2 changes: 2 additions & 0 deletions lib/Runtime/Base/ScriptContext.h
Expand Up @@ -1089,6 +1089,8 @@ namespace Js
ScriptConfiguration const * GetConfig(void) const { return &config; }
CharClassifier const * GetCharClassifier(void) const;

static bool ExceedsStackNestedFuncCount(uint count);

ThreadContext * GetThreadContext() const { return threadContext; }

static const int MaxEvalSourceSize = 400;
Expand Down
3 changes: 2 additions & 1 deletion lib/Runtime/ByteCode/ByteCodeGenerator.cpp
Expand Up @@ -1839,7 +1839,8 @@ bool ByteCodeGenerator::CanStackNestedFunc(FuncInfo * funcInfo, bool trace)
Assert(!funcInfo->IsGlobalFunction());
bool const doStackNestedFunc = !funcInfo->HasMaybeEscapedNestedFunc() && !IsInDebugMode()
&& !funcInfo->byteCodeFunction->IsCoroutine()
&& !funcInfo->byteCodeFunction->IsModule();
&& !funcInfo->byteCodeFunction->IsModule()
&& !Js::ScriptContext::ExceedsStackNestedFuncCount(funcInfo->root->nestedCount);
if (!doStackNestedFunc)
{
return false;
Expand Down

0 comments on commit f61a97a

Please sign in to comment.