Skip to content

Commit 49a3328

Browse files
committed
[1.11>master] [MERGE #6087 @akroshg] April servicing update for ChakraCore
Merge pull request #6087 from akroshg:stage1904 Fixes CVE-2019-0739 CVE-2019-0806 CVE-2019-0810 CVE-2019-0812 CVE-2019-0829 CVE-2019-0860 CVE-2019-0861
2 parents c81c1f7 + dbfb5bd commit 49a3328

12 files changed

+78
-22
lines changed

lib/Backend/GlobOpt.cpp

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3286,10 +3286,14 @@ GlobOpt::OptSrc(IR::Opnd *opnd, IR::Instr * *pInstr, Value **indirIndexValRef, I
32863286
}
32873287
originalPropertySym = sym->AsPropertySym();
32883288

3289-
// Dont give a value to 'arguments' property sym to prevent field copy prop of 'arguments'
3289+
// Don't give a value to 'arguments' property sym to prevent field copy prop of 'arguments'
32903290
if (originalPropertySym->AsPropertySym()->m_propertyId == Js::PropertyIds::arguments &&
32913291
originalPropertySym->AsPropertySym()->m_fieldKind == PropertyKindData)
32923292
{
3293+
if (opnd->AsSymOpnd()->IsPropertySymOpnd())
3294+
{
3295+
this->FinishOptPropOp(instr, opnd->AsPropertySymOpnd());
3296+
}
32933297
return nullptr;
32943298
}
32953299

@@ -4841,7 +4845,7 @@ GlobOpt::ValueNumberDst(IR::Instr **pInstr, Value *src1Val, Value *src2Val)
48414845
}
48424846
else
48434847
{
4844-
return NewGenericValue(src1ValueInfo->Type().ToDefiniteAnyNumber(), dst);
4848+
return NewGenericValue(src1ValueInfo->Type().ToDefiniteAnyNumber().SetCanBeTaggedValue(true), dst);
48454849
}
48464850
break;
48474851

@@ -4902,7 +4906,7 @@ GlobOpt::ValueNumberDst(IR::Instr **pInstr, Value *src1Val, Value *src2Val)
49024906
{
49034907
valueType = ValueType::Number;
49044908
}
4905-
return CreateDstUntransferredValue(valueType, instr, src1Val, src2Val);
4909+
return CreateDstUntransferredValue(valueType.SetCanBeTaggedValue(true), instr, src1Val, src2Val);
49064910
}
49074911

49084912
case Js::OpCode::Add_A:
@@ -4936,12 +4940,12 @@ GlobOpt::ValueNumberDst(IR::Instr **pInstr, Value *src1Val, Value *src2Val)
49364940
{
49374941
// If one of them is a float, the result probably is a float instead of just int
49384942
// but should always be a number.
4939-
valueType = ValueType::Float;
4943+
valueType = ValueType::Float.SetCanBeTaggedValue(true);
49404944
}
49414945
else
49424946
{
49434947
// Could be int, could be number
4944-
valueType = ValueType::Number;
4948+
valueType = ValueType::Number.SetCanBeTaggedValue(true);
49454949
}
49464950
}
49474951
else if (src1ValueInfo->IsLikelyFloat() || src2ValueInfo->IsLikelyFloat())
@@ -4965,7 +4969,7 @@ GlobOpt::ValueNumberDst(IR::Instr **pInstr, Value *src1Val, Value *src2Val)
49654969
&& (src2Val && src2ValueInfo->IsNotString() && src2ValueInfo->IsPrimitive()))
49664970
{
49674971
// If src1 and src2 are not strings and primitive, add should yield a number.
4968-
valueType = ValueType::Number;
4972+
valueType = ValueType::Number.SetCanBeTaggedValue(true);
49694973
}
49704974
else if((src1Val && src1ValueInfo->IsLikelyString()) || (src2Val && src2ValueInfo->IsLikelyString()))
49714975
{
@@ -4986,7 +4990,7 @@ GlobOpt::ValueNumberDst(IR::Instr **pInstr, Value *src1Val, Value *src2Val)
49864990
ValueType divValueType = GetDivValueType(instr, src1Val, src2Val, false);
49874991
if (divValueType.IsLikelyInt() || divValueType.IsFloat())
49884992
{
4989-
return CreateDstUntransferredValue(divValueType, instr, src1Val, src2Val);
4993+
return CreateDstUntransferredValue(divValueType.SetCanBeTaggedValue(true), instr, src1Val, src2Val);
49904994
}
49914995
}
49924996
// fall-through
@@ -5018,11 +5022,11 @@ GlobOpt::ValueNumberDst(IR::Instr **pInstr, Value *src1Val, Value *src2Val)
50185022
// This should ideally be NewNumberAndLikelyFloatValue since we know the result is a number but not sure if it will
50195023
// be a float value. However, that Number/LikelyFloat value type doesn't exist currently and all the necessary
50205024
// checks are done for float values (tagged int checks, etc.) so it's sufficient to just create a float value here.
5021-
valueType = ValueType::Float;
5025+
valueType = ValueType::Float.SetCanBeTaggedValue(true);
50225026
}
50235027
else
50245028
{
5025-
valueType = ValueType::Number;
5029+
valueType = ValueType::Number.SetCanBeTaggedValue(true);
50265030
}
50275031

