Skip to content

Commit

Permalink
[CVE-2019-0652] Chakracore Tianfucup Arguments UaF - Tencent
Browse files Browse the repository at this point in the history
  • Loading branch information
MikeHolman committed Feb 13, 2019
1 parent 0f7e500 commit ea97a60
Show file tree
Hide file tree
Showing 19 changed files with 175 additions and 6 deletions.
16 changes: 16 additions & 0 deletions lib/Runtime/Types/DeferredTypeHandler.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@ namespace Js
// be certain that the type has only writable data properties.
}

DeferredTypeHandlerBase(DeferredTypeHandlerBase * typeHandler) : DynamicTypeHandler(typeHandler)
{
Assert(this->GetIsInlineSlotCapacityLocked() == typeHandler->GetIsInlineSlotCapacityLocked());
Assert(this->GetHasOnlyWritableDataProperties() == typeHandler->GetHasOnlyWritableDataProperties());
}
public:
void ConvertFunction(JavascriptFunction * instance, DynamicTypeHandler * handler);
void Convert(DynamicObject * instance, DeferredInitializeMode mode, int initSlotCapacity, BOOL hasAccessor = false);
Expand Down Expand Up @@ -75,10 +80,15 @@ namespace Js

private:
DeferredTypeHandler() : DeferredTypeHandlerBase(isPrototypeTemplate, _inlineSlotCapacity, _offsetOfInlineSlots), m_initializer(initializer) { }
DeferredTypeHandler(DeferredTypeHandler * typeHandler) :
DeferredTypeHandlerBase(typeHandler),
m_initializer(typeHandler->m_initializer)
{}

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

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

template <DeferredTypeInitializer initializer, typename DeferredTypeFilter, bool isPrototypeTemplate, uint16 _inlineSlotCapacity, uint16 _offsetOfInlineSlots>
DynamicTypeHandler * DeferredTypeHandler<initializer, DeferredTypeFilter, isPrototypeTemplate, _inlineSlotCapacity, _offsetOfInlineSlots>::Clone(Recycler * recycler)
{
return RecyclerNew(recycler, DeferredTypeHandler, this);
}

template <DeferredTypeInitializer initializer, typename DeferredTypeFilter, bool isPrototypeTemplate, uint16 _inlineSlotCapacity, uint16 _offsetOfInlineSlots>
int DeferredTypeHandler<initializer, DeferredTypeFilter, isPrototypeTemplate, _inlineSlotCapacity, _offsetOfInlineSlots>::GetPropertyCount()
{
Expand Down
18 changes: 18 additions & 0 deletions lib/Runtime/Types/DictionaryTypeHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,24 @@ namespace Js
CopyPropertyTypes(PropertyTypesWritableDataOnly | PropertyTypesWritableDataOnlyDetection | PropertyTypesInlineSlotCapacityLocked | PropertyTypesHasSpecialProperties, typeHandler->GetPropertyTypes());
}

template <typename T>
DictionaryTypeHandlerBase<T>::DictionaryTypeHandlerBase(Recycler* recycler, DictionaryTypeHandlerBase * typeHandler) :
DynamicTypeHandler(typeHandler),
nextPropertyIndex(typeHandler->nextPropertyIndex)
#if ENABLE_FIXED_FIELDS
, singletonInstance(nullptr)
#endif
{
Assert(this->GetIsInlineSlotCapacityLocked() == typeHandler->GetIsInlineSlotCapacityLocked());
propertyMap = typeHandler->propertyMap->Clone();
}

template <typename T>
DynamicTypeHandler * DictionaryTypeHandlerBase<T>::Clone(Recycler * recycler)
{
return RecyclerNew(recycler, DictionaryTypeHandlerBase, recycler, this);
}

