CVE-2021-4327 (C++, published 2023-03-01T11:15Z)
Description: value: 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.
Severity: nan (CVSS v3 base score: 9.8)
Weakness: CWE-190 \u2014 Integer Overflow or Wraparound
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.
Repository: https://github.com/SerenityOS/serenity
Files changed:
Userland/Libraries/LibJS/Runtime/TypedArray.cpp
Userland/Libraries/LibJS/Tests/builtins/TypedArray/typed-array-from-ArrayBuffer-bad-offset.js
Commit message: LibJS: Add overflow checks when creating TypedArray from ArrayBuffer

Thanks to Iliad for finding this! :^)


Vulnerable code:
    size_t new_byte_length;
        new_byte_length = buffer_byte_length - offset;
        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);
    typed_array.set_byte_length(new_byte_length);
    typed_array.set_array_length(new_byte_length / element_size);

Fixed code:
    Checked<size_t> new_byte_length;
        new_byte_length = buffer_byte_length;
        new_byte_length -= offset;
        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);
    if (new_byte_length.has_overflow()) {
        vm.throw_exception<RangeError>(global_object, ErrorType::InvalidLength, "typed array");
        return;
    }

    typed_array.set_byte_length(new_byte_length.value());
    typed_array.set_array_length(new_byte_length.value() / element_size);
test("construct Uint32Array with zero-length ArrayBuffer and overflowing offset", () => {
    expect(() => new Uint32Array(new ArrayBuffer(0), 4, 1024 * 1024 * 1024 - 1)).toThrow(
        RangeError
    );
});