Skip to content
Permalink
Browse files

CVE-2019-0992

  • Loading branch information...
pleath committed May 15, 2019
1 parent 1caa411 commit 53b75c5f4a206740375f6a8a96934242d556e7c4
@@ -5004,16 +5004,24 @@ BackwardPass::UpdateArrayBailOutKind(IR::Instr *const instr)
return;
}

instr->GetDst()->AsIndirOpnd()->AllowConversion(true);
IR::BailOutKind includeBailOutKinds = IR::BailOutInvalid;
if (!baseValueType.IsNotNativeArray() &&
(!baseValueType.IsLikelyNativeArray() || instr->GetSrc1()->IsVar()) &&
!currentBlock->noImplicitCallNativeArrayUses->IsEmpty() &&
!(instr->GetBailOutKind() & IR::BailOutOnArrayAccessHelperCall))
{
// There is an upwards-exposed use of a native array. Since the array referenced by this instruction can be aliased,
// this instruction needs to bail out if it converts the native array even if this array specifically is not
// upwards-exposed.
includeBailOutKinds |= IR::BailOutConvertedNativeArray;
if (!baseValueType.IsLikelyNativeArray() || instr->GetSrc1()->IsVar())
{
includeBailOutKinds |= IR::BailOutConvertedNativeArray;
}
else
{
// We are assuming that array conversion is impossible here, so make sure we execute code that fails if conversion does happen.
instr->GetDst()->AsIndirOpnd()->AllowConversion(false);
}
}

if(baseOpnd->IsArrayRegOpnd() && baseOpnd->AsArrayRegOpnd()->EliminatedUpperBoundCheck())
@@ -2694,6 +2694,39 @@ GlobOpt::OptInstr(IR::Instr *&instr, bool* isInstrRemoved)
return instrNext;
}

bool
GlobOpt::IsNonNumericRegOpnd(IR::RegOpnd *opnd, bool inGlobOpt) const
{
if (opnd == nullptr)
{
return false;
}

if (opnd->m_sym->m_isNotNumber)
{
return true;
}

if (!inGlobOpt)
{
return false;
}

if (opnd->GetValueType().IsNumber() || currentBlock->globOptData.IsTypeSpecialized(opnd->m_sym))
{
if (!this->IsLoopPrePass())
{
return false;
}

Value * opndValue = this->currentBlock->globOptData.FindValue(opnd->m_sym);
ValueInfo * opndValueInfo = opndValue ? opndValue->GetValueInfo() : nullptr;
return !opndValueInfo || !this->IsSafeToTransferInPrepass(opnd->m_sym, opndValueInfo);
}

return true;
}

bool
GlobOpt::OptTagChecks(IR::Instr *instr)
{
@@ -773,6 +773,8 @@ class GlobOpt
const bool lossy = false, const bool forceInvariantHoisting = false, IR::BailOutKind bailoutKind = IR::BailOutInvalid);
void HoistInvariantValueInfo(ValueInfo *const invariantValueInfoToHoist, Value *const valueToUpdate, BasicBlock *const targetBlock);
void OptHoistUpdateValueType(Loop* loop, IR::Instr* instr, IR::Opnd** srcOpndPtr, Value *const srcVal);
bool IsNonNumericRegOpnd(IR::RegOpnd *opnd, bool inGlobOpt) const;

