Skip to content

Commit ea97a60

Browse files
committed
[CVE-2019-0652] Chakracore Tianfucup Arguments UaF - Tencent
1 parent 0f7e500 commit ea97a60

19 files changed

+175
-6
lines changed

lib/Runtime/Types/DeferredTypeHandler.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,11 @@ namespace Js
2020
// be certain that the type has only writable data properties.
2121
}
2222

23+
DeferredTypeHandlerBase(DeferredTypeHandlerBase * typeHandler) : DynamicTypeHandler(typeHandler)
24+
{
25+
Assert(this->GetIsInlineSlotCapacityLocked() == typeHandler->GetIsInlineSlotCapacityLocked());
26+
Assert(this->GetHasOnlyWritableDataProperties() == typeHandler->GetHasOnlyWritableDataProperties());
27+
}
2328
public:
2429
void ConvertFunction(JavascriptFunction * instance, DynamicTypeHandler * handler);
2530
void Convert(DynamicObject * instance, DeferredInitializeMode mode, int initSlotCapacity, BOOL hasAccessor = false);
@@ -75,10 +80,15 @@ namespace Js
7580

7681
private:
7782
DeferredTypeHandler() : DeferredTypeHandlerBase(isPrototypeTemplate, _inlineSlotCapacity, _offsetOfInlineSlots), m_initializer(initializer) { }
83+
DeferredTypeHandler(DeferredTypeHandler * typeHandler) :
84+
DeferredTypeHandlerBase(typeHandler),
85+
m_initializer(typeHandler->m_initializer)
86+
{}
7887

7988
public:
8089
static DeferredTypeHandler *GetDefaultInstance() { return &defaultInstance; }
8190

91+
virtual DynamicTypeHandler * Clone(Recycler* recycler);
8292
virtual BOOL IsLockable() const override { return true; }
8393
virtual BOOL IsSharable() const override { return true; }
8494
virtual int GetPropertyCount() override;
@@ -156,6 +166,12 @@ namespace Js
156166
template <DeferredTypeInitializer initializer, typename DeferredTypeFilter, bool isPrototypeTemplate, uint16 _inlineSlotCapacity, uint16 _offsetOfInlineSlots>
157167
DeferredTypeHandler<initializer, DeferredTypeFilter, isPrototypeTemplate, _inlineSlotCapacity, _offsetOfInlineSlots> DeferredTypeHandler<initializer, DeferredTypeFilter, isPrototypeTemplate, _inlineSlotCapacity, _offsetOfInlineSlots>::defaultInstance;
158168

169+
template <DeferredTypeInitializer initializer, typename DeferredTypeFilter, bool isPrototypeTemplate, uint16 _inlineSlotCapacity, uint16 _offsetOfInlineSlots>
170+
DynamicTypeHandler * DeferredTypeHandler<initializer, DeferredTypeFilter, isPrototypeTemplate, _inlineSlotCapacity, _offsetOfInlineSlots>::Clone(Recycler * recycler)
171+
{
172+
return RecyclerNew(recycler, DeferredTypeHandler, this);
173+
}
174+
159175
template <DeferredTypeInitializer initializer, typename DeferredTypeFilter, bool isPrototypeTemplate, uint16 _inlineSlotCapacity, uint16 _offsetOfInlineSlots>
160176
int DeferredTypeHandler<initializer, DeferredTypeFilter, isPrototypeTemplate, _inlineSlotCapacity, _offsetOfInlineSlots>::GetPropertyCount()
161177
{

lib/Runtime/Types/DictionaryTypeHandler.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,24 @@ namespace Js
5353
CopyPropertyTypes(PropertyTypesWritableDataOnly | PropertyTypesWritableDataOnlyDetection | PropertyTypesInlineSlotCapacityLocked | PropertyTypesHasSpecialProperties, typeHandler->GetPropertyTypes());
5454
}
5555

