Permalink
Browse files

[CVE-2017-8601] Generate bailouts for cases of typed array stores whe…

…re conversion of the source value can cause implicit calls. For BailOutOnImplicitCalls, check implicit call bit on return from the conversion helper. For BailOutOnArrayAccessHelperCall, bail out instead of calling the conversion helper.
  • Loading branch information...
pleath committed Jul 11, 2017
1 parent 3915540 commit 9326bda18a18a810b59f0ef39c0eabc1c8b6406f
const IR::AutoReuseOpnd autoReuseReg(reg, m_func);
InsertMove(reg, src, stElem);

bool bailOutOnHelperCall = stElem->HasBailOutInfo() && (stElem->GetBailOutKind() & IR::BailOutOnArrayAccessHelperCall);

// Convert to float, and assign to indirOpnd
if (baseValueType.IsLikelyOptimizedVirtualTypedArray())
{
IR::RegOpnd* dstReg = IR::RegOpnd::New(indirOpnd->GetType(), this->m_func);
m_lowererMD.EmitLoadFloat(dstReg, reg, stElem, bailOutOnHelperCall);
m_lowererMD.EmitLoadFloat(dstReg, reg, stElem, stElem, labelHelper);
InsertMove(indirOpnd, dstReg, stElem);
}
else
{
m_lowererMD.EmitLoadFloat(indirOpnd, reg, stElem, bailOutOnHelperCall);
m_lowererMD.EmitLoadFloat(indirOpnd, reg, stElem, stElem, labelHelper);
}

}
}
else if (objectType == ObjectType::Uint8ClampedArray || objectType == ObjectType::Uint8ClampedVirtualArray || objectType == ObjectType::Uint8ClampedMixedArray)
// Any pointer is larger than 512 because first 64k memory is reserved by the OS
// #endif

IR::LabelInstr *labelInlineSet = IR::LabelInstr::New(Js::OpCode::Label, this->m_func, true);
IR::LabelInstr *labelInlineSet = IR::LabelInstr::New(Js::OpCode::Label, this->m_func);
#ifndef _M_ARM
// TEST src, ~(TaggedInt(255)) -- Check for tagged int >= 255 and <= 0
// JEQ $inlineSet

// Uint8ClampedArray::DirectSetItem(array, index, value);

m_lowererMD.LoadHelperArgument(stElem, regSrc);
IR::Opnd *indexOpnd = indirOpnd->GetIndexOpnd();
if (indexOpnd == nullptr)
// Inserting a helper call. Make sure it observes the main instructions's requirements regarding implicit calls.
if (!instrIsInHelperBlock)
{
indexOpnd = IR::IntConstOpnd::New(indirOpnd->GetOffset(), TyInt32, this->m_func);
stElem->InsertBefore(IR::LabelInstr::New(Js::OpCode::Label, m_func, true));
}
else

