Skip to content
Permalink
Browse files

[1.11>master] [MERGE #6016 @pleath] ChakraCore Servicing Release for …

…1903

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 3a9a3d5 + f61a97a commit 95b7191c299eac2a7e8557937cb89f22c80bf20f
@@ -1527,6 +1527,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
@@ -1539,11 +1540,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);
@@ -1553,18 +1557,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);
}
@@ -1589,11 +1603,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);
}

@@ -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;
@@ -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;
@@ -605,7 +605,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
@@ -1160,9 +1160,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();
@@ -1186,7 +1189,7 @@ void GlobOpt::InsertValueCompensation(
}

GlobOptBlockData &predecessorBlockData = predecessor->globOptData;
GlobOptBlockData &successorBlockData = *CurrentBlockData();
GlobOptBlockData &successorBlockData = successor->globOptData;
struct DelayChangeValueInfo
{
Value* predecessorValue;
@@ -736,7 +736,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);
@@ -442,9 +442,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;
}
@@ -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"));
@@ -1674,7 +1674,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();
@@ -4992,7 +4992,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
@@ -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);
}

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

OOPEmitBufferManager *
OOPEmitBufferManagerWithLock *
ServerScriptContext::GetEmitBufferManager(bool asmJsManager)
{
if (asmJsManager)
@@ -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;
}
@@ -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;
@@ -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;
@@ -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);
@@ -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;
@@ -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;
}
@@ -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);
@@ -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;
@@ -1492,6 +1492,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()
{
@@ -1105,6 +1105,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;
@@ -1859,7 +1859,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;
Oops, something went wrong.

0 comments on commit 95b7191

Please sign in to comment.
You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.