template <typename T>
int DictionaryTypeHandlerBase<T>::GetPropertyCount()
{
Expand Down
3 changes: 3 additions & 0 deletions lib/Runtime/Types/DictionaryTypeHandler.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ namespace Js
DictionaryTypeHandlerBase(Recycler* recycler);
DictionaryTypeHandlerBase(Recycler* recycler, int slotCapacity, uint16 inlineSlotCapacity, uint16 offsetOfInlineSlots);
DictionaryTypeHandlerBase(DictionaryTypeHandlerBase* typeHandler);
DictionaryTypeHandlerBase(Recycler* recycler, DictionaryTypeHandlerBase * typeHandler);
DEFINE_VTABLE_CTOR_NO_REGISTER(DictionaryTypeHandlerBase, DynamicTypeHandler);

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

virtual DynamicTypeHandler * Clone(Recycler * recycler);

BOOL IsBigDictionaryTypeHandler();

virtual BOOL IsLockable() const override { return false; }
Expand Down
15 changes: 15 additions & 0 deletions lib/Runtime/Types/DynamicObject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,14 @@ namespace Js
auxSlots(instance->auxSlots),
objectArray(instance->objectArray) // copying the array should copy the array flags and array call site index as well
{
if (deepCopy)
{
if (!instance->GetDynamicType()->ShareType())
{
this->type = instance->DuplicateTypeAndTypeHandler();
}
}

DynamicTypeHandler * typeHandler = this->GetTypeHandler();

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

DynamicType* DynamicObject::DuplicateTypeAndTypeHandler()
{
DynamicType * newType = DuplicateType();
newType->typeHandler = newType->DuplicateTypeHandler();
return newType;
}

void DynamicObject::PrepareForConversionToNonPathType()
{
// Nothing to do in base class
Expand Down
1 change: 1 addition & 0 deletions lib/Runtime/Types/DynamicObject.h
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,7 @@ namespace Js
virtual BOOL IsCrossSiteObject() const { return FALSE; }

virtual DynamicType* DuplicateType();
DynamicType* DuplicateTypeAndTypeHandler();
virtual void PrepareForConversionToNonPathType();
static bool IsTypeHandlerCompatibleForObjectHeaderInlining(DynamicTypeHandler * oldTypeHandler, DynamicTypeHandler * newTypeHandler);

Expand Down
7 changes: 6 additions & 1 deletion lib/Runtime/Types/DynamicType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ namespace Js
Assert(this->GetTypeHandler()->IsSharable());
return true;
}
if (this->GetTypeHandler()->IsSharable())
if (this->GetTypeHandler()->IsSharable() && this->GetTypeHandler()->GetMayBecomeShared())
{
LockType();
this->GetTypeHandler()->ShareTypeHandler(this->GetScriptContext());
Expand All @@ -160,6 +160,11 @@ namespace Js
return false;
}

DynamicTypeHandler * DynamicType::DuplicateTypeHandler()
{
return GetTypeHandler()->Clone(this->GetRecycler());
}

bool
DynamicType::SetHasNoEnumerableProperties(bool value)
{
Expand Down
1 change: 1 addition & 0 deletions lib/Runtime/Types/DynamicType.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ namespace Js

public:
DynamicTypeHandler * GetTypeHandler() const { return typeHandler; }
DynamicTypeHandler * DuplicateTypeHandler();

void SetPrototype(RecyclableObject* newPrototype) { this->prototype = newPrototype; }
bool GetIsLocked() const { return this->isLocked; }
Expand Down
37 changes: 37 additions & 0 deletions lib/Runtime/Types/ES5ArrayTypeHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,28 @@ namespace Js
indexPropertyMap = RecyclerNew(recycler, InnerMap, recycler);
}

IndexPropertyDescriptorMap::IndexPropertyDescriptorMap(Recycler* recycler, const IndexPropertyDescriptorMap * const indexPropertyDescriptorMap)
: recycler(recycler), lastIndexAt(indexPropertyDescriptorMap->lastIndexAt)
{
indexList = indexPropertyDescriptorMap->CopyIndexList();
indexPropertyMap = indexPropertyDescriptorMap->indexPropertyMap->Clone();
}

IndexPropertyDescriptorMap * IndexPropertyDescriptorMap::Clone(Recycler * recycler)
{
return RecyclerNew(recycler, IndexPropertyDescriptorMap, recycler, this);
}

uint32 * IndexPropertyDescriptorMap::CopyIndexList() const
{
uint32 * newList = RecyclerNewArrayLeaf(recycler, uint32, Count());
for (int i = 0; i < Count(); i++)
{
newList[i] = this->indexList[i];
}
return newList;
}

void IndexPropertyDescriptorMap::Add(uint32 key, const IndexPropertyDescriptor& value)
{
if (indexPropertyMap->Count() >= (INT_MAX / 2))
Expand Down Expand Up @@ -215,6 +237,21 @@ namespace Js
indexPropertyMap = RecyclerNew(recycler, IndexPropertyDescriptorMap, recycler);
}

template <class T>
ES5ArrayTypeHandlerBase<T>::ES5ArrayTypeHandlerBase(Recycler* recycler, ES5ArrayTypeHandlerBase<T>* typeHandler)
: DictionaryTypeHandlerBase<T>(recycler, typeHandler)
{
dataItemAttributes = typeHandler->dataItemAttributes;
lengthWritable = typeHandler->lengthWritable;
indexPropertyMap = typeHandler->indexPropertyMap->Clone(recycler);
}

template <class T>
DynamicTypeHandler * ES5ArrayTypeHandlerBase<T>::Clone(Recycler * recycler)
{
return RecyclerNew(recycler, ES5ArrayTypeHandlerBase, recycler, this);
}

template <class T>
void ES5ArrayTypeHandlerBase<T>::SetIsPrototype(DynamicObject * instance)
{
Expand Down
5 changes: 5 additions & 0 deletions lib/Runtime/Types/ES5ArrayTypeHandler.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,11 @@ namespace Js

private:
void EnsureIndexList();
uint32 * CopyIndexList() const;

public:
IndexPropertyDescriptorMap(Recycler* recycler);
IndexPropertyDescriptorMap(Recycler* recycler, const IndexPropertyDescriptorMap * const indexPropertyDescriptorMap);

void Add(uint32 key, const IndexPropertyDescriptor& descriptor);
bool TryGetLastIndex(uint32* lastIndex);
Expand Down Expand Up @@ -73,6 +75,7 @@ namespace Js
{
return indexPropertyMap->TryGetReference(key, value);
}
IndexPropertyDescriptorMap * Clone(Recycler * recycler);

private:
static int __cdecl CompareIndex(const void* left, const void* right)
Expand Down Expand Up @@ -110,6 +113,7 @@ namespace Js
ES5ArrayTypeHandlerBase(Recycler* recycler);
ES5ArrayTypeHandlerBase(Recycler* recycler, int slotCapacity, uint16 inlineSlotCapacity, uint16 offsetOfInlineSlots);
ES5ArrayTypeHandlerBase(Recycler* recycler, DictionaryTypeHandlerBase<T>* typeHandler);
ES5ArrayTypeHandlerBase(Recycler* recycler, ES5ArrayTypeHandlerBase * typeHandler);
DEFINE_VTABLE_CTOR_NO_REGISTER(ES5ArrayTypeHandlerBase, DictionaryTypeHandlerBase<T>);

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

public:
virtual DynamicTypeHandler * Clone(Recycler * recyler);
virtual BOOL HasProperty(DynamicObject* instance, PropertyId propertyId, bool *noRedecl = nullptr, _Inout_opt_ PropertyValueInfo* info = nullptr) override;
virtual BOOL HasProperty(DynamicObject* instance, JavascriptString* propertyNameString) override;
virtual BOOL GetProperty(DynamicObject* instance, Var originalInstance, PropertyId propertyId, Var* value, PropertyValueInfo* info, ScriptContext* requestContext) override;
Expand Down
5 changes: 5 additions & 0 deletions lib/Runtime/Types/MissingPropertyTypeHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@ namespace Js
MissingPropertyTypeHandler::MissingPropertyTypeHandler() :
DynamicTypeHandler(1, 1, (uint16)sizeof(DynamicObject)) {}

DynamicTypeHandler * MissingPropertyTypeHandler::Clone(Recycler * recycler)
{
return RecyclerNew(recycler, MissingPropertyTypeHandler);
}

PropertyId MissingPropertyTypeHandler::GetPropertyId(ScriptContext* scriptContext, PropertyIndex index)
{
return Constants::NoProperty;
Expand Down
1 change: 1 addition & 0 deletions lib/Runtime/Types/MissingPropertyTypeHandler.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ namespace Js
protected:
DEFINE_VTABLE_CTOR_NO_REGISTER(MissingPropertyTypeHandler, DynamicTypeHandler);

virtual DynamicTypeHandler * Clone(Recycler * recycler);
virtual BOOL IsLockable() const override { return true; }
virtual BOOL IsSharable() const override { return true; }
virtual int GetPropertyCount() override { return 0; }
Expand Down
6 changes: 6 additions & 0 deletions lib/Runtime/Types/NullTypeHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,12 @@ namespace Js
template<bool IsPrototypeTemplate>
NullTypeHandler<IsPrototypeTemplate> * NullTypeHandler<IsPrototypeTemplate>::GetDefaultInstance() { return &defaultInstance; }

template<bool IsPrototypeTemplate>
DynamicTypeHandler * NullTypeHandler<IsPrototypeTemplate>::Clone(Recycler * recycler)
{
return RecyclerNew(recycler, NullTypeHandler, this);
}

#if DBG_DUMP
template<bool IsPrototypeTemplate>
void NullTypeHandler<IsPrototypeTemplate>::Dump(unsigned indent) const
Expand Down
8 changes: 7 additions & 1 deletion lib/Runtime/Types/NullTypeHandler.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,12 @@ namespace Js
DynamicTypeHandler(0, 0, 0, DefaultFlags | IsLockedFlag | MayBecomeSharedFlag | IsSharedFlag | (isPrototype ? IsPrototypeFlag : 0)),
isPrototype(isPrototype) {}

NullTypeHandlerBase(NullTypeHandlerBase* typeHandler, bool isPrototype) :
DynamicTypeHandler(typeHandler), isPrototype(typeHandler->isPrototype)
{}

DEFINE_VTABLE_CTOR_NO_REGISTER(NullTypeHandlerBase, DynamicTypeHandler);

private:
bool isPrototype;

public:
Expand Down Expand Up @@ -89,12 +92,15 @@ namespace Js

private:
NullTypeHandler() : NullTypeHandlerBase(IsPrototypeTemplate) {}
NullTypeHandler(NullTypeHandler * typeHandler) : NullTypeHandlerBase(typeHandler) {}

DEFINE_VTABLE_CTOR_NO_REGISTER(NullTypeHandler, NullTypeHandlerBase);

static NullTypeHandler defaultInstance;

public:
static NullTypeHandler * GetDefaultInstance();
virtual DynamicTypeHandler * Clone(Recycler * recycler);

#if ENABLE_TTD
public:
Expand Down
6 changes: 6 additions & 0 deletions lib/Runtime/Types/PathTypeHandler.h
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,12 @@ namespace Js
DEFINE_VTABLE_CTOR_INIT_NO_REGISTER(PathTypeHandlerBase, DynamicTypeHandler, predecessorType(nullptr), typePath(nullptr), successorInfo(nullptr));

public:
virtual DynamicTypeHandler * Clone(Recycler * recycler)
{
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");
return nullptr;
}

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

Expand Down
21 changes: 21 additions & 0 deletions lib/Runtime/Types/SimpleDictionaryTypeHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,27 @@ namespace Js
propertyMap = RecyclerNew(recycler, SimplePropertyDescriptorMap, recycler, propertyCapacity);
}

template <typename TPropertyIndex, typename TMapKey, bool IsNotExtensibleSupported>
SimpleDictionaryTypeHandlerBase<TPropertyIndex, TMapKey, IsNotExtensibleSupported>::SimpleDictionaryTypeHandlerBase(Recycler* recycler, SimpleDictionaryTypeHandlerBase * typeHandler) :
DynamicTypeHandler(typeHandler),
nextPropertyIndex(typeHandler->nextPropertyIndex),
singletonInstance(nullptr),
_gc_tag(typeHandler->_gc_tag),
isUnordered(typeHandler->isUnordered),
hasNamelessPropertyId(typeHandler->hasNamelessPropertyId),
numDeletedProperties(typeHandler->numDeletedProperties)
{
Assert(this->GetIsInlineSlotCapacityLocked() == typeHandler->GetIsInlineSlotCapacityLocked());
Assert(this->GetSlotCapacity() <= MaxPropertyIndexSize);
propertyMap = typeHandler->propertyMap->Clone();
}

template <typename TPropertyIndex, typename TMapKey, bool IsNotExtensibleSupported>
DynamicTypeHandler * SimpleDictionaryTypeHandlerBase<TPropertyIndex, TMapKey, IsNotExtensibleSupported>::Clone(Recycler * recycler)
{
return RecyclerNew(recycler, SimpleDictionaryTypeHandlerBase, recycler, this);
}

template <typename TPropertyIndex, typename TMapKey, bool IsNotExtensibleSupported>
template <bool check__proto__>
DynamicType* SimpleDictionaryTypeHandlerBase<TPropertyIndex, TMapKey, IsNotExtensibleSupported>::InternalCreateTypeForNewScObject(ScriptContext* scriptContext, DynamicType* type, const Js::PropertyIdArray *propIds, bool shareType)
Expand Down
2 changes: 2 additions & 0 deletions lib/Runtime/Types/SimpleDictionaryTypeHandler.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ namespace Js
SimpleDictionaryTypeHandlerBase(Recycler * recycler, int slotCapacity, uint16 inlineSlotCapacity, uint16 offsetOfInlineSlots, bool isLocked = false, bool isShared = false);
SimpleDictionaryTypeHandlerBase(ScriptContext * scriptContext, SimplePropertyDescriptor const* propertyDescriptors, int propertyCount, int slotCapacity, uint16 inlineSlotCapacity, uint16 offsetOfInlineSlots, bool isLocked = false, bool isShared = false);
SimpleDictionaryTypeHandlerBase(Recycler* recycler, int slotCapacity, int propertyCapacity, uint16 inlineSlotCapacity, uint16 offsetOfInlineSlots, bool isLocked = false, bool isShared = false);
SimpleDictionaryTypeHandlerBase(Recycler* recycler, SimpleDictionaryTypeHandlerBase * typeHandler);
DEFINE_VTABLE_CTOR_NO_REGISTER(SimpleDictionaryTypeHandlerBase, DynamicTypeHandler);

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

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

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

virtual BOOL IsLockable() const override { return true; }
Expand Down
Loading

0 comments on commit ea97a60

Please sign in to comment.