Skip to content

Commit

Permalink
[MERGE #5596 @aneeshdk] August 2018 Security Update
Browse files Browse the repository at this point in the history
Merge pull request #5596 from aneeshdk:servicing/1808_1.10

This update address the following issues in ChakraCore.dll : CVE-2018-8380, CVE-2018-8359, CVE-2018-8385, CVE-2018-8390, CVE-2018-8266, CVE-2018-8384, CVE-2018-8372, CVE-2018-8355 and CVE-2018-8381
  • Loading branch information
aneeshdk committed Aug 15, 2018
2 parents 2c4085b + cd84156 commit 8f90719
Show file tree
Hide file tree
Showing 58 changed files with 708 additions and 296 deletions.
2 changes: 1 addition & 1 deletion Build/NuGet/.pack-version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1.10.1
1.10.2
9 changes: 7 additions & 2 deletions lib/Backend/BackwardPass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2245,6 +2245,11 @@ BackwardPass::DeadStoreTypeCheckBailOut(IR::Instr * instr)
IR::PropertySymOpnd *propertySymOpnd =
(instr->GetDst() && instr->GetDst()->IsSymOpnd()) ? instr->GetDst()->AsPropertySymOpnd() : instr->GetSrc1()->AsPropertySymOpnd();

if (propertySymOpnd->TypeCheckRequired())
{
return;
}

bool isTypeCheckProtected = false;
IR::BailOutKind bailOutKind;
if (GlobOpt::NeedsTypeCheckBailOut(instr, propertySymOpnd, propertySymOpnd == instr->GetDst(), &isTypeCheckProtected, &bailOutKind))
Expand Down Expand Up @@ -4902,8 +4907,8 @@ BackwardPass::UpdateArrayBailOutKind(IR::Instr *const instr)
}

