PoC β€” Arm NN .armnn stack buffer overflow (saved return addresses overwritten)

Proof-of-concept for a huntr Model File Vulnerabilities (MFV) report against ARM-software/armnn, src/armnnDeserializer/Deserializer.cpp β†’ ToTensorInfo().

These files are inert data. They contain no shellcode and execute nothing; they simply carry a dimensionSpecificity vector longer than the destination array.

The issue

ToTensorInfo() reassigns its loop bound from a file-controlled vector length and writes that many entries into a fixed 5-element stack array β€” the bound is only checked afterwards, inside the TensorShape constructor.

746: bool dimensionsSpecificity[armnn::MaxNumOfTensorDimensions];   // 5 bools, on the stack
753:     size = dimensionSpecificity->size();      // from the file, NO clamp
756:     dimensionsSpecificity[i] = dimensionSpecificity->Get(i);   // OOB stack write
760: TensorShape shape(size, outputDims.data(), dimensionsSpecificity);  // validation only here

MaxNumOfTensorDimensions = 5 (include/armnn/Types.hpp:31).

The trigger file is valid against Arm's own schema β€” ArmnnSchema.fbs:83 declares dimensionSpecificity:[bool]; with no length limit. This is not a corrupted file.

Files

File Purpose
poc_benign_len4.armnn control β€” 4 entries, within bounds, parses normally
poc_abort_len210.armnn 210 entries β€” overflows the 5-byte stack array
poc_ctrl_0x41_len512.armnn 512 entries of 0x41 β€” used for the negative control below
gen_poc.py generator
RESULTS-table.txt full matrix of tested lengths and outcomes

Observed impact (release build, gdb)

#3  armnn::TensorShape::CheckValidNumDimensions(unsigned int) ()
#4  armnn::TensorShape::TensorShape(unsigned int, unsigned int const*, bool const*) ()
#5  armnnDeserializer::ToTensorInfo(armnnSerializer::TensorInfo const*) ()
#6  0x0101010101010101 in ?? ()      <-- saved return address, overwritten
#7  0x0101010101010101 in ?? ()

The SIGSEGV is not the out-of-bounds access itself: line 756 smashes the stack, line 760 then throws, and the C++ unwinder walks a call stack whose return addresses are already destroyed.

Negative control β€” stated deliberately

Attacker control over the written values is limited to {0x00, 0x01}, because flatbuffers::Vector<bool>::Get() normalises them. Verified with three payloads β€” implicit true, 0x41-filled, and 0xDEADBEEF-filled β€” all yielding 0x0101010101010101.

No arbitrary-byte control and no RCE is claimed. What is demonstrated is a stack overflow of attacker-chosen length that destroys saved return addresses.

Suggested fix

size = std::min<unsigned int>(dimensionSpecificity->size(), armnn::MaxNumOfTensorDimensions);

Attribution

Cyfra Tech Solutions (Roman Arce Bran), Costa Rica.

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