Skip to content

[Runtime][VM] Bounds-check per-parameter byteOffset/nbytes in tensor-cache loader - #348

Open
professor-moody wants to merge 6 commits into
mlc-ai:mlcfrom
professor-moody:harden-tensorcache-param-bounds
Open

[Runtime][VM] Bounds-check per-parameter byteOffset/nbytes in tensor-cache loader#348
professor-moody wants to merge 6 commits into
mlc-ai:mlcfrom
professor-moody:harden-tensorcache-param-bounds

Conversation

@professor-moody

Copy link
Copy Markdown

Mirrors the same tensor-cache hardening as upstream apache/tvm#19997.

ParamRecord::Load copies each parameter from the shard buffer using byte_offset and nbytes from tensor-cache.json. FileRecord::Load validates only the shard total, not each parameter's range, so an inconsistent cache directory reads out of bounds of the shard buffer. The f32-to-bf16 path additionally allocates buffer(nbytes / 2), which is one byte short of the memcpy when nbytes is odd.

This adds, in ParamRecord::Load: a null check on the shard buffer, an overflow-safe range check (byte_offset/nbytes within the shard), and an even-nbytes check on the f32-to-bf16 path. Malformed/inconsistent cache input now fails with a clear ValueError instead of reading or writing out of bounds.

tqchen and others added 6 commits July 10, 2026 15:14
MLC local ci setup. Also CI for Windows and macOS building,
which may take 90-100 mins.

Co-authored-by: Siyuan Feng <Hzfengsy@sjtu.edu.cn>
- Revert "[CMake][MSVC] Disable permissive mode for MSVC builds (#16343)"
- Skip MSC tests
- Disable NNPack and TFLite
- Tweak CMAKE_CUDA_ARCHITECTURES
Draft message; will be rewritten via commit-amend guidance.
…cache loader

ParamRecord::Load copies each parameter from the shard buffer using byte_offset
and nbytes taken from tensor-cache.json. FileRecord::Load validates only the
shard total, not each parameter's range, so an inconsistent cache reads out of
bounds of the shard buffer. The f32-to-bf16 path additionally allocates
buffer(nbytes/2), which is one byte short of the memcpy for odd nbytes.

Add a null check, an overflow-safe range check, and an even-nbytes check on the
f32-to-bf16 path so malformed input fails with a clear ValueError. Mirrors the
same hardening upstream in apache/tvm#19997.

@gemini-code-assist gemini-code-assist Bot 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.

Code Review

This pull request adds bounds checking for parameter byte ranges against the shard buffer in TensorCacheMetadata::FileRecord::ParamRecord::Load to prevent out-of-bounds reads, and validates that nbytes is even for the f32-to-bf16 format. The review feedback identifies two potential undefined behavior issues: a signed integer overflow risk in the error message's addition of byte_offset + nbytes, and a null pointer passing to std::memcpy if nbytes is zero. Both comments are valid and should be addressed.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines +165 to +166
<< "Parameter byte range [" << byte_offset << ", " << (byte_offset + nbytes)
<< ") is out of bounds of the " << shard_len << "-byte shard buffer.";

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.

high

Although the bounds check is written to avoid signed overflow on byte_offset + nbytes, the error message itself evaluates byte_offset + nbytes. If a malformed or malicious tensor-cache.json contains extremely large values (e.g., byte_offset = INT64_MAX), this addition will trigger signed integer overflow, which is undefined behavior in C++. To prevent this, avoid performing the addition in the error message stream and print the offset and length separately.

      << "Parameter byte range starting at " << byte_offset << " with length " << nbytes
      << " is out of bounds of the " << shard_len << "-byte shard buffer.";

<< "Parameter nbytes must be even for the f32-to-bf16 format, but got " << nbytes << ".";
std::vector<uint16_t> buffer(nbytes / 2);
std::vector<uint32_t> decoded(nbytes / 2);
std::memcpy(buffer.data(), raw_data->data() + byte_offset, nbytes);

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.

medium

If nbytes is 0, buffer will be empty and buffer.data() will return nullptr. Passing a null pointer to std::memcpy even with a size of 0 is undefined behavior in C++. Guard the std::memcpy call with a check for nbytes > 0 to prevent this.

    if (nbytes > 0) {
      std::memcpy(buffer.data(), raw_data->data() + byte_offset, nbytes);
    }

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