From 66b9abb148705d2a36062931cd5a8466a588e6e4 Mon Sep 17 00:00:00 2001 From: "Thomas Moore (CHAKRA)" Date: Fri, 1 Dec 2017 19:00:02 -0800 Subject: [PATCH] [CVE-2017-11889] UaF On the latest Patch - Qihoo 360 This change addresses a UAF that occurs when jitted code tries to index into a detached ArrayBuffer. The POC involves the convergence of JITing - a virtual type buffer (a certain performant type buffer that meets certain criteria) - A proxy object whose setter can cause the type buffer to be detached With this, it's possible to JIT code that indexes into the buffer without any checks. Thus, it's possible to index into the freed memory that backed the ArrayBuffer. The fix is to make sure that any call before a virtual ArrayBuffer access has a bailout to detect and protect against this assertion. --- lib/Backend/GlobOpt.cpp | 6 ++++-- lib/Backend/ValueInfo.h | 1 + lib/Runtime/Language/ValueType.cpp | 5 +++++ lib/Runtime/Language/ValueType.h | 1 + 4 files changed, 11 insertions(+), 2 deletions(-) diff --git a/lib/Backend/GlobOpt.cpp b/lib/Backend/GlobOpt.cpp index 7c8d93e9643..f634c6b53b5 100644 --- a/lib/Backend/GlobOpt.cpp +++ b/lib/Backend/GlobOpt.cpp @@ -12946,7 +12946,9 @@ GlobOpt::ProcessValueKills(IR::Instr *const instr) Assert(kills.KillsTypedArrayHeadSegmentLengths()); // - Calls need to kill the value types of values in the following list. For instance, calls can transform a JS array - // into an ES5 array, so any definitely-array value types need to be killed. Update the value types. + // into an ES5 array, so any definitely-array value types need to be killed. Also, VirtualTypeArrays do not have + // bounds checks; this can be problematic if the array is detached, so check to ensure that it is a virtual array. + // Update the value types to likley to ensure a bailout that asserts Array type is generated. // - Calls also need to kill typed array head segment lengths. A typed array's array buffer may be transferred to a web // worker, in which case the typed array's length is set to zero. for(auto it = valuesToKillOnCalls->GetIterator(); it.IsValid(); it.MoveNext()) @@ -12956,7 +12958,7 @@ GlobOpt::ProcessValueKills(IR::Instr *const instr) Assert( valueInfo->IsArrayOrObjectWithArray() || valueInfo->IsOptimizedTypedArray() && valueInfo->AsArrayValueInfo()->HeadSegmentLengthSym()); - if(valueInfo->IsArrayOrObjectWithArray()) + if (valueInfo->IsArrayOrObjectWithArray() || valueInfo->IsOptimizedVirtualTypedArray()) { ChangeValueType(nullptr, value, valueInfo->Type().ToLikely(), false); continue; diff --git a/lib/Backend/ValueInfo.h b/lib/Backend/ValueInfo.h index 8c2c6158381..e8cff7ff8b2 100644 --- a/lib/Backend/ValueInfo.h +++ b/lib/Backend/ValueInfo.h @@ -153,6 +153,7 @@ class ValueInfo : protected ValueType using ValueType::IsLikelyTypedArray; using ValueType::IsOptimizedTypedArray; + using ValueType::IsOptimizedVirtualTypedArray; using ValueType::IsLikelyOptimizedTypedArray; using ValueType::IsLikelyOptimizedVirtualTypedArray; diff --git a/lib/Runtime/Language/ValueType.cpp b/lib/Runtime/Language/ValueType.cpp index 22ef773b63d..aa90004056f 100644 --- a/lib/Runtime/Language/ValueType.cpp +++ b/lib/Runtime/Language/ValueType.cpp @@ -650,6 +650,11 @@ bool ValueType::IsOptimizedTypedArray() const return IsObject() && ((GetObjectType() >= ObjectType::Int8Array && GetObjectType() <= ObjectType::Float64MixedArray)); } +bool ValueType::IsOptimizedVirtualTypedArray() const +{ + return IsObject() && (GetObjectType() >= ObjectType::Int8VirtualArray && GetObjectType() <= ObjectType::Float64VirtualArray); +} + bool ValueType::IsLikelyOptimizedTypedArray() const { return IsLikelyObject() && ((GetObjectType() >= ObjectType::Int8Array && GetObjectType() <= ObjectType::Float64MixedArray)); diff --git a/lib/Runtime/Language/ValueType.h b/lib/Runtime/Language/ValueType.h index f789653575c..431867a9b12 100644 --- a/lib/Runtime/Language/ValueType.h +++ b/lib/Runtime/Language/ValueType.h @@ -228,6 +228,7 @@ class ValueType bool IsTypedIntOrFloatArray() const; bool IsOptimizedTypedArray() const; + bool IsOptimizedVirtualTypedArray() const; bool IsLikelyOptimizedTypedArray() const; bool IsLikelyOptimizedVirtualTypedArray() const;