Skip to content

Commit

Permalink
[CVE-2017-11808] Type confusion in FrameDisplay items may lead to oob…
Browse files Browse the repository at this point in the history
… read/write
  • Loading branch information
rajatd authored and agarwal-sandeep committed Oct 10, 2017
1 parent d79926b commit f08408b
Show file tree
Hide file tree
Showing 14 changed files with 68 additions and 26 deletions.
14 changes: 8 additions & 6 deletions lib/Backend/Lower.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23374,7 +23374,7 @@ Lowerer::GenerateRecyclerAlloc(IR::JnHelperMethod allocHelper, size_t allocSize,
}

void
Lowerer::GenerateMemInit(IR::RegOpnd * opnd, int32 offset, int value, IR::Instr * insertBeforeInstr, bool isZeroed)
Lowerer::GenerateMemInit(IR::RegOpnd * opnd, int32 offset, int32 value, IR::Instr * insertBeforeInstr, bool isZeroed)
{
IRType type = TyInt32;
if (isZeroed)
Expand Down Expand Up @@ -24199,7 +24199,7 @@ Lowerer::LowerNewScopeSlots(IR::Instr * instr, bool doStackSlots)
IR::RegOpnd * dst = instr->UnlinkDst()->AsRegOpnd();

// dst = RecyclerAlloc(allocSize)
// dst[EncodedSlotCountSlotIndex = EncodedSlotCountSlotIOndex];
// dst[EncodedSlotCountSlotIndex] = min(actualSlotCount, MaxEncodedSlotCount);
// dst[ScopeMetadataSlotIndex] = FunctionBody;
// mov undefinedOpnd, undefined
// dst[FirstSlotIndex..count] = undefinedOpnd;
Expand All @@ -24210,8 +24210,10 @@ Lowerer::LowerNewScopeSlots(IR::Instr * instr, bool doStackSlots)
{
GenerateRecyclerAlloc(IR::HelperAllocMemForVarArray, allocSize, dst, instr);
}
GenerateMemInit(dst, Js::ScopeSlots::EncodedSlotCountSlotIndex * sizeof(Js::Var),
min<uint>(actualSlotCount, Js::ScopeSlots::MaxEncodedSlotCount), instr, !doStackSlots);

m_lowererMD.GenerateMemInit(dst, Js::ScopeSlots::EncodedSlotCountSlotIndex * sizeof(Js::Var),
(size_t)min<uint>(actualSlotCount, Js::ScopeSlots::MaxEncodedSlotCount), instr, !doStackSlots);

IR::Opnd * functionInfoOpnd = this->LoadFunctionInfoOpnd(instr);
GenerateMemInit(dst, Js::ScopeSlots::ScopeMetadataSlotIndex * sizeof(Js::Var),
functionInfoOpnd, instr, !doStackSlots);
Expand Down Expand Up @@ -25151,7 +25153,7 @@ Lowerer::LowerFrameDisplayCheck(IR::Instr * instr)

indirOpnd = IR::IndirOpnd::New(slotArrayOpnd,
Js::ScopeSlots::EncodedSlotCountSlotIndex * sizeof(Js::Var),
TyUint32, m_func, true);
TyVar, m_func, true);
IR::IntConstOpnd * slotIdOpnd = IR::IntConstOpnd::New(slotId - Js::ScopeSlots::FirstSlotIndex,
TyUint32, m_func);
InsertCompareBranch(indirOpnd, slotIdOpnd, Js::OpCode::BrLe_A, true, errorLabel, insertInstr);
Expand Down Expand Up @@ -25206,7 +25208,7 @@ Lowerer::LowerSlotArrayCheck(IR::Instr * instr)

IR::IndirOpnd * indirOpnd = IR::IndirOpnd::New(IR::RegOpnd::New(stackSym, TyVar, m_func),
Js::ScopeSlots::EncodedSlotCountSlotIndex * sizeof(Js::Var),
TyUint32, m_func, true);
TyVar, m_func, true);

slotIdOpnd->SetValue(slotId - Js::ScopeSlots::FirstSlotIndex);
InsertCompareBranch(indirOpnd, slotIdOpnd, Js::OpCode::BrGt_A, true, continueLabel, insertInstr);
Expand Down
10 changes: 10 additions & 0 deletions lib/Backend/LowerMDShared.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,16 @@ LowererMD::GenerateMemRef(intptr_t addr, IRType type, IR::Instr *instr, bool don
return IR::MemRefOpnd::New(addr, type, this->m_func);
}

