فهرست منبع

[CVE-2018-8280] Edge - Js::DataView SetValue and GetValue to a detached buffer allows for semi arbitrary memory read write.

Atul Katti 7 سال پیش
والد
کامیت
3ad284acd3
3فایلهای تغییر یافته به همراه26 افزوده شده و 17 حذف شده
  1. 6 0
      lib/Runtime/Library/DataView.cpp
  2. 15 12
      lib/Runtime/Library/DataView.h
  3. 5 5
      lib/Runtime/Library/WebAssemblyMemory.cpp

+ 6 - 0
lib/Runtime/Library/DataView.cpp

@@ -116,6 +116,12 @@ namespace Js
             mappedLength = byteLength - offset;
         }
 
+        // Evaluation of the argument(s) above is reentrant and can detach the array.
+        if (arrayBuffer->IsDetached())
+        {
+            JavascriptError::ThrowTypeError(scriptContext, JSERR_DetachedTypedArray);
+        }
+
         //10.   Let O be OrdinaryCreateFromConstructor(NewTarget, "%DataViewPrototype%", [[DataView]], [[ViewedArrayBuffer]], [[ByteLength]], [[ByteOffset]]).
         //11.   Set O's[[DataView]] internal slot to true.
         //12.   Set O's[[ViewedArrayBuffer]] internal slot to buffer.

+ 15 - 12
lib/Runtime/Library/DataView.h

@@ -107,17 +107,18 @@ namespace Js
         Var GetValue(Var offset, const char16* funcName, BOOL isLittleEndian = FALSE)
         {
             ScriptContext* scriptContext = GetScriptContext();
-            if (this->GetArrayBuffer()->IsDetached())
-            {
-                JavascriptError::ThrowTypeError(scriptContext, JSERR_DetachedTypedArray, funcName);
-            }
 
             uint32 length = GetLength();
             if (length < sizeof(TypeName))
             {
                 JavascriptError::ThrowRangeError(scriptContext, JSERR_DataView_InvalidOffset, funcName);
             }
+
             uint32 byteOffset = ArrayBuffer::ToIndex(offset, JSERR_DataView_InvalidOffset, scriptContext, length - sizeof(TypeName), false);
+            if (this->GetArrayBuffer()->IsDetached())
+            {
+                JavascriptError::ThrowTypeError(scriptContext, JSERR_DetachedTypedArray, funcName);
+            }
 
             TypeName item;
             TypeName* typedBuffer = (TypeName*)(buffer + byteOffset);
@@ -142,17 +143,18 @@ namespace Js
         Var GetValueWithCheck(Var offset, BOOL isLittleEndian, const char16* funcName)
         {
             ScriptContext* scriptContext = GetScriptContext();
-            if (this->GetArrayBuffer()->IsDetached())
-            {
-                JavascriptError::ThrowTypeError(scriptContext, JSERR_DetachedTypedArray, funcName);
-            }
 
             uint32 length = GetLength();
             if (length < sizeof(TypeName))
             {
                 JavascriptError::ThrowRangeError(scriptContext, JSERR_DataView_InvalidOffset, funcName);
             }
+
             uint32 byteOffset = ArrayBuffer::ToIndex(offset, JSERR_DataView_InvalidOffset, scriptContext, length - sizeof(TypeName), false);
+            if (this->GetArrayBuffer()->IsDetached())
+            {
+                JavascriptError::ThrowTypeError(scriptContext, JSERR_DetachedTypedArray, funcName);
+            }
 
             TypeName item;
             TypeName *typedBuffer = (TypeName*)(buffer + byteOffset);
@@ -177,17 +179,18 @@ namespace Js
         void SetValue(Var offset, TypeName value, BOOL isLittleEndian, const char16 *funcName)
         {
             ScriptContext* scriptContext = GetScriptContext();
-            if (this->GetArrayBuffer()->IsDetached())
-            {
-                JavascriptError::ThrowTypeError(scriptContext, JSERR_DetachedTypedArray, funcName);
-            }
 
             uint32 length = GetLength();
             if (length < sizeof(TypeName))
             {
                 JavascriptError::ThrowRangeError(scriptContext, JSERR_DataView_InvalidOffset, funcName);
             }
+
             uint32 byteOffset = ArrayBuffer::ToIndex(offset, JSERR_DataView_InvalidOffset, scriptContext, length - sizeof(TypeName), false);
+            if (this->GetArrayBuffer()->IsDetached())
+            {
+                JavascriptError::ThrowTypeError(scriptContext, JSERR_DetachedTypedArray, funcName);
+            }
 
             TypeName* typedBuffer = (TypeName*)(buffer + byteOffset);
             if (!isLittleEndian)

+ 5 - 5
lib/Runtime/Library/WebAssemblyMemory.cpp

@@ -134,17 +134,17 @@ WebAssemblyMemory::EntryGrow(RecyclableObject* function, CallInfo callInfo, ...)
     WebAssemblyMemory* memory = WebAssemblyMemory::FromVar(args[0]);
     Assert(ArrayBufferBase::Is(memory->m_buffer));
 
-    if (memory->m_buffer->IsDetached())
-    {
-        JavascriptError::ThrowTypeError(scriptContext, JSERR_DetachedTypedArray);
-    }
-
     Var deltaVar = scriptContext->GetLibrary()->GetUndefined();
     if (args.Info.Count >= 2)
     {
         deltaVar = args[1];
     }
+
     uint32 deltaPages = WebAssembly::ToNonWrappingUint32(deltaVar, scriptContext);
+    if (memory->m_buffer->IsDetached())
+    {
+        JavascriptError::ThrowTypeError(scriptContext, JSERR_DetachedTypedArray);
+    }
 
     int32 oldPageCount = memory->GrowInternal(deltaPages);
     if (oldPageCount == -1)