YAML Metadata Warning:empty or missing yaml metadata in repo card
Check out the documentation for more information.
OpenCV TFLite importer out-of-bounds read in parseTensor
This repository contains a proof-of-concept malicious TFLite model that crashes OpenCV's
cv2.dnn.readNetFromTFLite with an out-of-bounds read at model-load time (SIGSEGV).
It is a security PoC for a huntr Model File Format report. The model is intentionally malformed and the repo is gated. Notably, the file is a structurally valid TFLite flatbuffer: it passes OpenCV's FlatBuffers verifier, because the verifier checks structure, not the consistency between a tensor's declared shape and its buffer length.
Affected
opencv-python/ OpenCVcv2.dnn, confirmed on 4.13.0 (latest at time of writing), on Linux.- The vulnerable code is unchanged on
master. - Entry point:
cv2.dnn.readNetFromTFLite(path).
Root cause
modules/dnn/src/tflite/tflite_importer.cpp, TFLiteImporter::parseTensor. The importer first runs
the FlatBuffers verifier (VerifyModelBuffer), then for each tensor reads its shape and wraps the
tensor's buffer in a cv::Mat without validating that the buffer byte size matches the declared
element count:
std::vector<int> shape(tensor.shape()->begin(), tensor.shape()->end());
const Buffer* buffer = model->buffers()->Get(tensor.buffer());
const void* data = buffer->data()->data();
...
Mat res = Mat(shape, dtype, const_cast<void*>(data)); // no shape-vs-buffer-size check
The verifier only validates flatbuffer structure (offsets/vectors are internally consistent), not
that a tensor's declared shape matches its buffer length. A constant tensor whose shape declares far
more elements than its buffer holds therefore passes verification, and when the tensor is consumed
during layer construction the Mat is read/copied over its declared (huge) element count, reading
off the end of the small buffer.
Proof of concept
poc.tflite is a valid one-Dense-layer model whose weight tensor shape is changed from [8, 4] to
[134217728, 4] while its buffer still holds only 32 floats. The change is a single int32 value
inside the shape vector, so the flatbuffer stays structurally valid and the verifier passes. Loading
the model makes the importer read ~134M*4 elements from the 32-float buffer.
pip install opencv-python # to reproduce (verify.py)
python verify.py # loads poc.tflite in a child process; reports the crash
# to regenerate poc.tflite from scratch you also need tensorflow:
pip install tensorflow && python make_poc.py
Observed on opencv-python 4.13.0 (Linux): the child process terminates with SIGSEGV (exit -11)
inside readNetFromTFLite, before any inference. On Windows it terminates with an access violation
(0xC0000005). A non-vulnerable build would load the model or reject it cleanly.
Impact
Any application that loads an untrusted or attacker-supplied .tflite through OpenCV is exposed.
Loading third-party TFLite models is a normal, documented use of this API, and the malicious file
passes the importer's own verifier, so a "verify before use" defense does not help. A ~1 KB file
reliably crashes the process via an out-of-bounds read in native code (a denial of service), and
because the over-read bytes are read into the tensor's Mat, the read can also disclose adjacent
process heap memory.
Fix
In parseTensor, after reading the shape and buffer, validate that
buffer->data()->size() == shape_product * elemSize (and reject the model otherwise) before
constructing the Mat.
Relation to the other OpenCV importer issues
This is a distinct vulnerability from the OpenCV Caffe importer (caffe_importer.cpp blobFromProto)
and ONNX importer (onnx_graph_simplifier.cpp getMatFromTensor) out-of-bounds issues: a different
importer, a different function (parseTensor in tflite_importer.cpp), and a different model format
(TFLite). It is also notable in that the malicious model passes the importer's FlatBuffers verifier.
- Downloads last month
- -