Skip to content

Fix integer overflow in Chakra napi_create_dataview bounds check#181

Open
bkaradzic-microsoft wants to merge 1 commit into
BabylonJS:mainfrom
bkaradzic-microsoft:bk-fix-dataview-overflow
Open

Fix integer overflow in Chakra napi_create_dataview bounds check#181
bkaradzic-microsoft wants to merge 1 commit into
BabylonJS:mainfrom
bkaradzic-microsoft:bk-fix-dataview-overflow

Conversation

@bkaradzic-microsoft

Copy link
Copy Markdown
Member

Summary

napi_create_dataview (Chakra backend) validated the requested view with an unchecked byte_length + byte_offset > bufferLength comparison. Both operands are caller-supplied size_t values, so on 64-bit builds their sum can overflow and wrap past the limit. When that happens:

  • the values are truncated to 32-bit for JsCreateDataView (yielding a small, valid view), but
  • the original 64-bit byte_offset/byte_length are stored in DataViewInfo and later returned by napi_get_dataview_info alongside the small backing buffer

…handing a calling native addon an out-of-bounds read/write primitive (CWE-190 → CWE-125/787, also CWE-681).

Fix

Validate byte_offset and byte_length against the buffer size individually, without adding them:
cpp if (byte_offset > bufferLength || byte_length > bufferLength - byte_offset) { /* range error */ }
After this check both values are <= bufferLength (a 32-bit quantity), so the later 32-bit truncation and the values stored in DataViewInfo are guaranteed in range.

  • JavaScriptCore backend delegates to the JS DataView constructor → unaffected.
  • V8 backend carries the same upstream pattern but is vendored verbatim from Node → left untouched.

Test

This path is not reachable from JS (new DataView uses the engine directly, not this N-API), so coverage is a native gtest. It crafts an offset/length whose low 32 bits are valid for a 16-byte buffer but whose 64-bit sum wraps, and asserts the view is rejected (and never reports the raw 64-bit extents). Guarded to the Chakra engine and 64-bit builds (JSRUNTIMEHOST_NAPI_ENGINE_CHAKRA + _WIN64).

Verified the test fails on the pre-fix code and passes after the fix; full suite green (5 native tests + 151 JS tests) on Win32-x64 Chakra Debug.

Copilot AI review requested due to automatic review settings June 4, 2026 16:35

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This pull request hardens the Chakra Node-API implementation of napi_create_dataview against a size_t addition overflow in its bounds check, preventing creation of a DataView whose stored (reported) offset/length could be out of range for the underlying buffer (potential OOB access in native addons). It also adds a targeted native regression test and wires up a build define so the test only compiles/runs for the Chakra configuration.

Changes:

  • Fix overflow-prone range validation in napi_create_dataview by checking byte_offset and byte_length against the buffer size without adding them.
  • Add a Chakra + 64-bit guarded gtest regression that reproduces the wraparound scenario and asserts the request is rejected (or at minimum never reports raw huge extents).
  • Add a CMake compile definition (JSRUNTIMEHOST_NAPI_ENGINE_CHAKRA) for UnitTests when building with the Chakra backend.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.

File Description
Core/Node-API/Source/js_native_api_chakra.cc Replaces the overflow-prone byte_length + byte_offset bounds check with a subtraction-based check that cannot overflow and keeps stored DataViewInfo extents in range.
Tests/UnitTests/Shared/Shared.cpp Adds a Chakra/_WIN64 regression test that constructs an overflowing (offset, length) pair and verifies it is rejected (and does not leak huge extents via napi_get_dataview_info).
Tests/UnitTests/CMakeLists.txt Defines JSRUNTIMEHOST_NAPI_ENGINE_CHAKRA for UnitTests when NAPI_JAVASCRIPT_ENGINE is Chakra, enabling the guarded regression test.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@bkaradzic-microsoft bkaradzic-microsoft enabled auto-merge (squash) June 4, 2026 19:30
@bkaradzic-microsoft bkaradzic-microsoft force-pushed the bk-fix-dataview-overflow branch from e448fbf to 3025fb8 Compare June 9, 2026 16:29

