YAML Metadata Warning:empty or missing yaml metadata in repo card
Check out the documentation for more information.
PoC: heap OOB read in ArmNN deserializer ParseSplitter via unchecked numViews (CWE-125)
Loading a crafted ArmNN model (.armnn flatbuffer) with a Splitter layer whose OriginsDescriptor.numViews
exceeds the layer's actual output-slot count reads out of bounds in the deserializer.
Root cause
src/armnnDeserializer/Deserializer.cpp (ParseSplitter):
TensorRawPtrVector outputs = GetOutputs(graph, layerIndex); // size = layer->outputSlots()->size()
uint32_t numViews = flatBufferOriginsDescriptor->numViews(); // SEPARATE attacker field
// Check numViews and numDimensions corresponds to the ones already serialized ...
// numViews == flatBufferViewSizes.size(); // <-- cross-check COMMENTED OUT (3276-3278)
...
for (unsigned int vIdx = 0; vIdx < numViews; ++vIdx) {
armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[vIdx]); // :3301 std::vector op[] no bound
layer->GetOutputSlot(vIdx).SetTensorInfo(outputTensorInfo);
}
outputs is sized to the serialized output-slot count (GetOutputs โ layer->outputSlots()->size()), but
numViews is read independently from the Splitter's OriginsDescriptor with no validation โ the
intended cross-check numViews == flatBufferViewSizes.size() exists only as a comment, never implemented.
A .armnn Splitter layer with numViews > output-slot count makes outputs[vIdx] (std::vector::operator[],
no bounds check) read past the heap vector buffer โ a garbage TensorInfo* that ToTensorInfo() then
dereferences. The flatbuffers::Verifier only checks structural integrity, not this cross-field invariant.
Reachable on the normal IDeserializer::CreateNetworkFromBinary load path. Distinct from the filed
dimensionSpecificity[5] stack overflow (different function and field).
Reproduce (AddressSanitizer)
g++ -fsanitize=address -g -O0 armnn_splitter_numviews_oob_harness.cpp -o poc && ./poc
# outputs.size()=2 (serialized output slots); numViews=4 (attacker, unchecked)
# loop reads outputs[vIdx] for vIdx in [0,4) -> OOB at vIdx>=2 ...
# ==ERROR: AddressSanitizer: heap-buffer-overflow READ of size 8 ... after the vector buffer
Fix
Implement the commented-out cross-check: reject the model when numViews != outputs.size() (and
numViews != flatBufferViewSizes->size()) before the loop.