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.

ArmNN Deserializer β€” Stack Buffer Overflow via TensorInfo.dimensionSpecificity (CWE-121)

Summary

ARM-software/armnn's native model-file parser (armnnDeserializer, src/armnnDeserializer/Deserializer.cpp) deserializes .armnn FlatBuffers model files. The free function armnnDeserializer::ToTensorInfo() (Deserializer.cpp, around line 743-760) decodes every TensorInfo table that appears anywhere in a model file (every layer's input/output tensor descriptors, constant tensors, etc.) and copies the optional dimensionSpecificity FlatBuffers vector into a fixed 5-element stack array:

auto dimensions = tensorPtr->dimensions();
unsigned int size = dimensions->size();
std::vector<unsigned int> outputDims(dimensions->begin(), dimensions->begin() + size);
bool dimensionsSpecificity[armnn::MaxNumOfTensorDimensions];   // stack array, size == 5
std::fill_n(dimensionsSpecificity, armnn::MaxNumOfTensorDimensions, true);
if (tensorPtr->dimensionSpecificity() != nullptr)
{
    auto dimensionSpecificity = tensorPtr->dimensionSpecificity();
    size = dimensionSpecificity->size();          // <-- attacker-controlled length, NOT clamped
    for (unsigned int i = 0; i < size; ++i)
    {
        dimensionsSpecificity[i] = dimensionSpecificity->Get(i);   // <-- OOB WRITE once i >= 5
    }
}

armnn::MaxNumOfTensorDimensions is 5 (include/armnn/Types.hpp). The loop bound size is taken directly from the length of the attacker-supplied dimensionSpecificity FlatBuffers vector, with no check against the fixed stack buffer size. Any TensorInfo in the model file whose dimensionSpecificity vector has more than 5 elements causes the loop to write attacker-controlled boolean bytes (each element is the raw byte from the file, coerced to bool) past the end of the 5-byte stack array, corrupting adjacent stack memory (other stack locals, saved registers, padding, and β€” depending on compiler/stack layout/optimization level β€” potentially the return address) for as many bytes as the attacker declares the vector to be (we tested 40 bytes in the PoC; the vector length field is a FlatBuffers uint32 count, so far larger overflows are possible in a single call).

ToTensorInfo() is called from nearly every layer parser in the file (ParseFloor, ParseAdd, ParseActivation, ParseConvolution2d, ... β€” over 50 call sites), so this is reachable through essentially any .armnn model that contains an Input/Output/any-layer TensorInfo with a crafted dimensionSpecificity field. This PoC uses the simplest possible layer (FloorLayer) to reach it via a single output slot's TensorInfo.

Attacker input β†’ sink

  1. Application loads an untrusted .armnn model file with armnnDeserializer::IDeserializer::CreateNetworkFromBinary() β€” the standard, documented entry point used by ExecuteNetwork and any ArmNN-based downstream integrator that accepts serialized ArmNN models.
  2. CreateNetworkFromGraph() walks graph->layers() and dispatches each layer to its parser function (Deserializer.cpp:927-937).
  3. The crafted FloorLayer's output slot carries a TensorInfo whose dimensionSpecificity vector has 40 elements (dimensions only has 1).
  4. ParseFloor() (Deserializer.cpp:2253) calls ToTensorInfo(outputs[0]).
  5. ToTensorInfo() writes 40 bytes into a 5-byte stack array (Deserializer.cpp:756) β†’ stack-buffer-overflow.

Reproduction

Built at ArmNN commit (see ARMNN_COMMIT.txt), 2026-07-02, current main HEAD at time of testing.

# 1. Generate ArmnnSchema_generated.h and build armnnDeserializer + armnn
#    (core, no backends needed) with ASan, NDEBUG (Release-like, matches
#    real deployment: flatbuffers' internal asserts are compiled out):
cmake -S armnn -B build -G Ninja \
  -DBUILD_ARMNN_DESERIALIZER=ON -DBUILD_UNIT_TESTS=OFF -DBUILD_TESTS=OFF \
  -DBUILD_ONNX_PARSER=OFF -DBUILD_TF_LITE_PARSER=OFF -DBUILD_ARMNN_SERIALIZER=OFF \
  -DFLATC_DIR=/usr/bin -DFLATBUFFERS_LIBRARY=<path-to-libflatbuffers.so> \
  -DFLATBUFFERS_INCLUDE_PATH=<flatbuffers-include-dir> \
  -DCMAKE_CXX_FLAGS="-fsanitize=address -g -O1 -DNDEBUG" \
  -DCMAKE_EXE_LINKER_FLAGS="-fsanitize=address"
