YAML Metadata Warning:empty or missing yaml metadata in repo card
Check out the documentation for more information.
Arm NN DetectionPostProcess score/box count mismatch - CPU heap OOB read
Summary
This bundle demonstrates a heap out-of-bounds read in Arm NN's CPU Reference backend when loading and executing a serialized Arm NN FlatBuffers model containing a DetectionPostProcess layer.
The malicious model uses individually well-formed Float32 tensors:
| Tensor | Control shape | Malicious shape |
|---|---|---|
box_encodings |
[1, 2, 4] |
[1, 2, 4] |
scores |
[1, 2, 3] |
[1, 1, 3] |
| anchors | [2, 4] |
[2, 4] |
Both models use m_UseRegularNms=true and m_NumClasses=2. The malicious model changes only the score tensor's candidate count from two to one. The bundled .armnn files were generated with the supplied dpp_model_probe.cpp and Arm NN's own ISerializer at the pinned commit; their SHA-256 values bind verification to those exact files. The verifier uses those supplied files and does not regenerate them. They are not raw-byte mutations or truncated vectors.
Arm NN's DetectionPostProcessQueueDescriptor::Validate() checks tensor ranks, supported data types, and scores.shape[2] == m_NumClasses + 1, but does not require scores.shape[1] to equal box_encodings.shape[1] or the anchor count. During CPU inference, the Reference backend derives numBoxes from box_encodings.shape[1], creates a score vector sized from the smaller scores tensor, and then indexes it once for every box. AddressSanitizer reports a 4-byte heap out-of-bounds read at DetectionPostProcess.cpp:246.
Impact
An attacker who supplies a malicious serialized .armnn model can cause a native heap out-of-bounds read during ordinary CPU model inference. This PoC demonstrates the memory-safety violation only. It does not claim remote code execution, a heap write, arbitrary file read, or arbitrary file write.
Affected source
Tested against Arm NN commit 2b61cecc9df7a43fca1463795062cf359e6be820.
- Validation omission:
src/backends/backendsCommon/WorkloadData.cpp,DetectionPostProcessQueueDescriptor::Validate(). - Vulnerable CPU inference access:
src/backends/reference/workloads/DetectionPostProcess.cpp:246. - CPU call path:
RefDetectionPostProcessWorkload::Execute().
Direct commit-pinned links are in source_citations.md.
Files
control_detection_postprocess.armnn- clean control model.malicious_detection_postprocess.armnn- malicious model.dpp_model_probe.cpp- serializer-backed generator and CPU runtime harness.Dockerfile,verify_cpu_asan.sh,run_verification.ps1- reproducible Docker verification.logs/control_cpu_asan.logandlogs/malicious_cpu_asan.log- raw logs generated by the final verification.verify_report.json- hashes, conditions, and expected outcomes.
Reproduce on Windows with Docker Desktop
From this directory, run:
powershell -ExecutionPolicy Bypass -File .\run_verification.ps1
The script:
- Builds a temporary Docker image with only build dependencies.
- Fetches Arm NN commit
2b61cecc9df7a43fca1463795062cf359e6be820inside a disposable container. - Builds the CPU Reference backend and serializer with AddressSanitizer and UndefinedBehaviorSanitizer.
- Verifies the two supplied model hashes.
- Runs the control model first and requires
CPU_INFERENCE_OK. - Runs the malicious model second and requires an ASan
heap-buffer-overflowatDetectionPostProcess.cpp:246. - Removes the exact temporary container image after completion. The raw logs remain in
logs/.
No GPU is required.
Expected result
The control run exits successfully with:
DESERIALIZER_LOAD_OK /poc/control_detection_postprocess.armnn
CPU_LOAD_OK
CPU_INFERENCE_OK
The malicious run exits non-zero with an ASan report beginning with:
ERROR: AddressSanitizer: heap-buffer-overflow
READ of size 4
... DetectionPostProcess.cpp:246
Model hashes
3712694E8B05F576CF81657BAD19E5896BC7D849B9B05E947DE1A78F8D1C3E16 control_detection_postprocess.armnn
5BEDBF5C5C0FDB5A2168B5A1B3137C33248360A90A02CCADEE4CE0086927A9C2 malicious_detection_postprocess.armnn