if (stElem->HasBailOutInfo() && (stElem->GetBailOutKind() & IR::BailOutOnArrayAccessHelperCall))
{
Assert(indirOpnd->GetOffset() == 0);
// Bail out instead of doing the helper call.
Assert(labelHelper);
this->InsertBranch(Js::OpCode::Br, labelHelper, stElem);
}
m_lowererMD.LoadHelperArgument(stElem, indexOpnd);
m_lowererMD.LoadHelperArgument(stElem, stElem->GetDst()->AsIndirOpnd()->GetBaseOpnd());
else
{
IR::Instr *instr = IR::Instr::New(Js::OpCode::Call, this->m_func);
stElem->InsertBefore(instr);

IR::Instr *instr = IR::Instr::New(Js::OpCode::Call, this->m_func);
if (stElem->HasBailOutInfo() && BailOutInfo::IsBailOutOnImplicitCalls(stElem->GetBailOutKind()))
{
// Bail out if this helper triggers implicit calls.
instr = instr->ConvertToBailOutInstr(stElem->GetBailOutInfo(), stElem->GetBailOutKind());
if (stElem->GetBailOutInfo()->bailOutInstr == stElem)
{
IR::Instr * instrShare = stElem->ShareBailOut();
LowerBailTarget(instrShare);
}
}

Assert(objectType == ObjectType::Uint8ClampedArray || objectType == ObjectType::Uint8ClampedMixedArray || objectType == ObjectType::Uint8ClampedVirtualArray);
instr->SetSrc1(IR::HelperCallOpnd::New(IR::HelperUint8ClampedArraySetItem, this->m_func));
m_lowererMD.LoadHelperArgument(instr, regSrc);
IR::Opnd *indexOpnd = indirOpnd->GetIndexOpnd();
if (indexOpnd == nullptr)
{
indexOpnd = IR::IntConstOpnd::New(indirOpnd->GetOffset(), TyInt32, this->m_func);
}
else
{
Assert(indirOpnd->GetOffset() == 0);
}
m_lowererMD.LoadHelperArgument(instr, indexOpnd);
m_lowererMD.LoadHelperArgument(instr, stElem->GetDst()->AsIndirOpnd()->GetBaseOpnd());

stElem->InsertBefore(instr);
m_lowererMD.LowerCall(instr, 0);
Assert(objectType == ObjectType::Uint8ClampedArray || objectType == ObjectType::Uint8ClampedMixedArray || objectType == ObjectType::Uint8ClampedVirtualArray);
m_lowererMD.ChangeToHelperCall(instr, IR::JnHelperMethod::HelperUint8ClampedArraySetItem);

// JMP $fallThrough
InsertBranch(Js::OpCode::Br, labelFallThru, stElem);
// JMP $fallThrough
InsertBranch(Js::OpCode::Br, labelFallThru, stElem);
}

//$inlineSet
stElem->InsertBefore(labelInlineSet);
AssertMsg(AutoSystemInfo::Data.SSE2Available(), "GloOpt shouldn't have specialized Uint32Array StElemI to float64 if SSE2 is unavailable.");
#endif

bool bailOutOnHelperCall = stElem->HasBailOutInfo() ? !!(stElem->GetBailOutKind() & IR::BailOutOnArrayAccessHelperCall) : false;
if (bailOutOnHelperCall)
{
if(!GlobOpt::DoEliminateArrayAccessHelperCall(this->m_func))
{
// Array access helper call removal is already off for some reason. Prevent trying to rejit again
// because it won't help and the same thing will happen again. Just abort jitting this function.
if(PHASE_TRACE(Js::BailOutPhase, this->m_func))
{
Output::Print(_u(" Aborting JIT because EliminateArrayAccessHelperCall is already off\n"));
Output::Flush();
}
throw Js::OperationAbortedException();
}

throw Js::RejitException(RejitReason::ArrayAccessHelperCallEliminationDisabled);
}

IR::RegOpnd *const reg = IR::RegOpnd::New(TyInt32, this->m_func);
const IR::AutoReuseOpnd autoReuseReg(reg, m_func);
m_lowererMD.EmitFloatToInt(reg, src, stElem);
m_lowererMD.EmitFloatToInt(reg, src, stElem, stElem, labelHelper);

// MOV indirOpnd, reg
InsertMove(indirOpnd, reg, stElem);
// FromVar reg, Src
IR::RegOpnd *const reg = IR::RegOpnd::New(TyInt32, this->m_func);
const IR::AutoReuseOpnd autoReuseReg(reg, m_func);
IR::Instr *const instr = IR::Instr::New(Js::OpCode::FromVar, reg, regSrc, stElem->m_func);
IR::Instr * instr = IR::Instr::New(Js::OpCode::FromVar, reg, regSrc, stElem->m_func);
stElem->InsertBefore(instr);

// Convert reg to int32
// Note: ToUint32 is implemented as (uint32)ToInt32()
bool bailOutOnHelperCall = (stElem->HasBailOutInfo() && (stElem->GetBailOutKind() & IR::BailOutOnArrayAccessHelperCall));
IR::BailOutKind bailOutKind = stElem->HasBailOutInfo() ? stElem->GetBailOutKind() : IR::BailOutInvalid;
if (BailOutInfo::IsBailOutOnImplicitCalls(bailOutKind))
{
instr = instr->ConvertToBailOutInstr(stElem->GetBailOutInfo(), bailOutKind);
if (stElem->GetBailOutInfo()->bailOutInstr == stElem)
{
IR::Instr * instrShare = stElem->ShareBailOut();
LowerBailTarget(instrShare);
}
}