ninja -C build armnnDeserializer

# 2. Compile this harness against the just-built libraries (same compiler,
#    e.g. g++, as used for the library, to avoid mixed ASan runtimes):
g++ -std=c++17 -fsanitize=address -g -O1 -DNDEBUG \
  -I armnn/include -I armnn/src/armnnUtils -I armnn/generated \
  -I <flatbuffers-include-dir> \
  harness.cpp -L build -Wl,-rpath,build -larmnnDeserializer -larmnn -o harness

# 3. Craft the model file (already provided as poc_floor_stackoverflow.armnn,
#    built from poc_floor_stackoverflow.json via):
flatc -b armnn/src/armnnSerializer/ArmnnSchema.fbs poc_floor_stackoverflow.json

# 4. Run:
LD_LIBRARY_PATH=build ASAN_OPTIONS=detect_leaks=0 ./harness poc_floor_stackoverflow.armnn

Observed result (real evidence, not theoretical)

AddressSanitizer reports a stack-buffer-overflow WRITE of size 1, directly at the vulnerable line, with a clean call stack from the public CreateNetworkFromBinary API down to the vulnerable write:

==420219==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7b4d36bf1885 ...
WRITE of size 1 at 0x7b4d36bf1885 thread T0
    #0 ... armnnDeserializer::ToTensorInfo(armnnSerializer::TensorInfo const*) Deserializer.cpp:756
    #1 ... armnnDeserializer::IDeserializer::DeserializerImpl::ParseFloor(...) Deserializer.cpp:2253
    #2 ... armnnDeserializer::IDeserializer::DeserializerImpl::CreateNetworkFromGraph(...) Deserializer.cpp:934
    #3 ... armnnDeserializer::IDeserializer::DeserializerImpl::CreateNetworkFromBinary(...) Deserializer.cpp:882
    #4 ... armnnDeserializer::IDeserializer::CreateNetworkFromBinary(...) Deserializer.cpp:59
    #5 ... main harness.cpp:29
...
Address 0x7b4d36bf1885 is located in stack of thread T0 at offset 133 in frame
    #0 ... armnnDeserializer::ToTensorInfo(...) Deserializer.cpp:679
  ...
    [128, 133) 'dimensionsSpecificity' (line 746) <== Memory access at offset 133 overflows this variable

Full log: asan_crash_log.txt.

Dedup / prior-art check

  • git blame shows this exact code has been present, unmodified in the relevant lines, since commit 800b281e50 (2021-02-12) β€” over 5 years, and is still present at the current main HEAD (2b61cecc9d, 2026-07-02).
  • No matching GitHub issue, PR, security advisory, or CVE for ArmNN mentions dimensionSpecificity, ToTensorInfo, or a deserializer stack overflow. The only related public fix we found (a heap overflow in SpaceToBatchND input-type validation) is in the separate armnnTfLiteParser component (TensorFlow Lite import), not armnnDeserializer (ArmNN's own native FlatBuffers format), and concerns input-type validation, not tensor-shape/stack handling.
  • Distinct root cause from the companion padList/crops heap-overflow finding filed alongside this one (different function, different bug class β€” fixed-size stack buffer overflow vs. unsigned-integer-underflow driven heap OOB read).

Suggested fix

Clamp the loop bound to armnn::MaxNumOfTensorDimensions (and reject/throw a ParseException if dimensionSpecificity->size() > armnn::MaxNumOfTensorDimensions, mirroring the pattern already used elsewhere in this file for other size-mismatch checks).

Files

  • poc_floor_stackoverflow.json β€” human-readable FlatBuffers JSON for the crafted model (one InputLayer, one FloorLayer whose output TensorInfo.dimensionSpecificity has 40 entries vs. a 5-element stack buffer).
  • poc_floor_stackoverflow.armnn β€” the compiled crafted model file (flatc -b ArmnnSchema.fbs poc_floor_stackoverflow.json).
  • harness.cpp β€” minimal driver that calls the real, unmodified armnnDeserializer::IDeserializer::CreateNetworkFromBinary() API on a file path given on the command line.
  • ArmnnSchema.fbs β€” copy of the exact schema used (from the tested commit), needed to regenerate the .armnn file with flatc.
  • asan_crash_log.txt β€” full AddressSanitizer report from running the harness against the PoC file.
  • ARMNN_COMMIT.txt β€” the exact ARM-software/armnn commit hash this was built and tested against.
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