Skip to content

Commit e40a34f

Browse files
author
Jianchun Xu
committed
[CVE-2017-8607] DictionaryTypeHandler property descriptor may contain invalid index
Pre-reserve potentially needed slots upfront.
1 parent 7c3214e commit e40a34f

File tree

2 files changed

+30
-31
lines changed

2 files changed

+30
-31
lines changed

lib/Runtime/Types/DictionaryTypeHandler.cpp

Lines changed: 29 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1537,6 +1537,18 @@ namespace Js
15371537
Assert(this->VerifyIsExtensible(scriptContext, false) || this->HasProperty(instance, propertyId)
15381538
|| JavascriptFunction::IsBuiltinProperty(instance, propertyId));
15391539

1540+
// We could potentially need 2 new slots to hold getter/setter, try pre-reserve
1541+
if (this->GetSlotCapacity() - 2 < nextPropertyIndex)
1542+
{
1543+
if (this->GetSlotCapacity() > MaxPropertyIndexSize - 2)
1544+
{
1545+
return ConvertToBigDictionaryTypeHandler(instance)
1546+
->SetAccessors(instance, propertyId, getter, setter, flags);
1547+
}
1548+
1549+
this->EnsureSlotCapacity(instance, 2);
1550+
}
1551+
15401552
DictionaryPropertyDescriptor<T>* descriptor;
15411553
if (this->GetFlags() & IsPrototypeFlag)
15421554
{
@@ -1582,15 +1594,7 @@ namespace Js
15821594
// conversion from data-property to accessor property
15831595
if (descriptor->ConvertToGetterSetter(nextPropertyIndex))
15841596
{
1585-
if (this->GetSlotCapacity() <= nextPropertyIndex)
1586-
{
1587-
if (this->GetSlotCapacity() >= MaxPropertyIndexSize)
1588-
{
1589-
Throw::OutOfMemory();
1590-
}
1591-
1592-
this->EnsureSlotCapacity(instance);
1593-
}
1597+
AssertOrFailFast(this->GetSlotCapacity() >= nextPropertyIndex); // pre-reserved 2 at entry
15941598
}
15951599

15961600
// DictionaryTypeHandlers are not supposed to be shared.
@@ -1673,15 +1677,7 @@ namespace Js
16731677
T getterIndex = ::Math::PostInc(nextPropertyIndex);
16741678
T setterIndex = ::Math::PostInc(nextPropertyIndex);
16751679
DictionaryPropertyDescriptor<T> newDescriptor(getterIndex, setterIndex);
1676-
if (this->GetSlotCapacity() <= nextPropertyIndex)
1677-
{
1678-
if (this->GetSlotCapacity() >= MaxPropertyIndexSize)
1679-
{
1680-
Throw::OutOfMemory();
1681-
}
1682-
1683-
this->EnsureSlotCapacity(instance);
1684-
}
1680+
AssertOrFailFast(this->GetSlotCapacity() >= nextPropertyIndex); // pre-reserved 2 at entry
16851681

16861682
// DictionaryTypeHandlers are not supposed to be shared.
16871683
Assert(!GetIsOrMayBecomeShared());
@@ -1782,6 +1778,18 @@ namespace Js
17821778
}
17831779
else if ((descriptor->Attributes & PropertyLetConstGlobal) != (attributes & PropertyLetConstGlobal))
17841780
{
1781+
// We could potentially need 1 new slot by AddShadowedData(), try pre-reserve
1782+
if (this->GetSlotCapacity() <= nextPropertyIndex)
1783+
{
1784+
if (this->GetSlotCapacity() >= MaxPropertyIndexSize)
1785+
{
1786+
return ConvertToBigDictionaryTypeHandler(instance)->SetPropertyWithAttributes(
1787+
instance, propertyId, value, attributes, info, flags, possibleSideEffects);
1788+
}
1789+
1790+
this->EnsureSlotCapacity(instance);
1791+
}
1792+
17851793
bool addingLetConstGlobal = (attributes & PropertyLetConstGlobal) != 0;
17861794

17871795
if (addingLetConstGlobal)
@@ -1795,15 +1803,7 @@ namespace Js
17951803

17961804
descriptor->AddShadowedData(nextPropertyIndex, addingLetConstGlobal);
17971805

1798-
if (this->GetSlotCapacity() <= nextPropertyIndex)
1799-
{
1800-
if (this->GetSlotCapacity() >= MaxPropertyIndexSize)
1801-
{
1802-
Throw::OutOfMemory();
1803-
}
1804-
1805-
this->EnsureSlotCapacity(instance);
1806-
}
1806+
AssertOrFailFast(this->GetSlotCapacity() >= nextPropertyIndex); // pre-reserved above
18071807

18081808
if (addingLetConstGlobal)
18091809
{
@@ -1891,15 +1891,14 @@ namespace Js
18911891
}
18921892

18931893
template <typename T>
1894-
void DictionaryTypeHandlerBase<T>::EnsureSlotCapacity(DynamicObject * instance)
1894+
void DictionaryTypeHandlerBase<T>::EnsureSlotCapacity(DynamicObject * instance, T increment /*= 1*/)
18951895
{
18961896
Assert(this->GetSlotCapacity() < MaxPropertyIndexSize); // Otherwise we can't grow this handler's capacity. We should've evolved to Bigger handler or OOM.
18971897

18981898
// A Dictionary type is expected to have more properties
18991899
// grow exponentially rather linearly to avoid the realloc and moves,
19001900
// however use a small exponent to avoid waste
1901-
int newSlotCapacity;
1902-
newSlotCapacity = ::Math::Add(nextPropertyIndex, (T)1);
1901+
int newSlotCapacity = ::Math::Add(nextPropertyIndex, increment);
19031902
newSlotCapacity = ::Math::Add(newSlotCapacity, newSlotCapacity >> 2);
19041903
if (newSlotCapacity > MaxPropertyIndexSize)
19051904
{

lib/Runtime/Types/DictionaryTypeHandler.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ namespace Js
208208
void Add(const PropertyRecord* propertyId, PropertyAttributes attributes, ScriptContext *const scriptContext);
209209
void Add(const PropertyRecord* propertyId, PropertyAttributes attributes, bool isInitialized, bool isFixed, bool usedAsFixed, ScriptContext *const scriptContext);
210210

211-
void EnsureSlotCapacity(DynamicObject * instance);
211+
void EnsureSlotCapacity(DynamicObject * instance, T increment = 1);
212212

213213
BOOL AddProperty(DynamicObject* instance, const PropertyRecord* propertyRecord, Var value, PropertyAttributes attributes, PropertyValueInfo* info, PropertyOperationFlags flags, bool throwIfNotExtensible, SideEffects possibleSideEffects);
214214
ES5ArrayTypeHandlerBase<T>* ConvertToES5ArrayType(DynamicObject *instance);

0 commit comments

Comments
 (0)