50285032
return CreateDstUntransferredValue(valueType, instr, src1Val, src2Val);

lib/Backend/GlobOptFields.cpp

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -229,10 +229,17 @@ GlobOpt::KillLiveElems(IR::IndirOpnd * indirOpnd, BVSparse<JitArenaAllocator> *
229229
this->KillAllFields(bv); // This also kills all property type values, as the same bit-vector tracks those stack syms
230230
SetAnyPropertyMayBeWrittenTo();
231231
}
232-
else if (inGlobOpt && indexOpnd && !indexOpnd->GetValueType().IsInt() && !currentBlock->globOptData.IsInt32TypeSpecialized(indexOpnd->m_sym))
232+
else if (inGlobOpt)
233233
{
234-
// Write/delete to a non-integer numeric index can't alias a name on the RHS of a dot, but it change object layout
235-
this->KillAllObjectTypes(bv);
234+
Value * indexValue = indexOpnd ? this->currentBlock->globOptData.FindValue(indexOpnd->GetSym()) : nullptr;
235+
ValueInfo * indexValueInfo = indexValue ? indexValue->GetValueInfo() : nullptr;
236+
int indexLowerBound = 0;
237+
238+
if (indirOpnd->GetOffset() < 0 || (indexOpnd && (!indexValueInfo || !indexValueInfo->TryGetIntConstantLowerBound(&indexLowerBound, false) || indexLowerBound < 0)))
239+
{
240+
// Write/delete to a non-integer numeric index can't alias a name on the RHS of a dot, but it change object layout
241+
this->KillAllObjectTypes(bv);
242+
}
236243
}
237244
}
238245

