Skip to content

Commit 396d78f

Browse files
Jianchun Xurajatd
authored andcommitted
[CVE-2018-0995] Edge - JavascriptNativeIntArray::ConvertToVarArray could lead to UAF - Individual
1 parent 14a2773 commit 396d78f

File tree

1 file changed

+39
-31
lines changed

1 file changed

+39
-31
lines changed

lib/Runtime/Library/JavascriptArray.cpp

Lines changed: 39 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1921,8 +1921,21 @@ namespace Js
19211921
// And/or the old segment is not scanned by the recycler, so we need a new one to hold vars.
19221922
SparseArraySegment<Var> *newSeg =
19231923
SparseArraySegment<Var>::AllocateSegment(recycler, left, length, nextSeg);
1924-
19251924
AnalysisAssert(newSeg);
1925+
1926+
// Fill the new segment with the overflow.
1927+
for (i = 0; (uint)i < newSeg->length; i++)
1928+
{
1929+
ival = ((SparseArraySegment<int32>*)seg)->elements[i];
1930+
if (ival == JavascriptNativeIntArray::MissingItem)
1931+
{
1932+
continue;
1933+
}
1934+
newSeg->elements[i] = JavascriptNumber::ToVar(ival, scriptContext);
1935+
}
1936+
1937+
// seg elements are copied over, now it is safe to replace seg with newSeg.
1938+
// seg could be GC collected if replaced by newSeg.
19261939
Assert((prevSeg == nullptr) == (seg == intArray->head));
19271940
newSeg->next = nextSeg;
19281941
intArray->LinkSegments((SparseArraySegment<Var>*)prevSeg, newSeg);
@@ -1937,17 +1950,6 @@ namespace Js
19371950
{
19381951
segmentMap->SwapSegment(left, seg, newSeg);
19391952
}
1940-
1941-
// Fill the new segment with the overflow.
1942-
for (i = 0; (uint)i < newSeg->length; i++)
1943-
{
1944-
ival = ((SparseArraySegment<int32>*)seg)->elements[i];
1945-
if (ival == JavascriptNativeIntArray::MissingItem)
1946-
{
1947-
continue;
1948-
}
1949-
newSeg->elements[i] = JavascriptNumber::ToVar(ival, scriptContext);
1950-
}
19511953
}
19521954
else
19531955
{
@@ -2097,26 +2099,12 @@ namespace Js
20972099
}
20982100
uint32 left = seg->left;
20992101
uint32 length = seg->length;
2100-
SparseArraySegment<Var> *newSeg;
2102+
SparseArraySegment<Var> *newSeg = nullptr;
21012103
if (seg->next == nullptr && SparseArraySegmentBase::IsLeafSegment(seg, recycler))
21022104
{
21032105
// The old segment is not scanned by the recycler, so we need a new one to hold vars.
21042106
newSeg =
21052107
SparseArraySegment<Var>::AllocateSegment(recycler, left, length, nextSeg);
2106-
Assert((prevSeg == nullptr) == (seg == fArray->head));
2107-
newSeg->next = nextSeg;
2108-
fArray->LinkSegments((SparseArraySegment<Var>*)prevSeg, newSeg);
2109-
if (fArray->GetLastUsedSegment() == seg)
2110-
{
2111-
fArray->SetLastUsedSegment(newSeg);
2112-
}
2113-
prevSeg = newSeg;
2114-
2115-
SegmentBTree * segmentMap = fArray->GetSegmentMap();
2116-
if (segmentMap)
2117-
{
2118-
segmentMap->SwapSegment(left, seg, newSeg);
2119-
}
21202108
}
21212109
else
21222110
{
@@ -2172,6 +2160,26 @@ namespace Js
21722160
// Fill the remaining slots.
21732161
newSeg->FillSegmentBuffer(i, seg->size);
21742162
}
2163+
2164+
// seg elements are copied over, now it is safe to replace seg with newSeg.
2165+
// seg could be GC collected if replaced by newSeg.
2166+
if (newSeg != seg)
2167+
{
2168+
Assert((prevSeg == nullptr) == (seg == fArray->head));
2169+
newSeg->next = nextSeg;
2170+
fArray->LinkSegments((SparseArraySegment<Var>*)prevSeg, newSeg);
2171+
if (fArray->GetLastUsedSegment() == seg)
2172+
{
2173+
fArray->SetLastUsedSegment(newSeg);
2174+
}
2175+
prevSeg = newSeg;
2176+
2177+
SegmentBTree * segmentMap = fArray->GetSegmentMap();
2178+
if (segmentMap)
2179+
{
2180+
segmentMap->SwapSegment(left, seg, newSeg);
2181+
}
2182+
}
21752183
}
21762184

21772185
if (fArray->GetType() == scriptContext->GetLibrary()->GetNativeFloatArrayType())
@@ -3140,7 +3148,7 @@ namespace Js
31403148
JS_REENTRANT_NO_MUTATE(jsReentLock, CopyNativeIntArrayElementsToVar(pDestArray, BigIndex(idxDest).GetSmallIndex(), pIntItemArray));
31413149
idxDest = idxDest + pIntItemArray->length;
31423150
}
3143-
else
3151+
else
31443152
{
31453153
JavascriptNativeFloatArray *pFloatItemArray = JavascriptOperators::TryFromVar<JavascriptNativeFloatArray>(aItem);
31463154
if (pFloatItemArray)
@@ -3390,7 +3398,7 @@ namespace Js
33903398

33913399
idxDest = idxDest + pIntItemArray->length;
33923400
}
3393-
else
3401+
else
33943402
{
33953403
JavascriptNativeFloatArray * pFloatItemArray = JavascriptOperators::TryFromVar<JavascriptNativeFloatArray>(aItem);
33963404
if (pFloatItemArray && !isFillFromPrototypes)
@@ -5384,7 +5392,7 @@ namespace Js
53845392
{
53855393
RecyclableObject* protoObj = prototype;
53865394

5387-
if (!(DynamicObject::IsAnyArray(protoObj) || JavascriptOperators::IsObject(protoObj))
5395+
if (!(DynamicObject::IsAnyArray(protoObj) || JavascriptOperators::IsObject(protoObj))
53885396
|| JavascriptProxy::Is(protoObj)
53895397
|| protoObj->IsExternal())
53905398
{
@@ -6099,7 +6107,7 @@ namespace Js
60996107
*isIntArray = true;
61006108
#endif
61016109
}
6102-
else
6110+
else
61036111
{
61046112
JavascriptNativeFloatArray* nativeFloatArray = JavascriptOperators::TryFromVar<JavascriptNativeFloatArray>(this);
61056113
if (nativeFloatArray)

0 commit comments

Comments
 (0)