void
LowererMD::GenerateMemInit(IR::RegOpnd * opnd, int32 offset, size_t value, IR::Instr * insertBeforeInstr, bool isZeroed)
{
#if _M_X64
lowererMDArch.GenerateMemInit(opnd, offset, value, insertBeforeInstr, isZeroed);
#else
m_lowerer->GenerateMemInit(opnd, offset, (uint32)value, insertBeforeInstr, isZeroed);
#endif
}

///----------------------------------------------------------------------------
///
/// LowererMD::InvertBranch
Expand Down
1 change: 1 addition & 0 deletions lib/Backend/LowerMDShared.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ class LowererMD
public:
void Init(Lowerer *lowerer);
IR::Opnd * GenerateMemRef(intptr_t addr, IRType type, IR::Instr *instr, bool dontEncode = false);
void GenerateMemInit(IR::RegOpnd * opnd, int32 offset, size_t value, IR::Instr * insertBeforeInstr, bool isZeroed = false);
IR::Instr * ChangeToHelperCall(IR::Instr * instr, IR::JnHelperMethod helperMethod, IR::LabelInstr *labelBailOut = nullptr,
IR::Opnd *opndInstance = nullptr, IR::PropertySymOpnd * propSymOpnd = nullptr, bool isHelperContinuation = false);
void FinalLower();
Expand Down
22 changes: 22 additions & 0 deletions lib/Backend/amd64/LowererMDArch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -577,6 +577,28 @@ LowererMDArch::SetMaxArgSlots(Js::ArgSlot actualCount /*including this*/)
return;
}

void
LowererMDArch::GenerateMemInit(IR::RegOpnd * opnd, int32 offset, size_t value, IR::Instr * insertBeforeInstr, bool isZeroed)
{
IRType type = TyVar;
if (isZeroed)
{
if (value == 0)
{
// Recycler memory are zero initialized
return;
}

type = value <= UINT_MAX ?
(value <= USHORT_MAX ?
(value <= UCHAR_MAX ? TyUint8 : TyUint16) :
TyUint32) :
type;
}
Func * func = this->m_func;
lowererMD->GetLowerer()->InsertMove(IR::IndirOpnd::New(opnd, offset, type, func), IR::IntConstOpnd::New(value, type, func), insertBeforeInstr);
}

IR::Instr *
LowererMDArch::LowerCallIDynamic(IR::Instr *callInstr, IR::Instr*saveThisArgOutInstr, IR::Opnd *argsLength, ushort callFlags, IR::Instr * insertBeforeInstrForCFG)
{
Expand Down
1 change: 1 addition & 0 deletions lib/Backend/amd64/LowererMDArch.h
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,7 @@ class LowererMDArch
IR::LabelInstr * GetBailOutStackRestoreLabel(BailOutInfo * bailOutInfo, IR::LabelInstr * exitTargetInstr);
void GeneratePreCall(IR::Instr * callInstr, IR::Opnd *functionObjOpnd, IR::Instr* insertBeforeInstrForCFGCheck = nullptr);
void SetMaxArgSlots(Js::ArgSlot actualCount /*including this*/);
void GenerateMemInit(IR::RegOpnd * opnd, int32 offset, size_t value, IR::Instr * insertBeforeInstr, bool isZeroed = false);
};

#define REG_EH_TARGET RegArg0
Expand Down
6 changes: 6 additions & 0 deletions lib/Backend/arm/LowerMD.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -378,6 +378,12 @@ LowererMD::SetMaxArgSlots(Js::ArgSlot actualCount /*including this*/)
return;
}

void
LowererMD::GenerateMemInit(IR::RegOpnd * opnd, int32 offset, size_t value, IR::Instr * insertBeforeInstr, bool isZeroed)
{
m_lowerer->GenerateMemInit(opnd, offset, (uint32)value, insertBeforeInstr, isZeroed);
}

