You need to agree to share your contact information to access this model

This repository is publicly accessible, but you have to accept the conditions to access its files and content.

Log in or Sign Up to review the conditions and access this model content.

YAML Metadata Warning:empty or missing yaml metadata in repo card

Check out the documentation for more information.

onnx-tensorrt weight-converter TensorProto dims-vs-data-length OOB read (ASan PoC)

Authorized security research for the huntr.com Model File Vulnerability program. Local-only reproduction. No third-party systems are touched.

Summary

onnx/onnx-tensorrt's ONNX weight converter reads volume(shape) elements from a TensorProto's data field without checking that the field actually contains that many elements/bytes. The declared dims/shape is attacker-controlled and stored separately from the actual data, so a crafted .onnx with large declared dims but a short data field causes an out-of-bounds heap READ.

Two distinct instances, one root cause (dims-declared-count vs actual-data-length mismatch in the typed weight-conversion helpers):

  • INSTANCE 1 - convertInt32Data<DataType> (WeightsContext.hpp lines 134-145). Reads volume(shape) int32 values from TensorProto.int32_data().data() with no check that int32_data_size() >= volume(shape). Reached from convertOnnxWeights for FLOAT16/BFLOAT16/INT8/BOOL initializers (WeightsContext.cpp lines 401/404/407) when raw_data is empty.

  • INSTANCE 2 - convertDouble (WeightsContext.cpp lines 48-78). Reads volume(shape) doubles with no check that the source buffer is that long. On the DOUBLE raw_data path (WeightsContext.cpp line 342) the raw_data byte length is never checked to be >= volume(shape) * sizeof(double).

Verified against onnx/onnx-tensorrt commit 7c51a63a719180eb5160c874c111746f3fb46a6b (main).

Why there is no upstream guard

convertOnnxWeights calls validateOnnxInitializer (WeightsContext.cpp 136-159) before conversion. That function validates only: data type is supported, rank <= MAX_DIMS, and that volume * typeSize does not integer overflow. It does NOT check that the actual data field length is >= volume(shape).

The post-conversion sanity check trt_weights.size_bytes() != nbytes (WeightsContext.cpp 489) fires only AFTER the read loop has already run off the end of the buffer, so it cannot prevent the OOB read.

Note: the sibling helper convertPackedInt32Data (WeightsContext.cpp 80-97) DOES guard (nbytes > newWeightsObj.size_bytes() -> reject). The int32/double helpers simply omit the same check.

Files

file what
harness.cpp Faithful standalone ASan harness. Parses the real crafted TensorProto wire bytes and runs the convertInt32Data / convertDouble read loops VERBATIM as in upstream.
build.sh protoc + clang++ -fsanitize=address build.
onnx.proto ONNX proto schema (from onnx/onnx main) used to parse the crafted TensorProto.
make_onnx.py Builds the crafted malicious .onnx models and raw TensorProto bytes (dims=[1024], data=4). Builds the proto directly to bypass onnx.helper client-side count validation, exactly as a real attacker crafting wire bytes would.
make_control.py Builds control TensorProto bytes (dims=[4], data=4) that match.
poc_int8_int32data_oob.onnx Malicious model, INT8 initializer, dims=[1024], int32_data=4.
poc_double_rawdata_oob.onnx Malicious model, DOUBLE initializer, dims=[1024], raw_data=4 doubles.
tp_int8.pb / tp_double.pb The raw crafted TensorProto bytes the harness consumes.
tp_int8_control.pb / tp_double_control.pb Matching-length controls.
asan_int8.log INSTANCE 1 ASan heap-buffer-overflow READ trace.
asan_double.log INSTANCE 2 ASan heap-buffer-overflow READ trace.
asan_control.log Both controls run clean (no crash).

Harness fidelity

The harness is a faithful copy of the upstream read paths, not a re-implementation:

  • convertInt32Data<DataType> and convertDouble are copied VERBATIM (only logging removed). The loop bound volume(shape) and the source pointer (int32_data().data() / raw_data().data()) are unchanged.
  • volume(shape) is the product of dims, matching upstream.
  • createTempWeights is replaced by a heap allocation of the SAME size the real allocator produces (volume(shape) * sizeof(T)), so both the source (protobuf buffer) and destination are ASan-tracked.
  • The source buffer is the ACTUAL protobuf backing store of the crafted TensorProto (ASan reports the overflow as being in the protobuf RepeatedField<int>::Reserve / InlineGreedyStringParser allocation), i.e. real attacker-controlled data, parsed from the crafted wire bytes.

Full onnx-tensorrt cannot be built standalone (requires TensorRT), so the read loops are extracted verbatim and driven by the real TensorProto structure.

Build and run

Requires clang++ with AddressSanitizer, protoc, and libprotobuf.

bash build.sh
./harness_asan int8   tp_int8.pb        # INSTANCE 1 -> ASan heap-buffer-overflow READ
./harness_asan double tp_double.pb      # INSTANCE 2 -> ASan heap-buffer-overflow READ
./harness_asan int8   tp_int8_control.pb    # control -> clean
./harness_asan double tp_double_control.pb  # control -> clean

Result

  • INSTANCE 1: AddressSanitizer: heap-buffer-overflow ... READ of size 4 in convertInt32Data<signed char>, 0 bytes after the 32-byte protobuf int32_data region.
  • INSTANCE 2: AddressSanitizer: heap-buffer-overflow ... READ of size 8 in convertDouble, 0 bytes after the 33-byte protobuf raw_data region.
  • Controls (matching lengths): no crash.

Impact

An attacker who supplies a crafted .onnx (a common untrusted input - models are routinely downloaded from public hubs and loaded by parsing pipelines) triggers an out-of-bounds heap read during weight conversion. Consequences: crash / denial of service, and potential disclosure of adjacent heap memory into the converted weights buffer.

Remediation

In convertOnnxWeights / validateOnnxInitializer, before invoking convertInt32Data / convertDouble (and the analogous typed helpers), validate that the actual data field length is >= volume(shape):

  • int32_data path: require onnxTensor.int32_data_size() >= volume(shape).
  • raw_data DOUBLE path: require onnxTensor.raw_data().size() >= volume(shape) * sizeof(double).

Reject the initializer if the check fails, mirroring the guard already present in convertPackedInt32Data.

Downloads last month

-

Downloads are not tracked for this model. How to track
Inference Providers NEW
This model isn't deployed by any Inference Provider. 🙋 Ask for provider support