@bghgary bghgary left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Reviewed by Copilot on behalf of @bghgary]

Fix LGTM; comments inline.

Comment thread Tests/UnitTests/Shared/Shared.cpp Outdated
testThread.join();
}

#ifdef JSRUNTIMEHOST_NAPI_ENGINE_CHAKRA

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Drop this guard. The test's assertions are backend-agnostic (overflow rejected, or reported extents in range), so it should run on V8/JSC too and verify they reject the overflow instead of assuming it. The guard also only exists by adding the JSRUNTIMEHOST_NAPI_ENGINE_CHAKRA compile-def in CMakeLists, which is otherwise unused — so this forces a CMake change for no real reason.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done — removed the JSRUNTIMEHOST_NAPI_ENGINE_CHAKRA guard. The test is backend-agnostic (it asserts the overflow is either rejected or reported in range), so it now runs on V8/JSC too and verifies they reject it. Confirmed it still passes on Chakra locally.

Comment thread Tests/UnitTests/CMakeLists.txt Outdated
target_compile_definitions(UnitTests PRIVATE JSRUNTIMEHOST_PLATFORM="${JSRUNTIMEHOST_PLATFORM}")

if(NAPI_JAVASCRIPT_ENGINE STREQUAL "Chakra")
target_compile_definitions(UnitTests PRIVATE JSRUNTIMEHOST_NAPI_ENGINE_CHAKRA)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This compile-def exists only to drive the Chakra #ifdef around the new test. With that guard removed, nothing else uses it — drop this block too.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done — dropped this block; with the #ifdef removed, nothing else used JSRUNTIMEHOST_NAPI_ENGINE_CHAKRA.

Comment thread Tests/UnitTests/Shared/Shared.cpp Outdated
}

#ifdef JSRUNTIMEHOST_NAPI_ENGINE_CHAKRA
#ifdef _WIN64

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_WIN64 is MSVC/Windows-only, not a portable 64-bit check. The precondition is a 64-bit size_t, and <cstdint> is already included:

Suggested change
#ifdef _WIN64
#if SIZE_MAX > 0xFFFFFFFFu

Leave this as the sole guard — it also works on the non-Windows backends the test should now run on.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done — replaced _WIN64 with #if SIZE_MAX > 0xFFFFFFFFu as the sole guard (<cstdint> is already included), so it's a portable 64-bit size_t check that also covers the non-Windows backends.

napi_create_dataview validated the requested view with an unchecked
�yte_length + byte_offset > bufferLength comparison. byte_length and
byte_offset are caller-supplied size_t values, so on 64-bit builds their sum
can overflow and wrap past the limit. When that happens the values are then
truncated to 32-bit for JsCreateDataView (creating a small, valid view) while
the ORIGINAL 64-bit values are stored in DataViewInfo and later returned by
napi_get_dataview_info alongside the small backing buffer, giving a calling
addon an out-of-bounds read/write primitive.

Validate byte_offset and byte_length against the buffer size individually
without adding them, so neither overflow nor the subsequent 32-bit truncation
can slip an out-of-range view past the check. After the check both values are
<= bufferLength (a 32-bit quantity), so the truncation and the stored values
are guaranteed in range.

The JavaScriptCore backend delegates to the JS DataView constructor and is
unaffected. The V8 backend carries the same upstream pattern but is vendored
verbatim from Node and left untouched.

Add a native regression test (the path is not reachable from JS
ew DataView)
that crafts an offset/length whose low 32 bits are valid but whose 64-bit sum
wraps, and asserts the view is rejected (or at least never reports the raw
64-bit extents). Guarded to the Chakra engine and 64-bit builds.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants