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

Check out the documentation for more information.

Arm NN ParseSplitter descriptor-count OOB read

Summary

Arm NN's native .armnn deserializer trusts ViewsDescriptor.numDimensions as the inner-loop bound in ParseSplitter(). It does not cross-check that value against either viewSizes[v].data.size() or viewOrigins[v].data.size().

The supplied model is a valid outer FlatBuffer. It contains two one-dimensional split views but declares numDimensions = 1,000,000. Loading it through IDeserializer::CreateNetworkFromBinary() causes an attacker-sized out-of-bounds read in ParseSplitter() at Deserializer.cpp:3285.

Verified target

  • Repository: ARM-software/armnn
  • Commit: 2b61cecc9df7a43fca1463795062cf359e6be820
  • Date: 2026-07-02
  • Library: libarmnnDeserializer.35.0
  • Entry point: armnnDeserializer::IDeserializer::CreateNetworkFromBinary

Root cause

Deserializer.cpp:3269-3287 reads four independently serialized values:

auto flatBufferViewSizes = flatBufferViewsDescriptor->viewSizes();
auto flatBufferOriginsDescriptor = flatBufferViewsDescriptor->origins();
auto flatBufferViewOrigins = flatBufferOriginsDescriptor->viewOrigins();
uint32_t numViews = flatBufferOriginsDescriptor->numViews();
uint32_t numDimensions = flatBufferOriginsDescriptor->numDimensions();

The source then contains a comment stating the required cross-checks, but does not implement them. Instead, it loops to the attacker-controlled counts:

for (unsigned int vIdx = 0; vIdx < numViews; ++vIdx)
{
    for (unsigned int dIdx = 0; dIdx < numDimensions; ++dIdx)
    {
        viewsDescriptor.SetViewSize(
            vIdx, dIdx, flatBufferViewSizes->Get(vIdx)->data()->Get(dIdx));
        viewsDescriptor.SetViewOriginCoord(
            vIdx, dIdx, flatBufferViewOrigins->Get(vIdx)->data()->Get(dIdx));
    }
}

FlatBuffers verifies each vector independently. It cannot infer that the separate count fields must match those vectors.

Differential proof

The two 908-byte models are identical except for numDimensions:

  • control.armnn: numDimensions = 1
  • trigger.armnn: numDimensions = 1,000,000

Three control runs completed with exit code 0. Three trigger runs terminated with exit code 134 and the same AddressSanitizer container-overflow in ParseSplitter().

SHA-256:

  • control: 03edb0b73c14ce283b1d39d70b3d4913d157e072a1dd63ae15193b252933014c
  • trigger: dfdfbb9c1302bae1b47a50e39a46738b6b1aae6ca2033e90206269a17038a6b3

Reproduction

With an ASan/UBSan Arm NN build in cyber/huntr-mfv/build-armnn:

chmod +x reproduce.sh
./reproduce.sh /absolute/path/to/makemoney

The control loads, optimizes, and executes successfully. The trigger fails during deserialization, before runtime execution.

Impact

An untrusted native Arm NN model can make the deserializer read beyond the model buffer by an attacker-controlled distance. The demonstrated result is a reliable process crash. The values read out of bounds are also consumed as view metadata, which may influence subsequent descriptor construction before a crash.

Prior-art distinction

The closest public report is EnigmaConsultant's ParseConcat finding. That report concerns OriginsDescriptor in ParseConcat() at a different source and fix site. This report concerns ViewsDescriptor in ParseSplitter(), where both viewSizes and viewOrigins require validation. Exact ParseSplitter, ViewsDescriptor, source-line, hash, and sanitizer-signature searches returned no public match.

Suggested fix

Before allocating or iterating:

  1. Require viewSizes, origins, and viewOrigins to be non-null.
  2. Require numViews to equal the number of output slots, viewSizes.size(), and viewOrigins.size().
  3. Require every per-view data vector to be non-null and exactly numDimensions elements long.
  4. Reject impractical counts before constructing armnn::ViewsDescriptor.
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