IR::BailOutKind includeBailOutKinds = IR::BailOutInvalid;
if(!baseValueType.IsNotNativeArray() &&
(!baseValueType.IsLikelyNativeArray() || !instr->GetSrc1()->IsInt32()) &&
if (!baseValueType.IsNotNativeArray() &&
(!baseValueType.IsLikelyNativeArray() || instr->GetSrc1()->IsVar()) &&
!currentBlock->noImplicitCallNativeArrayUses->IsEmpty() &&
!(instr->GetBailOutKind() & IR::BailOutOnArrayAccessHelperCall))
{
Expand Down
31 changes: 29 additions & 2 deletions lib/Backend/BailOut.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -506,6 +506,13 @@ uint32 BailOutRecord::GetArgumentsObjectOffset()
return argumentsObjectOffset;
}

Js::FunctionEntryPointInfo *BailOutRecord::GetFunctionEntryPointInfo() const
{
Js::EntryPointInfo* result = this->globalBailOutRecordTable->entryPointInfo;
AssertOrFailFast(result->IsFunctionEntryPointInfo());
return (Js::FunctionEntryPointInfo*)result;
}

Js::Var BailOutRecord::EnsureArguments(Js::InterpreterStackFrame * newInstance, Js::JavascriptCallStackLayout * layout, Js::ScriptContext* scriptContext, Js::Var* pArgumentsObject) const
{
Assert(globalBailOutRecordTable->hasStackArgOpt);
Expand Down Expand Up @@ -1706,7 +1713,27 @@ void BailOutRecord::ScheduleFunctionCodeGen(Js::ScriptFunction * function, Js::S
BailOutRecord * bailOutRecordNotConst = (BailOutRecord *)(void *)bailOutRecord;
bailOutRecordNotConst->bailOutCount++;

Js::FunctionEntryPointInfo *entryPointInfo = function->GetFunctionEntryPointInfo();
Js::FunctionEntryPointInfo *entryPointInfo = bailOutRecord->GetFunctionEntryPointInfo();

#if DBG
// BailOutRecord is not recycler-allocated, so make sure something the recycler can see was keeping the entry point info alive.
// We expect the entry point to be kept alive as follows:
// 1. The function's current type might still have the same entry point info as when we entered the function (easy case)
// 2. The function might have moved to a successor path type, which still keeps the previous type and its entry point info alive
// 3. The entry point info might be held by the ThreadContext (QueueFreeOldEntryPointInfoIfInScript):
// a. If the entry point info was replaced on the type that used to hold it (ScriptFunction::ChangeEntryPoint)
// b. If the function's last-added property was deleted and it moved to a previous type (ScriptFunction::ReplaceTypeWithPredecessorType)
// c. If the function's path type got replaced with a dictionary, then all previous entry point infos in that path are queued on the ThreadContext (ScriptFunction::PrepareForConversionToNonPathType)
bool foundEntryPoint = false;
executeFunction->MapEntryPointsUntil([&](int index, Js::FunctionEntryPointInfo* info)
{
foundEntryPoint = info == entryPointInfo;
return foundEntryPoint;
});
foundEntryPoint = foundEntryPoint || function->GetScriptContext()->GetThreadContext()->IsOldEntryPointInfo(entryPointInfo);
Assert(foundEntryPoint);
#endif

uint8 callsCount = entryPointInfo->callsCount > 255 ? 255 : static_cast<uint8>(entryPointInfo->callsCount);
RejitReason rejitReason = RejitReason::None;
bool reThunk = false;
Expand Down Expand Up @@ -2235,7 +2262,7 @@ void BailOutRecord::ScheduleFunctionCodeGen(Js::ScriptFunction * function, Js::S
if (bailOutRecord->IsForLoopTop() && IR::IsTypeCheckBailOutKind(bailOutRecord->bailOutKind))
{
// Disable FieldPRE if we're triggering a type check rejit due to a bailout at the loop top.
// Most likely this was caused by a CheckFixedFld that was hoisted from a branch block where
// Most likely this was caused by a CheckFixedFld that was hoisted from a branch block where
// only certain types flowed, to the loop top, where more types (different or non-equivalent)
// were flowing in.
profileInfo->DisableFieldPRE();
Expand Down
5 changes: 4 additions & 1 deletion lib/Backend/BailOut.h
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,8 @@ class BailOutRecord
void SetType(BailoutRecordType type) { this->type = type; }
bool IsShared() const { return type == Shared || type == SharedForLoopTop; }
bool IsForLoopTop() const { return type == SharedForLoopTop; }

Js::FunctionEntryPointInfo *GetFunctionEntryPointInfo() const;
protected:
struct BailOutReturnValue
{
Expand Down Expand Up @@ -237,7 +239,7 @@ class BailOutRecord

static void UpdatePolymorphicFieldAccess(Js::JavascriptFunction * function, BailOutRecord const * bailOutRecord);

static void ScheduleFunctionCodeGen(Js::ScriptFunction * function, Js::ScriptFunction * innerMostInlinee, BailOutRecord const * bailOutRecord, IR::BailOutKind bailOutKind,
static void ScheduleFunctionCodeGen(Js::ScriptFunction * function, Js::ScriptFunction * innerMostInlinee, BailOutRecord const * bailOutRecord, IR::BailOutKind bailOutKind,
uint32 actualBailOutOffset, Js::ImplicitCallFlags savedImplicitCallFlags, void * returnAddress);
static void ScheduleLoopBodyCodeGen(Js::ScriptFunction * function, Js::ScriptFunction * innerMostInlinee, BailOutRecord const * bailOutRecord, IR::BailOutKind bailOutKind);
static void CheckPreemptiveRejit(Js::FunctionBody* executeFunction, IR::BailOutKind bailOutKind, BailOutRecord* bailoutRecord, uint8& callsOrIterationsCount, int loopNumber);
Expand Down Expand Up @@ -416,6 +418,7 @@ struct GlobalBailOutRecordDataTable
// The offset to 'registerSaveSpace' is hard-coded in LinearScanMD::SaveAllRegisters, so let this be the first member variable
Js::Var *registerSaveSpace;
GlobalBailOutRecordDataRow *globalBailOutRecordDataRows;
Js::EntryPointInfo *entryPointInfo;
uint32 length;
uint32 size;
int32 firstActualStackOffset;
Expand Down
9 changes: 8 additions & 1 deletion lib/Backend/FunctionJITTimeInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ FunctionJITTimeInfo::BuildJITTimeData(
jitData->isInlined = codeGenData->GetIsInlined();
jitData->weakFuncRef = (intptr_t)codeGenData->GetWeakFuncRef();
jitData->inlineesBv = (BVFixedIDL*)(const BVFixed*)codeGenData->inlineesBv;
jitData->entryPointInfoAddr = (intptr_t)codeGenData->GetEntryPointInfo();

if (!codeGenData->GetFunctionBody() || !codeGenData->GetFunctionBody()->GetByteCode())
{
Expand Down Expand Up @@ -62,7 +63,7 @@ FunctionJITTimeInfo::BuildJITTimeData(
Assert(defaultEntryPointInfo->IsFunctionEntryPointInfo());
Js::FunctionEntryPointInfo *functionEntryPointInfo = static_cast<Js::FunctionEntryPointInfo*>(defaultEntryPointInfo);
jitData->callsCountAddress = (intptr_t)&functionEntryPointInfo->callsCount;

jitData->sharedPropertyGuards = codeGenData->sharedPropertyGuards;
jitData->sharedPropGuardCount = codeGenData->sharedPropertyGuardCount;
}
Expand Down Expand Up @@ -203,6 +204,12 @@ FunctionJITTimeInfo::GetFunctionInfoAddr() const
return m_data.functionInfoAddr;
}

intptr_t
FunctionJITTimeInfo::GetEntryPointInfoAddr() const
{
return m_data.entryPointInfoAddr;
}

intptr_t
FunctionJITTimeInfo::GetWeakFuncRef() const
{
Expand Down
1 change: 1 addition & 0 deletions lib/Backend/FunctionJITTimeInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ class FunctionJITTimeInfo
JITTimeFunctionBody * GetBody() const;
bool IsPolymorphicCallSite(Js::ProfileId profiledCallSiteId) const;
intptr_t GetFunctionInfoAddr() const;
intptr_t GetEntryPointInfoAddr() const;
intptr_t GetWeakFuncRef() const;
uint GetLocalFunctionId() const;
uint GetSourceContextId() const;
Expand Down
3 changes: 3 additions & 0 deletions lib/Backend/GlobOpt.h
Original file line number Diff line number Diff line change
Expand Up @@ -938,6 +938,9 @@ class GlobOpt
template<bool makeChanges>
bool ProcessPropOpInTypeCheckSeq(IR::Instr* instr, IR::PropertySymOpnd *opnd, BasicBlock* block, bool updateExistingValue, bool* emitsTypeCheckOut = nullptr, bool* changesTypeValueOut = nullptr, bool *isObjTypeChecked = nullptr);
void KillObjectHeaderInlinedTypeSyms(BasicBlock *block, bool isObjTypeSpecialized, SymID symId = SymID_Invalid);
bool HasLiveObjectHeaderInlinedTypeSym(BasicBlock *block, bool isObjTypeSpecialized, SymID symId = SymID_Invalid);
template<class Fn>
bool MapObjectHeaderInlinedTypeSymsUntil(BasicBlock *block, bool isObjTypeSpecialized, SymID opndId, Fn fn);
void ValueNumberObjectType(IR::Opnd *dstOpnd, IR::Instr *instr);
void SetSingleTypeOnObjectTypeValue(Value* value, const JITTypeHolder type);
void SetTypeSetOnObjectTypeValue(Value* value, Js::EquivalentTypeSet* typeSet);
Expand Down
179 changes: 78 additions & 101 deletions lib/Backend/GlobOptArrays.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -897,19 +897,8 @@ void GlobOpt::ArraySrcOpt::DoLowerBoundCheck()
Assert(!indexIntSym || indexIntSym->GetType() == TyInt32 || indexIntSym->GetType() == TyUint32);
}

// The info in the landing pad may be better than the info in the current block due to changes made to
// the index sym inside the loop. Check if the bound check we intend to hoist is unnecessary in the
// landing pad.
if (!ValueInfo::IsLessThanOrEqualTo(
nullptr,
0,
0,
hoistInfo.IndexValue(),
hoistInfo.IndexConstantBounds().LowerBound(),
hoistInfo.IndexConstantBounds().UpperBound(),
hoistInfo.Offset()))
if (hoistInfo.IndexSym())
{
Assert(hoistInfo.IndexSym());
Assert(hoistInfo.Loop()->bailOutInfo);
globOpt->EnsureBailTarget(hoistInfo.Loop());

Expand Down Expand Up @@ -1156,106 +1145,94 @@ void GlobOpt::ArraySrcOpt::DoUpperBoundCheck()
Assert(!indexIntSym || indexIntSym->GetType() == TyInt32 || indexIntSym->GetType() == TyUint32);
}

// The info in the landing pad may be better than the info in the current block due to changes made to the
// index sym inside the loop. Check if the bound check we intend to hoist is unnecessary in the landing pad.
if (!ValueInfo::IsLessThanOrEqualTo(
hoistInfo.IndexValue(),
hoistInfo.IndexConstantBounds().LowerBound(),
hoistInfo.IndexConstantBounds().UpperBound(),
hoistInfo.HeadSegmentLengthValue(),
hoistInfo.HeadSegmentLengthConstantBounds().LowerBound(),
hoistInfo.HeadSegmentLengthConstantBounds().UpperBound(),
hoistInfo.Offset()))
{
Assert(hoistInfo.Loop()->bailOutInfo);
globOpt->EnsureBailTarget(hoistInfo.Loop());
Assert(hoistInfo.Loop()->bailOutInfo);
globOpt->EnsureBailTarget(hoistInfo.Loop());

if (hoistInfo.LoopCount())
if (hoistInfo.LoopCount())
{
// Generate the loop count and loop count based bound that will be used for the bound check
if (!hoistInfo.LoopCount()->HasBeenGenerated())
{
// Generate the loop count and loop count based bound that will be used for the bound check
if (!hoistInfo.LoopCount()->HasBeenGenerated())
{
globOpt->GenerateLoopCount(hoistInfo.Loop(), hoistInfo.LoopCount());
}
globOpt->GenerateSecondaryInductionVariableBound(
hoistInfo.Loop(),
indexVarSym->GetInt32EquivSym(nullptr),
hoistInfo.LoopCount(),
hoistInfo.MaxMagnitudeChange(),
hoistInfo.IndexSym());
globOpt->GenerateLoopCount(hoistInfo.Loop(), hoistInfo.LoopCount());
}
globOpt->GenerateSecondaryInductionVariableBound(
hoistInfo.Loop(),
indexVarSym->GetInt32EquivSym(nullptr),
hoistInfo.LoopCount(),
hoistInfo.MaxMagnitudeChange(),
hoistInfo.IndexSym());
}

IR::Opnd* lowerBound = indexIntSym
? static_cast<IR::Opnd *>(IR::RegOpnd::New(indexIntSym, TyInt32, instr->m_func))
: IR::IntConstOpnd::New(
hoistInfo.IndexConstantBounds().LowerBound(),
TyInt32,
instr->m_func);

lowerBound->SetIsJITOptimizedReg(true);
IR::Opnd* upperBound = IR::RegOpnd::New(headSegmentLengthSym, headSegmentLengthSym->GetType(), instr->m_func);
upperBound->SetIsJITOptimizedReg(true);
IR::Opnd* lowerBound = indexIntSym
? static_cast<IR::Opnd *>(IR::RegOpnd::New(indexIntSym, TyInt32, instr->m_func))
: IR::IntConstOpnd::New(
hoistInfo.IndexConstantBounds().LowerBound(),
TyInt32,
instr->m_func);

// indexSym <= headSegmentLength + offset (src1 <= src2 + dst)
IR::Instr *const boundCheck = globOpt->CreateBoundsCheckInstr(
lowerBound,
upperBound,
hoistInfo.Offset(),
hoistInfo.IsLoopCountBasedBound()
? IR::BailOutOnFailedHoistedLoopCountBasedBoundCheck
: IR::BailOutOnFailedHoistedBoundCheck,
hoistInfo.Loop()->bailOutInfo,
hoistInfo.Loop()->bailOutInfo->bailOutFunc);
lowerBound->SetIsJITOptimizedReg(true);
IR::Opnd* upperBound = IR::RegOpnd::New(headSegmentLengthSym, headSegmentLengthSym->GetType(), instr->m_func);
upperBound->SetIsJITOptimizedReg(true);

InsertInstrInLandingPad(boundCheck, hoistInfo.Loop());
// indexSym <= headSegmentLength + offset (src1 <= src2 + dst)
IR::Instr *const boundCheck = globOpt->CreateBoundsCheckInstr(
lowerBound,
upperBound,
hoistInfo.Offset(),
hoistInfo.IsLoopCountBasedBound()
? IR::BailOutOnFailedHoistedLoopCountBasedBoundCheck
: IR::BailOutOnFailedHoistedBoundCheck,
hoistInfo.Loop()->bailOutInfo,
hoistInfo.Loop()->bailOutInfo->bailOutFunc);

if (indexIntSym)
{
TRACE_PHASE_INSTR(
Js::Phase::BoundCheckHoistPhase,
instr,
_u("Hoisting array upper bound check out of loop %u to landing pad block %u, as (s%u <= s%u + %d)\n"),
hoistInfo.Loop()->GetLoopNumber(),
landingPad->GetBlockNum(),
hoistInfo.IndexSym()->m_id,
headSegmentLengthSym->m_id,
hoistInfo.Offset());
}
else
{
TRACE_PHASE_INSTR(
Js::Phase::BoundCheckHoistPhase,
instr,
_u("Hoisting array upper bound check out of loop %u to landing pad block %u, as (%d <= s%u + %d)\n"),
hoistInfo.Loop()->GetLoopNumber(),
landingPad->GetBlockNum(),
hoistInfo.IndexConstantBounds().LowerBound(),
headSegmentLengthSym->m_id,
hoistInfo.Offset());
}
InsertInstrInLandingPad(boundCheck, hoistInfo.Loop());

TESTTRACE_PHASE_INSTR(
if (indexIntSym)
{
TRACE_PHASE_INSTR(
Js::Phase::BoundCheckHoistPhase,
instr,
_u("Hoisting array upper bound check out of loop %u to landing pad block %u, as (s%u <= s%u + %d)\n"),
hoistInfo.Loop()->GetLoopNumber(),
landingPad->GetBlockNum(),
hoistInfo.IndexSym()->m_id,
headSegmentLengthSym->m_id,
hoistInfo.Offset());
}
else
{
TRACE_PHASE_INSTR(
Js::Phase::BoundCheckHoistPhase,
instr,
_u("Hoisting array upper bound check out of loop\n"));
_u("Hoisting array upper bound check out of loop %u to landing pad block %u, as (%d <= s%u + %d)\n"),
hoistInfo.Loop()->GetLoopNumber(),
landingPad->GetBlockNum(),
hoistInfo.IndexConstantBounds().LowerBound(),
headSegmentLengthSym->m_id,
hoistInfo.Offset());
}

// Record the bound check instruction as available
const IntBoundCheck boundCheckInfo(
hoistInfo.IndexValue() ? hoistInfo.IndexValueNumber() : ZeroValueNumber,
hoistInfo.HeadSegmentLengthValue()->GetValueNumber(),
boundCheck,
landingPad);
{
const bool added = globOpt->CurrentBlockData()->availableIntBoundChecks->AddNew(boundCheckInfo) >= 0;
Assert(added || failedToUpdateCompatibleUpperBoundCheck);
}
for (InvariantBlockBackwardIterator it(globOpt, globOpt->currentBlock, landingPad, nullptr);
it.IsValid();
it.MoveNext())
{
const bool added = it.Block()->globOptData.availableIntBoundChecks->AddNew(boundCheckInfo) >= 0;
Assert(added || failedToUpdateCompatibleUpperBoundCheck);
}
TESTTRACE_PHASE_INSTR(
Js::Phase::BoundCheckHoistPhase,
instr,
_u("Hoisting array upper bound check out of loop\n"));

// Record the bound check instruction as available
const IntBoundCheck boundCheckInfo(
hoistInfo.IndexValue() ? hoistInfo.IndexValueNumber() : ZeroValueNumber,
hoistInfo.HeadSegmentLengthValue()->GetValueNumber(),
boundCheck,
landingPad);
{
const bool added = globOpt->CurrentBlockData()->availableIntBoundChecks->AddNew(boundCheckInfo) >= 0;
Assert(added || failedToUpdateCompatibleUpperBoundCheck);
}
for (InvariantBlockBackwardIterator it(globOpt, globOpt->currentBlock, landingPad, nullptr);
it.IsValid();
it.MoveNext())
{
const bool added = it.Block()->globOptData.availableIntBoundChecks->AddNew(boundCheckInfo) >= 0;
Assert(added || failedToUpdateCompatibleUpperBoundCheck);
}
}

Expand Down
Loading

0 comments on commit 8f90719

Please sign in to comment.