56+
template <typename T>
57+
DictionaryTypeHandlerBase<T>::DictionaryTypeHandlerBase(Recycler* recycler, DictionaryTypeHandlerBase * typeHandler) :
58+
DynamicTypeHandler(typeHandler),
59+
nextPropertyIndex(typeHandler->nextPropertyIndex)
60+
#if ENABLE_FIXED_FIELDS
61+
, singletonInstance(nullptr)
62+
#endif
63+
{
64+
Assert(this->GetIsInlineSlotCapacityLocked() == typeHandler->GetIsInlineSlotCapacityLocked());
65+
propertyMap = typeHandler->propertyMap->Clone();
66+
}
67+
68+
template <typename T>
69+
DynamicTypeHandler * DictionaryTypeHandlerBase<T>::Clone(Recycler * recycler)
70+
{
71+
return RecyclerNew(recycler, DictionaryTypeHandlerBase, recycler, this);
72+
}
73+
5674
template <typename T>
5775
int DictionaryTypeHandlerBase<T>::GetPropertyCount()
5876
{

lib/Runtime/Types/DictionaryTypeHandler.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ namespace Js
4646
DictionaryTypeHandlerBase(Recycler* recycler);
4747
DictionaryTypeHandlerBase(Recycler* recycler, int slotCapacity, uint16 inlineSlotCapacity, uint16 offsetOfInlineSlots);
4848
DictionaryTypeHandlerBase(DictionaryTypeHandlerBase* typeHandler);
49+
DictionaryTypeHandlerBase(Recycler* recycler, DictionaryTypeHandlerBase * typeHandler);
4950
DEFINE_VTABLE_CTOR_NO_REGISTER(DictionaryTypeHandlerBase, DynamicTypeHandler);
5051

5152
// Create a new type handler for a future DynamicObject. This is for public usage. "initialCapacity" indicates desired slotCapacity, subject to alignment round up.
@@ -62,6 +63,8 @@ namespace Js
6263
// Create a new type handler for a future DynamicObject. This is for public usage. "initialCapacity" indicates desired slotCapacity, subject to alignment round up.
6364
static DictionaryTypeHandlerBase* New(Recycler * recycler, int initialCapacity, uint16 inlineSlotCapacity, uint16 offsetOfInlineSlots);
6465

66+
virtual DynamicTypeHandler * Clone(Recycler * recycler);
67+
6568
BOOL IsBigDictionaryTypeHandler();
6669

6770
virtual BOOL IsLockable() const override { return false; }

lib/Runtime/Types/DynamicObject.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,14 @@ namespace Js
5151
auxSlots(instance->auxSlots),
5252
objectArray(instance->objectArray) // copying the array should copy the array flags and array call site index as well
5353
{
54+
if (deepCopy)
55+
{
56+
if (!instance->GetDynamicType()->ShareType())
57+
{
58+
this->type = instance->DuplicateTypeAndTypeHandler();
59+
}
60+
}
61+
5462
DynamicTypeHandler * typeHandler = this->GetTypeHandler();
5563

5664
// TODO: stack allocate aux Slots
@@ -526,6 +534,13 @@ namespace Js
526534
return RecyclerNew(GetRecycler(), DynamicType, this->GetDynamicType());
527535
}
528536

537+
DynamicType* DynamicObject::DuplicateTypeAndTypeHandler()
538+
{
539+
DynamicType * newType = DuplicateType();
540+
newType->typeHandler = newType->DuplicateTypeHandler();
541+
return newType;
542+
}
543+
529544
void DynamicObject::PrepareForConversionToNonPathType()
530545
{
531546
// Nothing to do in base class

lib/Runtime/Types/DynamicObject.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,7 @@ namespace Js
304304
virtual BOOL IsCrossSiteObject() const { return FALSE; }
305305

306306
virtual DynamicType* DuplicateType();
307+
DynamicType* DuplicateTypeAndTypeHandler();
307308
virtual void PrepareForConversionToNonPathType();
308309
static bool IsTypeHandlerCompatibleForObjectHeaderInlining(DynamicTypeHandler * oldTypeHandler, DynamicTypeHandler * newTypeHandler);
309310

lib/Runtime/Types/DynamicType.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ namespace Js
150150
Assert(this->GetTypeHandler()->IsSharable());
151151
return true;
152152
}
153-
if (this->GetTypeHandler()->IsSharable())
153+
if (this->GetTypeHandler()->IsSharable() && this->GetTypeHandler()->GetMayBecomeShared())
154154
{
155155
LockType();
156156
this->GetTypeHandler()->ShareTypeHandler(this->GetScriptContext());
@@ -160,6 +160,11 @@ namespace Js
160160
return false;
161161
}
162162

163+
DynamicTypeHandler * DynamicType::DuplicateTypeHandler()
164+
{
165+
return GetTypeHandler()->Clone(this->GetRecycler());
166+
}
167+
163168
bool
164169
DynamicType::SetHasNoEnumerableProperties(bool value)
165170
{

lib/Runtime/Types/DynamicType.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ namespace Js
4040

4141
public:
4242
DynamicTypeHandler * GetTypeHandler() const { return typeHandler; }
43+
DynamicTypeHandler * DuplicateTypeHandler();
4344

4445
void SetPrototype(RecyclableObject* newPrototype) { this->prototype = newPrototype; }
4546
bool GetIsLocked() const { return this->isLocked; }

lib/Runtime/Types/ES5ArrayTypeHandler.cpp

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,28 @@ namespace Js
1414
indexPropertyMap = RecyclerNew(recycler, InnerMap, recycler);
1515
}
1616

17+
IndexPropertyDescriptorMap::IndexPropertyDescriptorMap(Recycler* recycler, const IndexPropertyDescriptorMap * const indexPropertyDescriptorMap)
18+
: recycler(recycler), lastIndexAt(indexPropertyDescriptorMap->lastIndexAt)
19+
{
20+
indexList = indexPropertyDescriptorMap->CopyIndexList();
21+
indexPropertyMap = indexPropertyDescriptorMap->indexPropertyMap->Clone();
22+
}
23+
24+
IndexPropertyDescriptorMap * IndexPropertyDescriptorMap::Clone(Recycler * recycler)
25+
{
26+
return RecyclerNew(recycler, IndexPropertyDescriptorMap, recycler, this);
27+
}
28+
29+
uint32 * IndexPropertyDescriptorMap::CopyIndexList() const
30+
{
31+
uint32 * newList = RecyclerNewArrayLeaf(recycler, uint32, Count());
32+
for (int i = 0; i < Count(); i++)
33+
{
34+
newList[i] = this->indexList[i];
35+
}
36+
return newList;
37+
}
38+
1739
void IndexPropertyDescriptorMap::Add(uint32 key, const IndexPropertyDescriptor& value)
1840
{
1941
if (indexPropertyMap->Count() >= (INT_MAX / 2))
@@ -215,6 +237,21 @@ namespace Js
215237
indexPropertyMap = RecyclerNew(recycler, IndexPropertyDescriptorMap, recycler);
216238
}
217239

240+
template <class T>
241+
ES5ArrayTypeHandlerBase<T>::ES5ArrayTypeHandlerBase(Recycler* recycler, ES5ArrayTypeHandlerBase<T>* typeHandler)
242+
: DictionaryTypeHandlerBase<T>(recycler, typeHandler)
243+
{
244+
dataItemAttributes = typeHandler->dataItemAttributes;
245+
lengthWritable = typeHandler->lengthWritable;
246+
indexPropertyMap = typeHandler->indexPropertyMap->Clone(recycler);
247+
}
248+
249+
template <class T>
250+
DynamicTypeHandler * ES5ArrayTypeHandlerBase<T>::Clone(Recycler * recycler)
251+
{
252+
return RecyclerNew(recycler, ES5ArrayTypeHandlerBase, recycler, this);
253+
}
254+
218255
template <class T>
219256
void ES5ArrayTypeHandlerBase<T>::SetIsPrototype(DynamicObject * instance)
220257
{

lib/Runtime/Types/ES5ArrayTypeHandler.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,11 @@ namespace Js
4343

4444
private:
4545
void EnsureIndexList();
46+
uint32 * CopyIndexList() const;
4647

4748
public:
4849
IndexPropertyDescriptorMap(Recycler* recycler);
50+
IndexPropertyDescriptorMap(Recycler* recycler, const IndexPropertyDescriptorMap * const indexPropertyDescriptorMap);
4951

5052
void Add(uint32 key, const IndexPropertyDescriptor& descriptor);
5153
bool TryGetLastIndex(uint32* lastIndex);
@@ -73,6 +75,7 @@ namespace Js
7375
{
7476
return indexPropertyMap->TryGetReference(key, value);
7577
}
78+
IndexPropertyDescriptorMap * Clone(Recycler * recycler);
7679

7780
private:
7881
static int __cdecl CompareIndex(const void* left, const void* right)
@@ -110,6 +113,7 @@ namespace Js
110113
ES5ArrayTypeHandlerBase(Recycler* recycler);
111114
ES5ArrayTypeHandlerBase(Recycler* recycler, int slotCapacity, uint16 inlineSlotCapacity, uint16 offsetOfInlineSlots);
112115
ES5ArrayTypeHandlerBase(Recycler* recycler, DictionaryTypeHandlerBase<T>* typeHandler);
116+
ES5ArrayTypeHandlerBase(Recycler* recycler, ES5ArrayTypeHandlerBase * typeHandler);
113117
DEFINE_VTABLE_CTOR_NO_REGISTER(ES5ArrayTypeHandlerBase, DictionaryTypeHandlerBase<T>);
114118

115119
// This constructor is used to grow small ES5ArrayTypeHandler into BigES5ArrayTypeHandler. We simply take over all own fields here
@@ -158,6 +162,7 @@ namespace Js
158162
BOOL GetItemAccessors(ES5Array* arr, DynamicObject* instance, uint32 index, Var* getter, Var* setter);
159163

160164
public:
165+
virtual DynamicTypeHandler * Clone(Recycler * recyler);
161166
virtual BOOL HasProperty(DynamicObject* instance, PropertyId propertyId, bool *noRedecl = nullptr, _Inout_opt_ PropertyValueInfo* info = nullptr) override;
162167
virtual BOOL HasProperty(DynamicObject* instance, JavascriptString* propertyNameString) override;
163168
virtual BOOL GetProperty(DynamicObject* instance, Var originalInstance, PropertyId propertyId, Var* value, PropertyValueInfo* info, ScriptContext* requestContext) override;

lib/Runtime/Types/MissingPropertyTypeHandler.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,11 @@ namespace Js
1515
MissingPropertyTypeHandler::MissingPropertyTypeHandler() :
1616
DynamicTypeHandler(1, 1, (uint16)sizeof(DynamicObject)) {}
1717

18+
DynamicTypeHandler * MissingPropertyTypeHandler::Clone(Recycler * recycler)
19+
{
20+
return RecyclerNew(recycler, MissingPropertyTypeHandler);
21+
}
22+
1823
PropertyId MissingPropertyTypeHandler::GetPropertyId(ScriptContext* scriptContext, PropertyIndex index)
1924
{
2025
return Constants::NoProperty;

lib/Runtime/Types/MissingPropertyTypeHandler.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ namespace Js
1818
protected:
1919
DEFINE_VTABLE_CTOR_NO_REGISTER(MissingPropertyTypeHandler, DynamicTypeHandler);
2020

21+
virtual DynamicTypeHandler * Clone(Recycler * recycler);
2122
virtual BOOL IsLockable() const override { return true; }
2223
virtual BOOL IsSharable() const override { return true; }
2324
virtual int GetPropertyCount() override { return 0; }

lib/Runtime/Types/NullTypeHandler.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,12 @@ namespace Js
343343
template<bool IsPrototypeTemplate>
344344
NullTypeHandler<IsPrototypeTemplate> * NullTypeHandler<IsPrototypeTemplate>::GetDefaultInstance() { return &defaultInstance; }
345345

346+
template<bool IsPrototypeTemplate>
347+
DynamicTypeHandler * NullTypeHandler<IsPrototypeTemplate>::Clone(Recycler * recycler)
348+
{
349+
return RecyclerNew(recycler, NullTypeHandler, this);
350+
}
351+
346352
#if DBG_DUMP
347353
template<bool IsPrototypeTemplate>
348354
void NullTypeHandler<IsPrototypeTemplate>::Dump(unsigned indent) const

lib/Runtime/Types/NullTypeHandler.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,12 @@ namespace Js
1313
DynamicTypeHandler(0, 0, 0, DefaultFlags | IsLockedFlag | MayBecomeSharedFlag | IsSharedFlag | (isPrototype ? IsPrototypeFlag : 0)),
1414
isPrototype(isPrototype) {}
1515

16+
NullTypeHandlerBase(NullTypeHandlerBase* typeHandler, bool isPrototype) :
17+
DynamicTypeHandler(typeHandler), isPrototype(typeHandler->isPrototype)
18+
{}
19+
1620
DEFINE_VTABLE_CTOR_NO_REGISTER(NullTypeHandlerBase, DynamicTypeHandler);
1721

18-
private:
1922
bool isPrototype;
2023

2124
public:
@@ -89,12 +92,15 @@ namespace Js
8992

9093
private:
9194
NullTypeHandler() : NullTypeHandlerBase(IsPrototypeTemplate) {}
95+
NullTypeHandler(NullTypeHandler * typeHandler) : NullTypeHandlerBase(typeHandler) {}
96+
9297
DEFINE_VTABLE_CTOR_NO_REGISTER(NullTypeHandler, NullTypeHandlerBase);
9398

9499
static NullTypeHandler defaultInstance;
95100

96101
public:
97102
static NullTypeHandler * GetDefaultInstance();
103+
virtual DynamicTypeHandler * Clone(Recycler * recycler);
98104

99105
#if ENABLE_TTD
100106
public:

lib/Runtime/Types/PathTypeHandler.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,12 @@ namespace Js
113113
DEFINE_VTABLE_CTOR_INIT_NO_REGISTER(PathTypeHandlerBase, DynamicTypeHandler, predecessorType(nullptr), typePath(nullptr), successorInfo(nullptr));
114114

115115
public:
116+
virtual DynamicTypeHandler * Clone(Recycler * recycler)
117+
{
118+
AssertMsg(false, "DynamicTypeHandler::Clone is only called (today) when type handler is not shareable, or may not become shared. Path type handlers don't satisfy either condition");
119+
return nullptr;
120+
}
121+
116122
virtual BOOL IsLockable() const override { return true; }
117123
virtual BOOL IsSharable() const override { return true; }
118124

lib/Runtime/Types/SimpleDictionaryTypeHandler.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,27 @@ namespace Js
319319
propertyMap = RecyclerNew(recycler, SimplePropertyDescriptorMap, recycler, propertyCapacity);
320320
}
321321

322+
template <typename TPropertyIndex, typename TMapKey, bool IsNotExtensibleSupported>
323+
SimpleDictionaryTypeHandlerBase<TPropertyIndex, TMapKey, IsNotExtensibleSupported>::SimpleDictionaryTypeHandlerBase(Recycler* recycler, SimpleDictionaryTypeHandlerBase * typeHandler) :
324+
DynamicTypeHandler(typeHandler),
325+
nextPropertyIndex(typeHandler->nextPropertyIndex),
326+
singletonInstance(nullptr),
327+
_gc_tag(typeHandler->_gc_tag),
328+
isUnordered(typeHandler->isUnordered),
329+
hasNamelessPropertyId(typeHandler->hasNamelessPropertyId),
330+
numDeletedProperties(typeHandler->numDeletedProperties)
331+
{
332+
Assert(this->GetIsInlineSlotCapacityLocked() == typeHandler->GetIsInlineSlotCapacityLocked());
333+
Assert(this->GetSlotCapacity() <= MaxPropertyIndexSize);
334+
propertyMap = typeHandler->propertyMap->Clone();
335+
}
336+
337+
template <typename TPropertyIndex, typename TMapKey, bool IsNotExtensibleSupported>
338+
DynamicTypeHandler * SimpleDictionaryTypeHandlerBase<TPropertyIndex, TMapKey, IsNotExtensibleSupported>::Clone(Recycler * recycler)
339+
{
340+
return RecyclerNew(recycler, SimpleDictionaryTypeHandlerBase, recycler, this);
341+
}
342+
322343
template <typename TPropertyIndex, typename TMapKey, bool IsNotExtensibleSupported>
323344
template <bool check__proto__>
324345
DynamicType* SimpleDictionaryTypeHandlerBase<TPropertyIndex, TMapKey, IsNotExtensibleSupported>::InternalCreateTypeForNewScObject(ScriptContext* scriptContext, DynamicType* type, const Js::PropertyIdArray *propIds, bool shareType)

lib/Runtime/Types/SimpleDictionaryTypeHandler.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ namespace Js
8787
SimpleDictionaryTypeHandlerBase(Recycler * recycler, int slotCapacity, uint16 inlineSlotCapacity, uint16 offsetOfInlineSlots, bool isLocked = false, bool isShared = false);
8888
SimpleDictionaryTypeHandlerBase(ScriptContext * scriptContext, SimplePropertyDescriptor const* propertyDescriptors, int propertyCount, int slotCapacity, uint16 inlineSlotCapacity, uint16 offsetOfInlineSlots, bool isLocked = false, bool isShared = false);
8989
SimpleDictionaryTypeHandlerBase(Recycler* recycler, int slotCapacity, int propertyCapacity, uint16 inlineSlotCapacity, uint16 offsetOfInlineSlots, bool isLocked = false, bool isShared = false);
90+
SimpleDictionaryTypeHandlerBase(Recycler* recycler, SimpleDictionaryTypeHandlerBase * typeHandler);
9091
DEFINE_VTABLE_CTOR_NO_REGISTER(SimpleDictionaryTypeHandlerBase, DynamicTypeHandler);
9192

9293
typedef PropertyIndexRanges<TPropertyIndex> PropertyIndexRangesType;
@@ -104,6 +105,7 @@ namespace Js
104105

105106
static DynamicType* CreateTypeForNewScObject(ScriptContext* scriptContext, DynamicType* type, const Js::PropertyIdArray *propIds, bool shareType, bool check__proto__);
106107

108+
virtual DynamicTypeHandler * Clone(Recycler * recyler);
107109
virtual BOOL IsStringTypeHandler() const override { return PropertyMapKeyTraits<TMapKey>::IsStringTypeHandler(); }
108110

109111
virtual BOOL IsLockable() const override { return true; }

0 commit comments

Comments
 (0)