public:
static bool IsTypeSpecPhaseOff(Func const * func);
static bool DoAggressiveIntTypeSpec(Func const * func);
@@ -225,14 +225,7 @@ GlobOpt::KillLiveElems(IR::IndirOpnd * indirOpnd, BVSparse<JitArenaAllocator> *
// - We check the type specialization status for the sym as well. For the purpose of doing kills, we can assume that
// if type specialization happened, that fields don't need to be killed. Note that they may be killed in the next
// pass based on the value.
if (func->GetThisOrParentInlinerHasArguments() ||
(
indexOpnd &&
(
indexOpnd->m_sym->m_isNotNumber ||
(inGlobOpt && !indexOpnd->GetValueType().IsNumber() && !currentBlock->globOptData.IsTypeSpecialized(indexOpnd->m_sym))
)
))
if (func->GetThisOrParentInlinerHasArguments() || this->IsNonNumericRegOpnd(indexOpnd, inGlobOpt))
{
this->KillAllFields(bv); // This also kills all property type values, as the same bit-vector tracks those stack syms
SetAnyPropertyMayBeWrittenTo();
@@ -205,6 +205,12 @@ HELPERCALLCHK(Op_SetNativeIntElementI_Int32, Js::JavascriptOperators::OP_SetNati
HELPERCALLCHK(Op_SetNativeFloatElementI_Int32, Js::JavascriptOperators::OP_SetNativeFloatElementI_Int32, AttrCanThrow)
HELPERCALLCHK(Op_SetNativeIntElementI_UInt32, Js::JavascriptOperators::OP_SetNativeIntElementI_UInt32, AttrCanThrow)
HELPERCALLCHK(Op_SetNativeFloatElementI_UInt32, Js::JavascriptOperators::OP_SetNativeFloatElementI_UInt32, AttrCanThrow)
HELPERCALLCHK(Op_SetNativeIntElementI_NoConvert, Js::JavascriptOperators::OP_SetNativeIntElementI_NoConvert, AttrCanThrow)
HELPERCALLCHK(Op_SetNativeFloatElementI_NoConvert, Js::JavascriptOperators::OP_SetNativeFloatElementI_NoConvert, AttrCanThrow)
HELPERCALLCHK(Op_SetNativeIntElementI_Int32_NoConvert, Js::JavascriptOperators::OP_SetNativeIntElementI_Int32_NoConvert, AttrCanThrow)
HELPERCALLCHK(Op_SetNativeFloatElementI_Int32_NoConvert, Js::JavascriptOperators::OP_SetNativeFloatElementI_Int32_NoConvert, AttrCanThrow)
HELPERCALLCHK(Op_SetNativeIntElementI_UInt32_NoConvert, Js::JavascriptOperators::OP_SetNativeIntElementI_UInt32_NoConvert, AttrCanThrow)
HELPERCALLCHK(Op_SetNativeFloatElementI_UInt32_NoConvert, Js::JavascriptOperators::OP_SetNativeFloatElementI_UInt32_NoConvert, AttrCanThrow)
HELPERCALLCHK(ScrArr_SetNativeIntElementC, Js::JavascriptArray::OP_SetNativeIntElementC, AttrCanNotBeReentrant)
HELPERCALLCHK(ScrArr_SetNativeFloatElementC, Js::JavascriptArray::OP_SetNativeFloatElementC, AttrCanNotBeReentrant)
HELPERCALLCHK(Op_DeleteElementI, Js::JavascriptOperators::OP_DeleteElementI, AttrCanThrow)
@@ -9001,6 +9001,8 @@ Lowerer::LowerStElemI(IR::Instr * instr, Js::PropertyOperationFlags flags, bool

AssertMsg(dst->IsIndirOpnd(), "Expected indirOpnd on StElementI");

bool allowConvert = dst->AsIndirOpnd()->ConversionAllowed();

#if !FLOATVAR
if (dst->AsIndirOpnd()->GetBaseOpnd()->GetValueType().IsLikelyOptimizedTypedArray() && src1->IsRegOpnd())
{
@@ -9085,15 +9087,17 @@ Lowerer::LowerStElemI(IR::Instr * instr, Js::PropertyOperationFlags flags, bool
{
helperMethod =
srcType == TyVar ? IR::HelperOp_SetElementI_Int32 :
srcType == TyInt32 ? IR::HelperOp_SetNativeIntElementI_Int32 :
IR::HelperOp_SetNativeFloatElementI_Int32;
srcType == TyInt32 ?
(allowConvert ? IR::HelperOp_SetNativeIntElementI_Int32 : IR::HelperOp_SetNativeIntElementI_Int32_NoConvert) :
(allowConvert ? IR::HelperOp_SetNativeFloatElementI_Int32 : IR::HelperOp_SetNativeFloatElementI_Int32_NoConvert) ;
}
else if (indexOpnd->GetType() == TyUint32)
{
helperMethod =
srcType == TyVar ? IR::HelperOp_SetElementI_UInt32 :
srcType == TyInt32 ? IR::HelperOp_SetNativeIntElementI_UInt32 :
IR::HelperOp_SetNativeFloatElementI_UInt32;
srcType == TyInt32 ?
(allowConvert ? IR::HelperOp_SetNativeIntElementI_UInt32 : IR::HelperOp_SetNativeIntElementI_UInt32_NoConvert) :
(allowConvert ? IR::HelperOp_SetNativeFloatElementI_UInt32 : IR::HelperOp_SetNativeFloatElementI_UInt32_NoConvert) ;
}
else
{
@@ -9111,8 +9115,9 @@ Lowerer::LowerStElemI(IR::Instr * instr, Js::PropertyOperationFlags flags, bool

if (srcType != TyVar)
{
helperMethod =
srcType == TyInt32 ? IR::HelperOp_SetNativeIntElementI : IR::HelperOp_SetNativeFloatElementI;
helperMethod = srcType == TyInt32 ?
(allowConvert ? IR::HelperOp_SetNativeIntElementI : IR::HelperOp_SetNativeIntElementI_NoConvert) :
(allowConvert ? IR::HelperOp_SetNativeFloatElementI : IR::HelperOp_SetNativeFloatElementI_NoConvert);
}
}

@@ -2538,6 +2538,7 @@ IndirOpnd::New(RegOpnd *baseOpnd, int32 offset, IRType type, Func *func, bool do
indirOpnd->m_type = type;
indirOpnd->SetIsJITOptimizedReg(false);

indirOpnd->m_conversionAllowed = false;

indirOpnd->m_kind = OpndKindIndir;

@@ -2596,6 +2597,7 @@ IndirOpnd::CopyInternal(Func *func)
newOpnd->canStoreTemp = this->canStoreTemp;
newOpnd->SetOffset(m_offset, m_dontEncode);
newOpnd->SetIsJITOptimizedReg(this->GetIsJITOptimizedReg());
newOpnd->m_conversionAllowed = this->m_conversionAllowed;

#if DBG_DUMP
newOpnd->m_addrKind = m_addrKind;
@@ -1662,6 +1662,8 @@ class IndirOpnd: public Opnd
byte GetScale() const;
void SetScale(byte scale);
bool TryGetIntConstIndexValue(bool trySym, IntConstType *pValue, bool *pIsNotInt);
void AllowConversion(bool value) { m_conversionAllowed = value; }
bool ConversionAllowed() const { return m_conversionAllowed; }
#if DBG_DUMP || defined(ENABLE_IR_VIEWER)
const char16 * GetDescription();
IR::AddrOpndKind GetAddrKind() const;
@@ -1678,6 +1680,7 @@ class IndirOpnd: public Opnd
RegOpnd * m_indexOpnd;
int32 m_offset;
byte m_scale;
bool m_conversionAllowed;
Func * m_func; // We need the allocator to copy the base and index...

#if DBG_DUMP || defined(ENABLE_IR_VIEWER)
@@ -4644,6 +4644,120 @@ using namespace Js;
return JavascriptOperators::SetProperty(receiver, object, propertyRecord->GetPropertyId(), value, scriptContext, flags);
}

BOOL JavascriptOperators::OP_SetNativeIntElementI_NoConvert(
Var instance,
Var aElementIndex,
int32 iValue,
ScriptContext* scriptContext,
PropertyOperationFlags flags)
{
JIT_HELPER_REENTRANT_HEADER(Op_SetNativeIntElementI_NoConvert);
JIT_HELPER_SAME_ATTRIBUTES(Op_SetNativeIntElementI_NoConvert, Op_SetNativeIntElementI);
BOOL converted = OP_SetNativeIntElementI(instance, aElementIndex, iValue, scriptContext, flags);
if (converted)
{
AssertMsg(false, "Unexpected native array conversion");
Js::Throw::FatalInternalError();
}
return FALSE;
JIT_HELPER_END(Op_SetNativeIntElementI_NoConvert);
}

BOOL JavascriptOperators::OP_SetNativeIntElementI_UInt32_NoConvert(
Var instance,
uint32 aElementIndex,
int32 iValue,
ScriptContext* scriptContext,
PropertyOperationFlags flags)
{
JIT_HELPER_REENTRANT_HEADER(Op_SetNativeIntElementI_UInt32_NoConvert);
JIT_HELPER_SAME_ATTRIBUTES(Op_SetNativeIntElementI_UInt32_NoConvert, Op_SetNativeIntElementI_UInt32);
BOOL converted = OP_SetNativeIntElementI_UInt32(instance, aElementIndex, iValue, scriptContext, flags);
if (converted)
{
AssertMsg(false, "Unexpected native array conversion");
Js::Throw::FatalInternalError();
}
return FALSE;
JIT_HELPER_END(Op_SetNativeIntElementI_UInt32_NoConvert);
}

BOOL JavascriptOperators::OP_SetNativeIntElementI_Int32_NoConvert(
Var instance,
int32 aElementIndex,
int32 iValue,
ScriptContext* scriptContext,
PropertyOperationFlags flags)
{
JIT_HELPER_REENTRANT_HEADER(Op_SetNativeIntElementI_Int32_NoConvert);
JIT_HELPER_SAME_ATTRIBUTES(Op_SetNativeIntElementI_Int32_NoConvert, Op_SetNativeIntElementI_Int32);
BOOL converted = OP_SetNativeIntElementI_Int32(instance, aElementIndex, iValue, scriptContext, flags);
if (converted)
{
AssertMsg(false, "Unexpected native array conversion");
Js::Throw::FatalInternalError();
}
return FALSE;
JIT_HELPER_END(Op_SetNativeIntElementI_Int32_NoConvert);
}

BOOL JavascriptOperators::OP_SetNativeFloatElementI_NoConvert(
Var instance,
Var aElementIndex,
ScriptContext* scriptContext,
PropertyOperationFlags flags,
double dValue)
{
JIT_HELPER_REENTRANT_HEADER(Op_SetNativeFloatElementI_NoConvert);
JIT_HELPER_SAME_ATTRIBUTES(Op_SetNativeFloatElementI_NoConvert, Op_SetNativeFloatElementI);
BOOL converted = OP_SetNativeFloatElementI(instance, aElementIndex, scriptContext, flags, dValue);
if (converted)
{
AssertMsg(false, "Unexpected native array conversion");
Js::Throw::FatalInternalError();
}
return FALSE;
JIT_HELPER_END(Op_SetNativeFloatElementI_NoConvert);
}

BOOL JavascriptOperators::OP_SetNativeFloatElementI_UInt32_NoConvert(
Var instance,
uint32 aElementIndex,
ScriptContext* scriptContext,
PropertyOperationFlags flags,
double dValue)
{
JIT_HELPER_REENTRANT_HEADER(Op_SetNativeFloatElementI_UInt32_NoConvert);
JIT_HELPER_SAME_ATTRIBUTES(Op_SetNativeFloatElementI_NoConvert, Op_SetNativeFloatElementI_UInt32);
BOOL converted = OP_SetNativeFloatElementI_UInt32(instance, aElementIndex, scriptContext, flags, dValue);
if (converted)
{
AssertMsg(false, "Unexpected native array conversion");
Js::Throw::FatalInternalError();
}
return FALSE;
JIT_HELPER_END(Op_SetNativeFloatElementI_UInt32_NoConvert);
}

BOOL JavascriptOperators::OP_SetNativeFloatElementI_Int32_NoConvert(
Var instance,
int32 aElementIndex,
ScriptContext* scriptContext,
PropertyOperationFlags flags,
double dValue)
{
JIT_HELPER_REENTRANT_HEADER(Op_SetNativeFloatElementI_Int32_NoConvert);
JIT_HELPER_SAME_ATTRIBUTES(Op_SetNativeFloatElementI_NoConvert, Op_SetNativeFloatElementI_Int32);
BOOL converted = OP_SetNativeFloatElementI_Int32(instance, aElementIndex, scriptContext, flags, dValue);
if (converted)
{
AssertMsg(false, "Unexpected native array conversion");
Js::Throw::FatalInternalError();
}
return FALSE;
JIT_HELPER_END(Op_SetNativeFloatElementI_Int32_NoConvert);
}

BOOL JavascriptOperators::OP_SetNativeIntElementI(
Var instance,
Var aElementIndex,
@@ -392,6 +392,12 @@ namespace Js
static BOOL OP_SetElementI_UInt32(Var instance, uint32 aElementIndex, Var aValue, ScriptContext* scriptContext, PropertyOperationFlags flags = PropertyOperation_None);
static BOOL OP_SetElementI_Int32(Var instance, int32 aElementIndex, Var aValue, ScriptContext* scriptContext, PropertyOperationFlags flags = PropertyOperation_None);
static BOOL SetElementIHelper(Var receiver, RecyclableObject* object, Var index, Var value, ScriptContext* scriptContext, PropertyOperationFlags flags);
static BOOL OP_SetNativeIntElementI_NoConvert(Var instance, Var aElementIndex, int32 aValue, ScriptContext* scriptContext, PropertyOperationFlags flags = PropertyOperation_None);
static BOOL OP_SetNativeIntElementI_UInt32_NoConvert(Var instance, uint32 aElementIndex, int32 aValue, ScriptContext* scriptContext, PropertyOperationFlags flags = PropertyOperation_None);
static BOOL OP_SetNativeIntElementI_Int32_NoConvert(Var instance, int aElementIndex, int32 aValue, ScriptContext* scriptContext, PropertyOperationFlags flags = PropertyOperation_None);
static BOOL OP_SetNativeFloatElementI_NoConvert(Var instance, Var aElementIndex, ScriptContext* scriptContext, PropertyOperationFlags flags, double value);
static BOOL OP_SetNativeFloatElementI_UInt32_NoConvert(Var instance, uint32 aElementIndex, ScriptContext* scriptContext, PropertyOperationFlags flags, double value);
static BOOL OP_SetNativeFloatElementI_Int32_NoConvert(Var instance, int aElementIndex, ScriptContext* scriptContext, PropertyOperationFlags flags, double value);
static BOOL OP_SetNativeIntElementI(Var instance, Var aElementIndex, int32 aValue, ScriptContext* scriptContext, PropertyOperationFlags flags = PropertyOperation_None);
static BOOL OP_SetNativeIntElementI_UInt32(Var instance, uint32 aElementIndex, int32 aValue, ScriptContext* scriptContext, PropertyOperationFlags flags = PropertyOperation_None);
static BOOL OP_SetNativeIntElementI_Int32(Var instance, int aElementIndex, int32 aValue, ScriptContext* scriptContext, PropertyOperationFlags flags = PropertyOperation_None);

0 comments on commit 53b75c5

Please sign in to comment.
You can’t perform that action at this time.