CVE-2021-4327 (published 2023-03-01T11:15Z)

A vulnerability was found in SerenityOS. It has been rated as critical. Affected by this issue is the function initialize_typed_array_from_array_buffer in the library Userland/Libraries/LibJS/Runtime/TypedArray.cpp. The manipulation leads to integer overflow. The exploit has been disclosed to the public and may be used. Continious delivery with rolling releases is used by this product. Therefore, no version details of affected nor updated releases are available. The patch is identified as f6c6047e49f1517778f5565681fb64750b14bf60. It is recommended to apply a patch to fix this issue. VDB-222074 is the identifier assigned to this vulnerability.

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-190
cwe_name: Integer Overflow or Wraparound
description: The product performs a calculation that can
         produce an integer overflow or wraparound when the logic
         assumes that the resulting value will always be larger than
         the original value. This occurs when an integer value is
         incremented to a value that is too large to store in the
         associated representation. When this occurs, the value may
         become a very small or negative number.
extended_description: 
            
            
            
            
         
         

Fix information:
repo_url: https://github.com/SerenityOS/serenity
commit_details: repo_url: https://github.com/SerenityOS/serenity
author: Andreas Kling
author_date: 2021-01-27 07:50:46+01:00
msg: LibJS: Add overflow checks when creating TypedArray from ArrayBuffer

Thanks to Iliad for finding this! :^)
repository: repo_url: https://github.com/SerenityOS/serenity
repo_name: SerenityOS/serenity
description: The Serenity Operating System 🐞
repo_language: C++
owner: SerenityOS
file_changes: filename: TypedArray.cpp
change_type: ModificationType.MODIFY
diff: @@ -54,7 +54,7 @@ static void initialize_typed_array_from_array_buffer(GlobalObject& global_object
     }
     // FIXME: 8. If IsDetachedBuffer(buffer) is true, throw a TypeError exception.
     auto buffer_byte_length = array_buffer.byte_length();
-    size_t new_byte_length;
+    Checked<size_t> new_byte_length;
     if (length.is_undefined()) {
         if (buffer_byte_length % element_size != 0) {
             vm.throw_exception<RangeError>(global_object, ErrorType::TypedArrayInvalidBufferLength, typed_array.class_name(), element_size, buffer_byte_length);
@@ -64,18 +64,34 @@ static void initialize_typed_array_from_array_buffer(GlobalObject& global_object
             vm.throw_exception<RangeError>(global_object, ErrorType::TypedArrayOutOfRangeByteOffset, offset, buffer_byte_length);
             return;
         }
-        new_byte_length = buffer_byte_length - offset;
+        new_byte_length = buffer_byte_length;
+        new_byte_length -= offset;
     } else {
-        new_byte_length = new_length * element_size;
-        if (offset + new_byte_length > buffer_byte_length) {
-            vm.throw_exception<RangeError>(global_object, ErrorType::TypedArrayOutOfRangeByteOffsetOrLength, offset, offset + new_byte_length, buffer_byte_length);
+        new_byte_length = new_length;
+        new_byte_length *= element_size;
+
+        Checked<size_t> new_byte_end = new_byte_length;
+        new_byte_end += offset;
+
+        if (new_byte_end.has_overflow()) {
+            vm.throw_exception<RangeError>(global_object, ErrorType::InvalidLength, "typed array");
+            return;
+        }
+
+        if (new_byte_end.value() > buffer_byte_length) {
+            vm.throw_exception<RangeError>(global_object, ErrorType::TypedArrayOutOfRangeByteOffsetOrLength, offset, new_byte_end.value(), buffer_byte_length);
             return;
         }
     }
+    if (new_byte_length.has_overflow()) {
+        vm.throw_exception<RangeError>(global_object, ErrorType::InvalidLength, "typed array");
+        return;
+    }
+
     typed_array.set_viewed_array_buffer(&array_buffer);
-    typed_array.set_byte_length(new_byte_length);
+    typed_array.set_byte_length(new_byte_length.value());
     typed_array.set_byte_offset(offset);
-    typed_array.set_array_length(new_byte_length / element_size);
+    typed_array.set_array_length(new_byte_length.value() / element_size);
 }
 
 void TypedArrayBase::visit_edges(Visitor& visitor)

programming_language: Objective-C
filename: typed-array-from-ArrayBuffer-bad-offset.js
change_type: ModificationType.ADD
diff: @@ -0,0 +1,5 @@
+test("construct Uint32Array with zero-length ArrayBuffer and overflowing offset", () => {
+    expect(() => new Uint32Array(new ArrayBuffer(0), 4, 1024 * 1024 * 1024 - 1)).toThrow(
+        RangeError
+    );
+});

programming_language: TypeScript