CVE-2022-32234 (published 2022-10-11T01:15Z)

An out of bounds write in hermes, while handling large arrays, prior to commit 06eaec767e376bfdb883d912cb15e987ddf2bda1 allows attackers to potentially execute arbitrary code via crafted JavaScript. Note that this is only exploitable if the application using Hermes permits evaluation of untrusted JavaScript. Hence, most React Native applications are not affected.

CVSS v3 base score: 9.8, CRITICAL (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H)

Weakness information:
cwe_id: CWE-787
cwe_name: Out-of-bounds Write
description: The product writes data past the end, or before the beginning, of the intended buffer.
extended_description: 
            
            
             
			 
         
         

Fix information:
repo_url: https://github.com/facebook/hermes
commit_details: repo_url: https://github.com/facebook/hermes
author: Facebook Community Bot
author_date: 2022-07-06 16:51:56-07:00
msg: Re-sync with internal repository (#772)

Co-authored-by: Facebook Community Bot <6422482+facebook-github-bot@users.noreply.github.com>
repository: repo_url: https://github.com/facebook/hermes
repo_name: facebook/hermes
description: A JavaScript engine optimized for running React Native.
repo_language: C++
owner: facebook
file_changes: filename: SmallVector.h
change_type: ModificationType.MODIFY
diff: @@ -238,12 +238,16 @@ public:
 // Define this out-of-line to dissuade the C++ compiler from inlining it.
 template <typename T, bool isPodLike>
 void SmallVectorTemplateBase<T, isPodLike>::grow(size_t MinSize) {
-  if (MinSize > UINT32_MAX)
-    report_bad_alloc_error("SmallVector capacity overflow during allocation");
-
   // Always grow, even from zero.
-  size_t NewCapacity = size_t(NextPowerOf2(this->capacity() + 2));
-  NewCapacity = std::min(std::max(NewCapacity, MinSize), size_t(UINT32_MAX));
+  constexpr size_t MinGrowth = 2;
+  size_t NewCapacity = size_t(NextPowerOf2(this->capacity() + MinGrowth));
+  NewCapacity = static_cast<unsigned>(std::max(NewCapacity, MinSize));
+  // Ensure that NewCapacity did not overflow an unsigned int,
+  // and that the capacity in bytes will not overflow a size_t.
+  if (NewCapacity <= this->capacity() ||
+      NewCapacity < MinSize ||
+      NewCapacity > size_t(-1) / sizeof(T))
+    report_bad_alloc_error("SmallVector capacity overflow during allocation");
   T *NewElts = static_cast<T*>(llvh::safe_malloc(NewCapacity*sizeof(T)));
 
   // Move the elements over.

programming_language: C++
filename: SmallVector.cpp
change_type: ModificationType.MODIFY
diff: @@ -42,13 +42,16 @@ static_assert(sizeof(SmallVector<void *, 1>) ==
 /// on POD-like datatypes and is out of line to reduce code duplication.
 void SmallVectorBase::grow_pod(void *FirstEl, size_t MinCapacity,
                                size_t TSize) {
-  // Ensure we can fit the new capacity in 32 bits.
-  if (MinCapacity > UINT32_MAX)
-    report_bad_alloc_error("SmallVector capacity overflow during allocation");
+  constexpr size_t MinGrowth = 1;
+  size_t NewCapacity = 2 * capacity() + MinGrowth; // Always grow.
+  NewCapacity = static_cast<unsigned>(std::max(NewCapacity, MinCapacity));
 
-  size_t NewCapacity = 2 * capacity() + 1; // Always grow.
-  NewCapacity =
-      std::min(std::max(NewCapacity, MinCapacity), size_t(UINT32_MAX));
+  // Ensure that NewCapacity did not overflow an unsigned int,
+  // and that the capacity in bytes will not overflow a size_t.
+  if (NewCapacity <= this->capacity() ||
+      NewCapacity < MinCapacity ||
+      NewCapacity > size_t(-1) / TSize)
+    report_bad_alloc_error("SmallVector capacity overflow during allocation");
 
   void *NewElts;
   if (BeginX == FirstEl) {

programming_language: C++
filename: SmallVector.patch
change_type: ModificationType.ADD
diff: @@ -0,0 +1,51 @@
+diff --git a/xplat/hermes/external/llvh/include/llvh/ADT/SmallVector.h b/xplat/hermes/external/llvh/include/llvh/ADT/SmallVector.h
+--- a/xplat/hermes/external/llvh/include/llvh/ADT/SmallVector.h
++++ b/xplat/hermes/external/llvh/include/llvh/ADT/SmallVector.h
+@@ -238,12 +238,16 @@
+ // Define this out-of-line to dissuade the C++ compiler from inlining it.
+ template <typename T, bool isPodLike>
+ void SmallVectorTemplateBase<T, isPodLike>::grow(size_t MinSize) {
+-  if (MinSize > UINT32_MAX)
+-    report_bad_alloc_error("SmallVector capacity overflow during allocation");
+-
+   // Always grow, even from zero.
+-  size_t NewCapacity = size_t(NextPowerOf2(this->capacity() + 2));
+-  NewCapacity = std::min(std::max(NewCapacity, MinSize), size_t(UINT32_MAX));
++  constexpr size_t MinGrowth = 2;
++  size_t NewCapacity = size_t(NextPowerOf2(this->capacity() + MinGrowth));
++  NewCapacity = static_cast<unsigned>(std::max(NewCapacity, MinSize));
++  // Ensure that NewCapacity did not overflow an unsigned int,
++  // and that the capacity in bytes will not overflow a size_t.
++  if (NewCapacity <= this->capacity() ||
++      NewCapacity < MinSize ||
++      NewCapacity > size_t(-1) / sizeof(T))
++    report_bad_alloc_error("SmallVector capacity overflow during allocation");
+   T *NewElts = static_cast<T*>(llvh::safe_malloc(NewCapacity*sizeof(T)));
+ 
+   // Move the elements over.
+diff --git a/xplat/hermes/external/llvh/lib/Support/SmallVector.cpp b/xplat/hermes/external/llvh/lib/Support/SmallVector.cpp
+--- a/xplat/hermes/external/llvh/lib/Support/SmallVector.cpp
++++ b/xplat/hermes/external/llvh/lib/Support/SmallVector.cpp
+@@ -42,13 +42,16 @@
+ /// on POD-like datatypes and is out of line to reduce code duplication.
+ void SmallVectorBase::grow_pod(void *FirstEl, size_t MinCapacity,
+                                size_t TSize) {
+-  // Ensure we can fit the new capacity in 32 bits.
+-  if (MinCapacity > UINT32_MAX)
+-    report_bad_alloc_error("SmallVector capacity overflow during allocation");
++  constexpr size_t MinGrowth = 1;
++  size_t NewCapacity = 2 * capacity() + MinGrowth; // Always grow.
++  NewCapacity = static_cast<unsigned>(std::max(NewCapacity, MinCapacity));
+ 
+-  size_t NewCapacity = 2 * capacity() + 1; // Always grow.
+-  NewCapacity =
+-      std::min(std::max(NewCapacity, MinCapacity), size_t(UINT32_MAX));
++  // Ensure that NewCapacity did not overflow an unsigned int,
++  // and that the capacity in bytes will not overflow a size_t.
++  if (NewCapacity <= this->capacity() ||
++      NewCapacity < MinCapacity ||
++      NewCapacity > size_t(-1) / TSize)
++    report_bad_alloc_error("SmallVector capacity overflow during allocation");
+ 
+   void *NewElts;
+   if (BeginX == FirstEl) {

programming_language: Objective-C