bool bailOutOnHelperCall = !!(bailOutKind & IR::BailOutOnArrayAccessHelperCall);
m_lowererMD.EmitLoadInt32(instr, true /*conversionFromObjectAllowed*/, bailOutOnHelperCall, labelHelper);

// MOV indirOpnd, reg
@@ -6732,8 +6732,8 @@ LowererMD::EmitLoadFloatCommon(IR::Opnd *dst, IR::Opnd *src, IR::Instr *insertIn
return labelDone;
}

IR::RegOpnd *
LowererMD::EmitLoadFloat(IR::Opnd *dst, IR::Opnd *src, IR::Instr *insertInstr, bool bailOutOnHelperCall)
void
LowererMD::EmitLoadFloat(IR::Opnd *dst, IR::Opnd *src, IR::Instr *insertInstr, IR::Instr * instrBailOut, IR::LabelInstr * labelBailOut)
{
IR::LabelInstr *labelDone;
IR::Instr *instr;
@@ -6742,24 +6742,17 @@ LowererMD::EmitLoadFloat(IR::Opnd *dst, IR::Opnd *src, IR::Instr *insertInstr, b
if (labelDone == nullptr)
{
// We're done
return nullptr;
return;
}

if (bailOutOnHelperCall)
IR::BailOutKind bailOutKind = instrBailOut && instrBailOut->HasBailOutInfo() ? instrBailOut->GetBailOutKind() : IR::BailOutInvalid;
if (bailOutKind & IR::BailOutOnArrayAccessHelperCall)
{
if(!GlobOpt::DoEliminateArrayAccessHelperCall(this->m_func))
{
// Array access helper call removal is already off for some reason. Prevent trying to rejit again
// because it won't help and the same thing will happen again. Just abort jitting this function.
if(PHASE_TRACE(Js::BailOutPhase, this->m_func))
{
Output::Print(_u(" Aborting JIT because EliminateArrayAccessHelperCall is already off\n"));
Output::Flush();
}
throw Js::OperationAbortedException();
}

throw Js::RejitException(RejitReason::ArrayAccessHelperCallEliminationDisabled);
// Bail out instead of making the helper call.
Assert(labelBailOut);
m_lowerer->InsertBranch(Js::OpCode::Br, labelBailOut, insertInstr);
insertInstr->InsertBefore(labelDone);
return;
}

IR::Opnd *memAddress = dst;
@@ -6785,6 +6778,16 @@ LowererMD::EmitLoadFloat(IR::Opnd *dst, IR::Opnd *src, IR::Instr *insertInstr, b
instr->SetSrc2(reg3Opnd);
insertInstr->InsertBefore(instr);

if (BailOutInfo::IsBailOutOnImplicitCalls(bailOutKind))
{
instr = instr->ConvertToBailOutInstr(instrBailOut->GetBailOutInfo(), bailOutKind);
if (instrBailOut->GetBailOutInfo()->bailOutInstr == instrBailOut)
{
IR::Instr * instrShare = instrBailOut->ShareBailOut();
m_lowerer->LowerBailTarget(instrShare);
}
}

IR::JnHelperMethod helper;
if (dst->GetType() == TyFloat32)
{
@@ -6813,8 +6816,6 @@ LowererMD::EmitLoadFloat(IR::Opnd *dst, IR::Opnd *src, IR::Instr *insertInstr, b
}
// $Done
insertInstr->InsertBefore(labelDone);

return nullptr;
}

void
@@ -8362,13 +8363,26 @@ LowererMD::InsertConvertFloat64ToInt32(const RoundMode roundMode, IR::Opnd *cons
}

void
LowererMD::EmitFloatToInt(IR::Opnd *dst, IR::Opnd *src, IR::Instr *instrInsert)
LowererMD::EmitFloatToInt(IR::Opnd *dst, IR::Opnd *src, IR::Instr *instrInsert, IR::Instr *instrBailOut, IR::LabelInstr * labelBailOut)
{
#ifdef _M_IX86
// We should only generate this if sse2 is available
Assert(AutoSystemInfo::Data.SSE2Available());
#endif

IR::BailOutKind bailOutKind = IR::BailOutInvalid;
if (instrBailOut && instrBailOut->HasBailOutInfo())
{
bailOutKind = instrBailOut->GetBailOutKind();
if (bailOutKind & IR::BailOutOnArrayAccessHelperCall)
{
// Bail out instead of calling helper. If this is happening unconditionally, the caller should instead throw a rejit exception.
Assert(labelBailOut);
m_lowerer->InsertBranch(Js::OpCode::Br, labelBailOut, instrInsert);
return;
}
}

IR::LabelInstr *labelDone = IR::LabelInstr::New(Js::OpCode::Label, this->m_func);
IR::LabelInstr *labelHelper = IR::LabelInstr::New(Js::OpCode::Label, this->m_func, true);
IR::Instr *instr;
@@ -8385,11 +8399,23 @@ LowererMD::EmitFloatToInt(IR::Opnd *dst, IR::Opnd *src, IR::Instr *instrInsert)

EmitFloat32ToFloat64(arg, src, instrInsert);
}
// dst = ToInt32Core(src);
LoadDoubleHelperArgument(instrInsert, arg);

instr = IR::Instr::New(Js::OpCode::CALL, dst, this->m_func);
instrInsert->InsertBefore(instr);

if (BailOutInfo::IsBailOutOnImplicitCalls(bailOutKind))
{
instr = instr->ConvertToBailOutInstr(instrBailOut->GetBailOutInfo(), bailOutKind);
if (instrBailOut->GetBailOutInfo()->bailOutInstr == instrBailOut)
{
IR::Instr * instrShare = instrBailOut->ShareBailOut();
m_lowerer->LowerBailTarget(instrShare);
}
}

// dst = ToInt32Core(src);
LoadDoubleHelperArgument(instr, arg);

this->ChangeToHelperCall(instr, IR::HelperConv_ToInt32Core);

// $Done
@@ -217,13 +217,13 @@ class LowererMD
void EmitIntToLong(IR::Opnd *dst, IR::Opnd *src, IR::Instr *instrInsert);
void EmitUIntToLong(IR::Opnd *dst, IR::Opnd *src, IR::Instr *instrInsert);
void EmitLongToInt(IR::Opnd *dst, IR::Opnd *src, IR::Instr *instrInsert);
void EmitFloatToInt(IR::Opnd *dst, IR::Opnd *src, IR::Instr *instrInsert);
void EmitFloatToInt(IR::Opnd *dst, IR::Opnd *src, IR::Instr *instrInsert, IR::Instr * instrBailOut = nullptr, IR::LabelInstr * labelBailOut = nullptr);
void EmitInt64toFloat(IR::Opnd *dst, IR::Opnd *src, IR::Instr *instrInsert);
void EmitFloat32ToFloat64(IR::Opnd *dst, IR::Opnd *src, IR::Instr *instrInsert);
static IR::Instr *InsertConvertFloat64ToInt32(const RoundMode roundMode, IR::Opnd *const dst, IR::Opnd *const src, IR::Instr *const insertBeforeInstr);
void ConvertFloatToInt32(IR::Opnd* intOpnd, IR::Opnd* floatOpnd, IR::LabelInstr * labelHelper, IR::LabelInstr * labelDone, IR::Instr * instInsert);
void EmitLoadFloatFromNumber(IR::Opnd *dst, IR::Opnd *src, IR::Instr *insertInstr);
IR::RegOpnd * EmitLoadFloat(IR::Opnd *dst, IR::Opnd *src, IR::Instr *insertInstr, bool bailOutOnHelperCall = false);
void EmitLoadFloat(IR::Opnd *dst, IR::Opnd *src, IR::Instr *insertInstr, IR::Instr * instrBailOut = nullptr, IR::LabelInstr * labelBailOut = nullptr);
static void EmitNon32BitOvfCheck(IR::Instr *instr, IR::Instr *insertInstr, IR::LabelInstr* bailOutLabel);

static void LowerInt4NegWithBailOut(IR::Instr *const instr, const IR::BailOutKind bailOutKind, IR::LabelInstr *const bailOutLabel, IR::LabelInstr *const skipBailOutLabel);
Oops, something went wrong.

0 comments on commit 9326bda

Please sign in to comment.