-
-
Notifications
You must be signed in to change notification settings - Fork 56.5k
readNetFromTensorflow: BufferOverflow #21852
Copy link
Copy link
Closed
Description
System information (version)
- OpenCV => commit: b2e20a8
- Operating System / Platform => ubuntu 18.04
- Compiler => clang++ 10.0.1
Detailed description
Steps to reproduce
##### Issue submission checklist
- [X] I report the issue, it's not a question
<!--
OpenCV team works with forum.opencv.org, Stack Overflow and other communities
to discuss problems. Tickets with questions without a real issue statement will be
closed.
-->
- [ X] I checked the problem with documentation, FAQ, open issues,
forum.opencv.org, Stack Overflow, etc and have not found any solution
<!--
Places to check:
* OpenCV documentation: https://docs.opencv.org
* FAQ page: https://github.com/opencv/opencv/wiki/FAQ
* OpenCV forum: https://forum.opencv.org
* OpenCV issue tracker: https://github.com/opencv/opencv/issues?q=is%3Aissue
* Stack Overflow branch: https://stackoverflow.com/questions/tagged/opencv
-->
- [X ] I updated to the latest OpenCV version and the issue is still there
<!--
master branch for OpenCV 4.x and 3.4 branch for OpenCV 3.x releases.
OpenCV team supports only the latest release for each branch.
The ticket is closed if the problem is not reproduced with the modern version.
-->
- [X ] There is reproducer code and related data files: videos, images, onnx, etc
<!--
The best reproducer -- test case for OpenCV that we can add to the library.
Recommendations for media files and binary files:
* Try to reproduce the issue with images and videos in opencv_extra repository
to reduce attachment size
* Use PNG for images, if you report some CV related bug, but not image reader
issue
* Attach the image as an archive to the ticket, if you report some reader issue.
Image hosting services compress images and it breaks the repro code.
* Provide ONNX file for some public model or ONNX file with random weights,
if you report ONNX parsing or handling issue. Architecture details diagram
from netron tool can be very useful too. See https://lutzroeder.github.io/netron/
-->
Reproduce code
#include "opencv2/dnn.hpp"
using namespace cv;
using namespace dnn;
std::string Input1 { 0x08, 0x08, 0x0a, 0x00, 0x0a, 0x00 };
std::string Input1Path = "Input1";
void assign_file(const char *Path, const char *Data, unsigned Size) {
if (!Path)
return;
FILE *FP = fopen(Path, "wb");
if (!FP)
return;
fwrite(Data, Size, 1, FP);
fclose(FP);
}
int main(int argc, char* argv[]) {
assign_file(Input1Path.c_str(), Input1.c_str(), Input1.size());
Net net;
net = readNetFromTensorflow(Input1Path);
return 0;
}
Build steps to opencv
mkdir -p build && cd build
cmake -DBUILD_SHARED_LIBS=OFF -DOPENCV_ENABLE_ALLOCATOR_STATS=OFF -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_AR=/bin/llvm-ar -DCMAKE_C_FLAGS="-fsanitize=address,fuzzer-no-link -fno-omit-frame-pointer -g" -DCMAKE_CXX_FLAGS="-fsanitize=address,fuzzer-no-link -fno-omit-frame-pointer -g" -DCMAKE_EXE_LINKER_FLAGS="-fsanitize=address,fuzzer-no-link -fno-omit-frame-pointer -g" -DCMAKE_SHARED_LINKER_FLAGS="-fsanitize=address,fuzzer-no-link -fno-omit-frame-pointer -g" ..
make -j16
Reason
tf_graph_simplifier.cpp : sortByExecutionOrder(tensorflow::GraphDef& net)
// Line 985~991
std::map<std::string, int> nodesMap;
std::map<std::string, int>::iterator nodesMapIt;
for (int i = 0; i < net.node_size(); ++i) //net.node_size() is 3.
{
const tensorflow::NodeDef& node = net.node(i);
nodesMap.insert(std::make_pair(node.name(), i)); //net.node(0~2).name() is same(empty), thus nodesMap.size() is 1.
}
// Line 994~1015
std::vector<std::vector<int> > edges(nodesMap.size()); //edges.size() is 1, since nodesMap.size() is 1.
std::vector<int> numRefsToAdd(nodesMap.size(), 0);
std::vector<int> nodesToAdd;
for (int i = 0; i < net.node_size(); ++i) //net.node_size() is 3
{
const tensorflow::NodeDef& node = net.node(i);
int numInputsInGraph = 0;
for (int j = 0; j < node.input_size(); ++j)
{
std::string inpName = node.input(j);
inpName = inpName.substr(0, inpName.rfind(':'));
inpName = inpName.substr(inpName.find('^') + 1);
nodesMapIt = nodesMap.find(inpName);
if (nodesMapIt != nodesMap.end())
{
edges[nodesMapIt->second].push_back(i);
numInputsInGraph += 1;
}
}
if (numInputsInGraph == 0)
nodesToAdd.push_back(i); // {0, 1, 2} is inserted to nodesToAdd. nodesToAdd.size() is 3.
// Line 1032~1051
while (!nodesToAdd.empty()) // nodesToAdd is { 0, 1, 2 }.
{
int nodeToAdd = nodesToAdd.back(); // nodeToAdd is 2, 1, 0, in each loop.
nodesToAdd.pop_back();
permIds.push_back(nodeToAdd);
for (int i = 0; i < edges[nodeToAdd].size(); ++i) //edges.size() = 1 thus, when nodeToAdd is 1 or 2, buffer overflow happens.
{
int consumerId = edges[nodeToAdd][i];
if (numRefsToAdd[consumerId] > 0)
{
if (numRefsToAdd[consumerId] == 1)
nodesToAdd.push_back(consumerId);
else
CV_Assert(numRefsToAdd[consumerId] >= 0);
numRefsToAdd[consumerId] -= 1;
}
}
}
Address Sanitizer Report
==6716==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x60300001cf50 at pc 0x0000007623b6 bp 0x7ffdf23c8990 sp 0x7ffdf23c8988
READ of size 8 at 0x60300001cf50 thread T0
#0 0x7623b5 in std::vector<int, std::allocator<int> >::size() const /usr/lib/gcc/x86_64-linux-gnu/7.5.0/../../../../include/c++/7.5.0/bits/stl_vector.h:671:40
#1 0x7623b5 in cv::dnn::dnn4_v20211220::sortByExecutionOrder(opencv_tensorflow::GraphDef&) /root/fuzz-test-generation/exp/opencv/modules/dnn/src/tensorflow/tf_graph_simplifier.cpp:1039:46
#2 0x5f06b9 in cv::dnn::dnn4_v20211220::(anonymous namespace)::TFImporter::populateNet() /root/fuzz-test-generation/exp/opencv/modules/dnn/src/tensorflow/tf_importer.cpp:3018:9
#3 0x5e5e13 in cv::dnn::dnn4_v20211220::(anonymous namespace)::TFImporter::TFImporter(cv::dnn::dnn4_v20211220::Net&, char const*, char const*) /root/fuzz-test-generation/exp/opencv/modules/dnn/src/tensorflow/tf_importer.cpp:2709:5
#4 0x5e5e13 in cv::dnn::dnn4_v20211220::Net cv::dnn::dnn4_v20211220::detail::readNet<cv::dnn::dnn4_v20211220::(anonymous namespace)::TFImporter, char const*, char const*>(char const*&&, char const*&&) /root/fuzz-test-generation/exp/opencv/modules/dnn/src/tensorflow/../dnn_common.hpp:75:14
#5 0x5e2203 in cv::dnn::dnn4_v20211220::Net cv::dnn::dnn4_v20211220::detail::readNetDiagnostic<cv::dnn::dnn4_v20211220::(anonymous namespace)::TFImporter, char const*, char const*>(char const*&&, char const*&&) /root/fuzz-test-generation/exp/opencv/modules/dnn/src/tensorflow/../dnn_common.hpp:82:25
#6 0x5e2203 in cv::dnn::dnn4_v20211220::readNetFromTensorflow(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) /root/fuzz-test-generation/exp/opencv/modules/dnn/src/tensorflow/tf_importer.cpp:3219:12
#7 0x4d87d8 in main (/root/fuzz-test-generation/exp/opencv/fuzzer/imread/crash_2/crash+0x4d87d8)
#8 0x7f29bef0dbf6 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21bf6)
#9 0x42ddf9 in _start (/root/fuzz-test-generation/exp/opencv/fuzzer/imread/crash_2/crash+0x42ddf9)
0x60300001cf50 is located 8 bytes to the right of 24-byte region [0x60300001cf30,0x60300001cf48)
allocated by thread T0 here:
#0 0x4d5cad in operator new(unsigned long) (/root/fuzz-test-generation/exp/opencv/fuzzer/imread/crash_2/crash+0x4d5cad)
#1 0x75e978 in __gnu_cxx::new_allocator<std::vector<int, std::allocator<int> > >::allocate(unsigned long, void const*) /usr/lib/gcc/x86_64-linux-gnu/7.5.0/../../../../include/c++/7.5.0/ext/new_allocator.h:111:27
#2 0x75e978 in std::allocator_traits<std::allocator<std::vector<int, std::allocator<int> > > >::allocate(std::allocator<std::vector<int, std::allocator<int> > >&, unsigned long) /usr/lib/gcc/x86_64-linux-gnu/7.5.0/../../../../include/c++/7.5.0/bits/alloc_traits.h:436:20
#3 0x75e978 in std::_Vector_base<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >::_M_allocate(unsigned long) /usr/lib/gcc/x86_64-linux-gnu/7.5.0/../../../../include/c++/7.5.0/bits/stl_vector.h:172:20
#4 0x75e978 in std::_Vector_base<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >::_M_create_storage(unsigned long) /usr/lib/gcc/x86_64-linux-gnu/7.5.0/../../../../include/c++/7.5.0/bits/stl_vector.h:187:33
#5 0x75e978 in std::_Vector_base<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >::_Vector_base(unsigned long, std::allocator<std::vector<int, std::allocator<int> > > const&) /usr/lib/gcc/x86_64-linux-gnu/7.5.0/../../../../include/c++/7.5.0/bits/stl_vector.h:138:9
#6 0x75e978 in std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >::vector(unsigned long, std::allocator<std::vector<int, std::allocator<int> > > const&) /usr/lib/gcc/x86_64-linux-gnu/7.5.0/../../../../include/c++/7.5.0/bits/stl_vector.h:284:9
#7 0x75e978 in cv::dnn::dnn4_v20211220::sortByExecutionOrder(opencv_tensorflow::GraphDef&) /root/fuzz-test-generation/exp/opencv/modules/dnn/src/tensorflow/tf_graph_simplifier.cpp:994:36
#8 0x5f06b9 in cv::dnn::dnn4_v20211220::(anonymous namespace)::TFImporter::populateNet() /root/fuzz-test-generation/exp/opencv/modules/dnn/src/tensorflow/tf_importer.cpp:3018:9
#9 0x5e5e13 in cv::dnn::dnn4_v20211220::(anonymous namespace)::TFImporter::TFImporter(cv::dnn::dnn4_v20211220::Net&, char const*, char const*) /root/fuzz-test-generation/exp/opencv/modules/dnn/src/tensorflow/tf_importer.cpp:2709:5
#10 0x5e5e13 in cv::dnn::dnn4_v20211220::Net cv::dnn::dnn4_v20211220::detail::readNet<cv::dnn::dnn4_v20211220::(anonymous namespace)::TFImporter, char const*, char const*>(char const*&&, char const*&&) /root/fuzz-test-generation/exp/opencv/modules/dnn/src/tensorflow/../dnn_common.hpp:75:14
#11 0x5e2203 in cv::dnn::dnn4_v20211220::Net cv::dnn::dnn4_v20211220::detail::readNetDiagnostic<cv::dnn::dnn4_v20211220::(anonymous namespace)::TFImporter, char const*, char const*>(char const*&&, char const*&&) /root/fuzz-test-generation/exp/opencv/modules/dnn/src/tensorflow/../dnn_common.hpp:82:25
#12 0x5e2203 in cv::dnn::dnn4_v20211220::readNetFromTensorflow(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) /root/fuzz-test-generation/exp/opencv/modules/dnn/src/tensorflow/tf_importer.cpp:3219:12
#13 0x4d87d8 in main (/root/fuzz-test-generation/exp/opencv/fuzzer/imread/crash_2/crash+0x4d87d8)
#14 0x7f29bef0dbf6 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21bf6)
SUMMARY: AddressSanitizer: heap-buffer-overflow /usr/lib/gcc/x86_64-linux-gnu/7.5.0/../../../../include/c++/7.5.0/bits/stl_vector.h:671:40 in std::vector<int, std::allocator<int> >::size() const
Shadow bytes around the buggy address:
0x0c067fffb990: fa fa fd fd fd fd fa fa fd fd fd fd fa fa fd fd
0x0c067fffb9a0: fd fd fa fa fd fd fd fd fa fa fd fd fd fd fa fa
0x0c067fffb9b0: fd fd fd fd fa fa fd fd fd fd fa fa fd fd fd fd
0x0c067fffb9c0: fa fa fd fd fd fd fa fa fd fd fd fd fa fa fd fd
0x0c067fffb9d0: fd fd fa fa fd fd fd fd fa fa fd fd fd fd fa fa
=>0x0c067fffb9e0: fd fd fd fd fa fa 00 00 00 fa[fa]fa fa fa fa fa
0x0c067fffb9f0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c067fffba00: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c067fffba10: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c067fffba20: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c067fffba30: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
Shadow gap: cc
==6716==ABORTING
Effect
This bug may cause security vulnerability by reading invalid memory address.
Reactions are currently unavailable