@@ -479,7 +486,9 @@ GlobOpt::ProcessFieldKills(IR::Instr *instr, BVSparse<JitArenaAllocator> *bv, bo
479486
case Js::OpCode::NewScObjectNoCtor:
480487
if (inGlobOpt)
481488
{
482-
KillObjectHeaderInlinedTypeSyms(this->currentBlock, false);
489+
// Opcodes that make an object into a prototype may break object-header-inlining and final type opt.
490+
// Kill all known object layouts.
491+
KillAllObjectTypes(bv);
483492
}
484493
break;
485494

lib/Backend/JITType.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ JITType::BuildFromJsType(__in Js::Type * jsType, __out JITType * jitType)
3535

3636
Js::DynamicTypeHandler * handler = dynamicType->GetTypeHandler();
3737
data->handler.isObjectHeaderInlinedTypeHandler = handler->IsObjectHeaderInlinedTypeHandler();
38-
data->handler.isLocked = handler->GetIsLocked();
38+
data->handler.flags = handler->GetFlags();
3939
data->handler.inlineSlotCapacity = handler->GetInlineSlotCapacity();
4040
data->handler.offsetOfInlineSlots = handler->GetOffsetOfInlineSlots();
4141
data->handler.slotCapacity = handler->GetSlotCapacity();

lib/Backend/JITTypeHandler.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,13 @@ JITTypeHandler::IsObjectHeaderInlinedTypeHandler() const
1919
bool
2020
JITTypeHandler::IsLocked() const
2121
{
22-
return m_data.isLocked != FALSE;
22+
return Js::DynamicTypeHandler::GetIsLocked(m_data.flags);
23+
}
24+
25+
bool
26+
JITTypeHandler::IsPrototype() const
27+
{
28+
return Js::DynamicTypeHandler::GetIsPrototype(m_data.flags);
2329
}
2430

2531
uint16

lib/Backend/JITTypeHandler.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ class JITTypeHandler
1212

1313
bool IsObjectHeaderInlinedTypeHandler() const;
1414
bool IsLocked() const;
15+
bool IsPrototype() const;
1516

1617
uint16 GetInlineSlotCapacity() const;
1718
uint16 GetOffsetOfInlineSlots() const;

lib/Backend/Lower.cpp

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6208,7 +6208,7 @@ Lowerer::GenerateLdFldWithCachedType(IR::Instr * instrLdFld, bool* continueAsHel
62086208

62096209
// Load the value from the slot, getting the slot ID from the cache.
62106210
uint16 index = propertySymOpnd->GetSlotIndex();
6211-
Assert(index != -1);
6211+
AssertOrFailFast(index != (uint16)-1);
62126212

62136213
if (opndSlotArray->IsRegOpnd())
62146214
{
@@ -7247,7 +7247,7 @@ Lowerer::GenerateDirectFieldStore(IR::Instr* instrStFld, IR::PropertySymOpnd* pr
72477247

72487248
// Store the value to the slot, getting the slot index from the cache.
72497249
uint16 index = propertySymOpnd->GetSlotIndex();
7250-
Assert(index != -1);
7250+
AssertOrFailFast(index != (uint16)-1);
72517251

72527252
#if defined(RECYCLER_WRITE_BARRIER_JIT) && (defined(_M_IX86) || defined(_M_AMD64))
72537253
if (opndSlotArray->IsRegOpnd())
@@ -7399,6 +7399,19 @@ Lowerer::GenerateStFldWithCachedType(IR::Instr *instrStFld, bool* continueAsHelp
73997399
!instrStFld->HasBailOutInfo() || instrStFld->OnlyHasLazyBailOut(),
74007400
"Why does a direct field store have bailout that is not lazy?"
74017401
);
7402+
7403+
if (propertySymOpnd->HasInitialType() && propertySymOpnd->HasFinalType())
7404+
{
7405+
bool isPrototypeTypeHandler = propertySymOpnd->GetInitialType()->GetTypeHandler()->IsPrototype();
7406+
if (isPrototypeTypeHandler)
7407+
{
7408+
LoadScriptContext(instrStFld);
7409+
m_lowererMD.LoadHelperArgument(instrStFld, IR::IntConstOpnd::New(propertySymOpnd->GetPropertyId(), TyInt32, m_func, true));
7410+
IR::Instr * invalidateCallInstr = IR::Instr::New(Js::OpCode::Call, m_func);
7411+
instrStFld->InsertBefore(invalidateCallInstr);
7412+
m_lowererMD.ChangeToHelperCall(invalidateCallInstr, IR::HelperInvalidateProtoCaches);
7413+
}
7414+
}
74027415
instrStFld->Remove();
74037416
return true;
74047417
}
@@ -8215,6 +8228,16 @@ Lowerer::GenerateFieldStoreWithTypeChange(IR::Instr * instrStFld, IR::PropertySy
82158228

82168229
// Now do the store.
82178230
GenerateDirectFieldStore(instrStFld, propertySymOpnd);
8231+
8232+
bool isPrototypeTypeHandler = initialType->GetTypeHandler()->IsPrototype();
8233+
if (isPrototypeTypeHandler)
8234+
{
8235+
LoadScriptContext(instrStFld);
8236+
m_lowererMD.LoadHelperArgument(instrStFld, IR::IntConstOpnd::New(propertySymOpnd->GetPropertyId(), TyInt32, m_func, true));
8237+
IR::Instr * invalidateCallInstr = IR::Instr::New(Js::OpCode::Call, m_func);
8238+
instrStFld->InsertBefore(invalidateCallInstr);
8239+
m_lowererMD.ChangeToHelperCall(invalidateCallInstr, IR::HelperInvalidateProtoCaches);
8240+
}
82188241
}
82198242

82208243
bool

lib/JITIDL/JITTypes.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ typedef IDL_DEF([ref]) PSCRIPTCONTEXT_HANDLE * PPSCRIPTCONTEXT_HANDLE;
9090
typedef struct TypeHandlerIDL
9191
{
9292
IDL_Field(boolean) isObjectHeaderInlinedTypeHandler;
93-
IDL_Field(boolean) isLocked;
93+
IDL_Field(unsigned char) flags;
9494

9595
IDL_Field(unsigned short) inlineSlotCapacity;
9696
IDL_Field(unsigned short) offsetOfInlineSlots;

lib/Runtime/Language/JavascriptOperators.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9849,6 +9849,11 @@ using namespace Js;
98499849

98509850
Var result = CALL_ENTRYPOINT(threadContext, marshalledFunction->GetEntryPoint(), function, CallInfo(flags, 2), thisVar, putValue);
98519851
Assert(result);
9852+
9853+
// Set implicit call flags so we bail out if we're trying to propagate the stored value forward. We can't count on the getter/setter
9854+
// to produce the stored value on a LdFld.
9855+
threadContext->AddImplicitCallFlags(ImplicitCall_Accessor);
9856+
98529857
return nullptr;
98539858
});
98549859
}

lib/Runtime/Library/JavascriptRegExpConstructor.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -360,6 +360,10 @@ namespace Js
360360
EnsureValues(); // The last match info relies on the last input. Use it before it is changed.
361361
this->lastInput = tempInput;
362362
}
363+
364+
// Set implicit call flags since we are not necessarily making the original stored value available on re-load
365+
// and are killing the store that backs two exposed properties.
366+
this->GetScriptContext()->GetThreadContext()->AddImplicitCallFlags(ImplicitCall_Accessor);
363367
*result = true;
364368
return true;
365369
case PropertyIds::lastMatch:

lib/Runtime/Types/DictionaryTypeHandler.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ namespace Js
139139
PropertyString* propertyString = scriptContext->GetPropertyString(*propertyId);
140140
*propertyStringName = propertyString;
141141
T dataSlot = descriptor.template GetDataPropertyIndex<false>();
142-
if (dataSlot != NoSlots && (attribs & PropertyWritable))
142+
if (dataSlot != NoSlots && (attribs & PropertyWritable) && type == typeToEnumerate)
143143
{
144144
PropertyValueInfo::SetCacheInfo(info, propertyString, propertyString->GetLdElemInlineCache(), false);
145145
SetPropertyValueInfo(info, instance, dataSlot, &descriptor);

0 commit comments

Comments
 (0)