Skip to content

Fix integer overflow in 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 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
Comment thread Tests/UnitTests/CMakeLists.txt Outdated
Comment thread Tests/UnitTests/Shared/Shared.cpp Outdated
napi_create_dataview validated the requested view with an unchecked
byte_length + byte_offset > bufferLength comparison. Both are caller-supplied
size_t values, so on 64-bit builds their sum can overflow and wrap past the
limit, slipping an out-of-range view past the check.

- Chakra: the truncated 32-bit values created a small valid view while the
  original 64-bit extents were stored in DataViewInfo and handed back by
  napi_get_dataview_info, giving an out-of-bounds access primitive.
- V8: the wrapped value passed the check and then tripped a fatal CHECK inside
  v8::DataView::New, aborting the process.

Both backends now validate byte_offset and byte_length against the buffer size
individually, without adding them. JavaScriptCore delegates to the JS DataView
constructor and is unaffected. The V8JSI Node-API shim does not implement
napi_create_dataview (its DataView::New throws "TODO"), so the regression test
is compiled out there; it runs on Chakra, V8, and JavaScriptCore on 64-bit.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@bkaradzic-microsoft bkaradzic-microsoft force-pushed the bk-fix-dataview-overflow branch from 7c4bd47 to a553dd1 Compare June 11, 2026 16:08
@bkaradzic-microsoft bkaradzic-microsoft changed the title Fix integer overflow in Chakra napi_create_dataview bounds check Fix integer overflow in napi_create_dataview bounds check Jun 11, 2026
@bkaradzic-microsoft

Copy link
Copy Markdown
Member Author

Removing the Chakra-only guard (per review) surfaced two pre-existing issues in the other backends, now fixed:

  • V8 (Win32_x64_V8, Android_V8) crashed rather than rejecting the overflow. napi_create_dataview in js_native_api_v8.cc carried the same unchecked byte_length + byte_offset > buffer->ByteLength() comparison; the wrapped sum slipped past it and v8::DataView::New hit a fatal CHECK (Check failed: byte_length <= buffer->GetByteLength()), aborting the process. Applied the same overflow-safe check, so V8 now rejects the overflow — exactly what the test asserts. Verified locally (V8 suite green).

  • JSI (Win32_x64_JSI) failed to compile (C3861: 'napi_create_dataview': identifier not found). The V8JSI Node-API shim (Core/Node-API-JSI) doesn't implement napi_create_dataview / napi_get_dataview_info at all — its DataView::New literally throw std::runtime_error{"TODO"}. Since the API is absent there, the test is compiled out on JSI via a JSRUNTIMEHOST_NAPI_ENGINE_JSI define. This is a genuine "API not implemented" gate (different from the earlier unnecessary Chakra-only define), so the test still runs on Chakra, V8, and JavaScriptCore on 64-bit.

Verified locally on all three: V8 passes, Chakra passes, JSI compiles cleanly (test gated out).

@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; one comment inline.


v8::Local<v8::ArrayBuffer> buffer = value.As<v8::ArrayBuffer>();
if (byte_length + byte_offset > buffer->ByteLength()) {
// byte_offset and byte_length are caller-supplied size_t values; computing

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.

Per our convention, changes to the vendored Node.js V8 N-API need the // [BABYLON-NATIVE-ADDITION] marker (e.g. lines 361, 2553, 3372) so the divergence stays visible when syncing from upstream.

Suggested change
// byte_offset and byte_length are caller-supplied size_t values; computing
// [BABYLON-NATIVE-ADDITION]: overflow-safe bounds check; not in Node.js upstream
// byte_offset and byte_length are caller-supplied size_t values; computing

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