IR::Instr *
LowererMD::LowerCallIDynamic(IR::Instr *callInstr, IR::Instr*saveThisArgOutInstr, IR::Opnd *argsLength, ushort callFlags, IR::Instr * insertBeforeInstrForCFG)
{
Expand Down
1 change: 1 addition & 0 deletions lib/Backend/arm/LowerMD.h
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,7 @@ class LowererMD

void LowerInlineSpreadArgOutLoop(IR::Instr *callInstr, IR::RegOpnd *indexOpnd, IR::RegOpnd *arrayElementsStartOpnd);
void LowerTypeof(IR::Instr * typeOfInstr);
void GenerateMemInit(IR::RegOpnd * opnd, int32 offset, size_t value, IR::Instr * insertBeforeInstr, bool isZeroed = false);

public:
static IR::Instr * InsertCmovCC(const Js::OpCode opCode, IR::Opnd * dst, IR::Opnd* src1, IR::Instr* insertBeforeInstr, bool postRegAlloc);
Expand Down
1 change: 1 addition & 0 deletions lib/Backend/arm64/LowerMD.h
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,7 @@ class LowererMD

void LowerInlineSpreadArgOutLoop(IR::Instr *callInstr, IR::RegOpnd *indexOpnd, IR::RegOpnd *arrayElementsStartOpnd) { __debugbreak(); }
void LowerTypeof(IR::Instr * typeOfInstr) { __debugbreak(); }
void GenerateMemInit(IR::RegOpnd * opnd, int32 offset, size_t value, IR::Instr * insertBeforeInstr, bool isZeroed = false) { __debugbreak(); }
public:
static IR::Instr * InsertCmovCC(const Js::OpCode opCode, IR::Opnd * dst, IR::Opnd* src1, IR::Instr* insertBeforeInstr, bool postRegAlloc) { __debugbreak(); }
};
4 changes: 2 additions & 2 deletions lib/Runtime/Base/FunctionBody.h
Original file line number Diff line number Diff line change
Expand Up @@ -3792,9 +3792,9 @@ namespace Js
slotArray[ScopeMetadataSlotIndex] = scopeMetadataObj;
}

uint GetCount() const
size_t GetCount() const
{
return ::Math::PointerCastToIntegralTruncate<uint>(slotArray[EncodedSlotCountSlotIndex]);
return (size_t)slotArray[EncodedSlotCountSlotIndex];
}

void SetCount(uint count)
Expand Down
2 changes: 1 addition & 1 deletion lib/Runtime/Debug/DiagObjectModel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -643,7 +643,7 @@ namespace Js
}
else if (pFBody->GetPropertyIdsForScopeSlotArray() != nullptr)
{
uint slotArrayCount = slotArray.GetCount();
uint slotArrayCount = static_cast<uint>(slotArray.GetCount());
pMembersList = JsUtil::List<DebuggerPropertyDisplayInfo *, ArenaAllocator>::New(arena, slotArrayCount);

for (uint32 i = 0; i < slotArrayCount; i++)
Expand Down
6 changes: 3 additions & 3 deletions lib/Runtime/Debug/TTSnapshotExtractor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,8 @@ namespace TTD
slotInfo->SlotId = TTD_CONVERT_VAR_TO_PTR_ID(scope);
slotInfo->ScriptContextLogId = ctx->ScriptContextLogTag;

slotInfo->SlotCount = slots.GetCount();
slotInfo->SlotCount = static_cast<uint>(slots.GetCount());

slotInfo->Slots = this->m_pendingSnap->GetSnapshotSlabAllocator().SlabAllocateArray<TTDVar>(slotInfo->SlotCount);

for(uint32 j = 0; j < slotInfo->SlotCount; ++j)
Expand Down Expand Up @@ -324,8 +325,7 @@ namespace TTD
if(this->m_marks.MarkAndTestAddr<MarkTableTag::SlotArrayTag>(scope))
{
Js::ScopeSlots slotArray = (Js::Var*)scope;
uint slotArrayCount = slotArray.GetCount();

uint slotArrayCount = static_cast<uint>(slotArray.GetCount());
if(slotArray.IsFunctionScopeSlotArray())
{
this->MarkFunctionBody(slotArray.GetFunctionInfo()->GetFunctionBody());
Expand Down
2 changes: 1 addition & 1 deletion lib/Runtime/Language/JavascriptOperators.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7020,7 +7020,7 @@ namespace Js
Field(Var)* JavascriptOperators::OP_CloneScopeSlots(Field(Var) *slotArray, ScriptContext *scriptContext)
{
ScopeSlots slots((Js::Var*)slotArray);
uint size = ScopeSlots::FirstSlotIndex + slots.GetCount();
uint size = ScopeSlots::FirstSlotIndex + static_cast<uint>(slots.GetCount());

Field(Var)* slotArrayClone = RecyclerNewArray(scriptContext->GetRecycler(), Field(Var), size);
CopyArray(slotArrayClone, size, slotArray, size);
Expand Down
2 changes: 1 addition & 1 deletion lib/Runtime/Library/ScriptFunction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -560,7 +560,7 @@ namespace Js
case Js::ScopeType::ScopeType_SlotArray:
{
Js::ScopeSlots slotArray = (Js::Var*)scope;
uint slotArrayCount = slotArray.GetCount();
uint slotArrayCount = static_cast<uint>(slotArray.GetCount());

//get the function body associated with the scope
if(slotArray.IsFunctionScopeSlotArray())
Expand Down
22 changes: 10 additions & 12 deletions lib/Runtime/Library/StackScriptFunction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ namespace Js
if (stackScopeSlots)
{
// Scope slot pointer may be null if bailout didn't restore it, which means we don't need it.
Var* boxedScopeSlots = this->BoxScopeSlots(stackScopeSlots, ScopeSlots(stackScopeSlots).GetCount());
Var* boxedScopeSlots = this->BoxScopeSlots(stackScopeSlots, static_cast<uint>(ScopeSlots(stackScopeSlots).GetCount()));
interpreterFrame->SetLocalClosure((Var)boxedScopeSlots);
}
}
Expand Down Expand Up @@ -300,7 +300,7 @@ namespace Js
if (stackScopeSlots)
{
// Scope slot pointer may be null if bailout didn't restore it, which means we don't need it.
this->BoxScopeSlots(stackScopeSlots, ScopeSlots(stackScopeSlots).GetCount());
this->BoxScopeSlots(stackScopeSlots, static_cast<uint>(ScopeSlots(stackScopeSlots).GetCount()));
}
}

Expand Down Expand Up @@ -361,11 +361,10 @@ namespace Js
}
for (; i < frameDisplay->GetLength(); i++)
{
Var *scopeSlots = (Var*)frameDisplay->GetItem(i);
size_t count = ScopeSlots(scopeSlots).GetCount();
if (count < ScopeSlots::MaxEncodedSlotCount)
Var *pScope = (Var*)frameDisplay->GetItem(i);
if (ScopeSlots::Is(pScope))
{
Var *boxedSlots = this->BoxScopeSlots(scopeSlots, static_cast<uint>(count));
Var *boxedSlots = this->BoxScopeSlots(pScope, static_cast<uint>(ScopeSlots(pScope).GetCount()));
frameDisplay->SetItem(i, boxedSlots);
}
}
Expand Down Expand Up @@ -641,15 +640,14 @@ namespace Js
for (uint16 i = 0; i < length; i++)
{
// TODO: Once we allocate the slots on the stack, we can only look those slots
Var * scopeSlots = (Var *)frameDisplay->GetItem(i);
size_t scopeSlotcount = ScopeSlots(scopeSlots).GetCount(); // (size_t)scopeSlots[Js::ScopeSlots::EncodedSlotCountSlotIndex];
Var * pScope = (Var *)frameDisplay->GetItem(i);
// We don't do stack slots if we exceed max encoded slot count
if (scopeSlotcount < ScopeSlots::MaxEncodedSlotCount)
if (ScopeSlots::Is(pScope))
{
scopeSlots = BoxScopeSlots(scopeSlots, static_cast<uint>(scopeSlotcount));
pScope = BoxScopeSlots(pScope, static_cast<uint>(ScopeSlots(pScope).GetCount()));
}
boxedFrameDisplay->SetItem(i, scopeSlots);
frameDisplay->SetItem(i, scopeSlots);
boxedFrameDisplay->SetItem(i, pScope);
frameDisplay->SetItem(i, pScope);
}
return boxedFrameDisplay;
}
Expand Down

0 comments on commit f08408b

Please sign in to comment.