Null Pointer Dereference Vulnerability in readNetFromTensorflow function

Jul 3, 2023

CVE Number

CVE-2023-31990

Credits

Huascar Tejeda of Pentraze Cybersecurity

Summary

A NULL pointer dereference vulnerability in the OpenCV function cv::dnn::dnn4_v20221220::RemoveIdentityOps. This vulnerability occurs when processing a malformed TensorFlow model, leading to a segmentation fault.

CVSS

9.0 (Critical) - CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:C/C:H/I:H/A:H

Details

The vulnerability is triggered when accessing the input of a layer in a malformed TensorFlow model, leading to a segmentation fault (SIGSEGV) at address 0x000000000008, which points to zero page. The crash occurs specifically in the RemoveIdentityOps function at tf_graph_simplifier.cpp:818, when the code attempts to access the layer.input(0), which internally uses the google::protobuf::RepeatedPtrField::Get method, resulting in an invalid read operation that causes the program to crash.

The RemoveIdentityOps function iterates through the layers and checks those of type Identity. If the input of the identity layer is not properly defined, a null pointer dereference occurs.

ASAN

==1426052==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000008 (pc 0x7ffff759d8cb bp 0x7fffffffaff0 sp 0x7fffffffabc0 T0)
==1426052==The signal is caused by a READ memory access.
==1426052==Hint: address points to the zero page.
    #0 0x7ffff759d8cb in cv::dnn::dnn4_v20221220::RemoveIdentityOps(opencv_tensorflow::GraphDef&) /home/htejeda/opencv-4.7.0/modules/dnn/src/tensorflow/tf_graph_simplifier.cpp
    #1 0x7ffff75c6e7a in cv::dnn::dnn4_v20221220::(anonymous namespace)::TFImporter::populateNet() /home/htejeda/opencv-4.7.0/modules/dnn/src/tensorflow/tf_importer.cpp:3036:9
    #2 0x7ffff76dcf16 in cv::dnn::dnn4_v20221220::(anonymous namespace)::TFImporter::TFImporter(cv::dnn::dnn4_v20221220::Net&, char const*, unsigned long, char const*, unsigned long) /home/htejeda/opencv-4.7.0/modules/dnn/src/tensorflow/tf_importer.cpp:2753:5
    #3 0x7ffff76dcf16 in cv::dnn::dnn4_v20221220::Net cv::dnn::dnn4_v20221220::detail::readNet<cv::dnn::dnn4_v20221220::(anonymous namespace)::TFImporter, char const*&, unsigned long&, char const*&, unsigned long&>(char const*&, unsigned long&, char const*&, unsigned long&) /home/htejeda/opencv-4.7.0/modules/dnn/src/tensorflow/../dnn_common.hpp:76:14
    #4 0x7ffff76db002 in cv::dnn::dnn4_v20221220::Net cv::dnn::dnn4_v20221220::detail::readNetDiagnostic<cv::dnn::dnn4_v20221220::(anonymous namespace)::TFImporter, char const*&, unsigned long&, char const*&, unsigned long&>(char const*&, unsigned long&, char const*&, unsigned long&) /home/htejeda/opencv-4.7.0/modules/dnn/src/tensorflow/../dnn_common.hpp:83:25
    #5 0x7ffff76db002 in cv::dnn::dnn4_v20221220::readNetFromTensorflow(char const*, unsigned long, char const*, unsigned long) /home/htejeda/opencv-4.7.0/modules/dnn/src/tensorflow/tf_importer.cpp:3248:12
    #6 0x306a13 in main /home/htejeda/opencv-4.7.0/build/fuzzer.cc:43:5
    #7 0x7fffe8c29d8f in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16
    #8 0x7fffe8c29e3f in __libc_start_main csu/../csu/libc-start.c:392:3
    #9 0x2543e4 in _start (/home/htejeda/opencv-4.7.0/build/fuzzer+0x2543e4)

AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV /home/htejeda/opencv-4.7.0/modules/dnn/src/tensorflow/tf_graph_simplifier.cpp in cv::dnn::dnn4_v20221220::RemoveIdentityOps(opencv_tensorflow::GraphDef&)
==1426052==ABORTING

GDB Backtrace

CRASH detected in cv::dnn::dnn4_v20221220::RemoveIdentityOps due to a fault at or near 0x0000000000000008 leading to SIGSEGV (si_signo=11) / SEGV_MAPERR (si_code=1)

Crashing thread backtrace:
#0  0x00007ffff79fdf26 in cv::dnn::dnn4_v20221220::RemoveIdentityOps (/home/htejeda/opencv-4.7.0/build/lib/libopencv_dnn.so.407)
                       803: void cv::dnn::dnn4_v20221220::RemoveIdentityOps(net = (opencv_tensorflow::GraphDef &)@0x7fffffffd890) {
                       |||:
                       |||: /* Local reference: cv::String type = <incomplete type>; */
                       |||: /* Local reference: std::vector<int, std::allocator<int> > identity_ops_idx = std::vector of length 1, capacity 1 = {4}; */
                       |||: /* Local reference: int li = 4; */
                       |||: /* Local reference: IdentityOpsMap identity_ops = std::map with 0 elements; */
                       |||: /* Local reference: const opencv_tensorflow::NodeDef & layer = @0x610000000840; */
                       816:         if (type == "Identity" || type == "Dropout" || type == "PlaceholderWithDefault") {
                       817:             identity_ops_idx.push_back(li);
                       818:             identity_ops[layer.name()] = layer.input(0);
                       |||:
                       ---: }
                       at /home/htejeda/opencv-4.7.0/modules/dnn/src/tensorflow/tf_graph_simplifier.cpp:818

#1  0x00007ffff7a14acf in cv::dnn::dnn4_v20221220::(anonymous namespace)::TFImporter::populateNet (/home/htejeda/opencv-4.7.0/build/lib/libopencv_dnn.so.407)
                       3000: void cv::dnn::dnn4_v20221220::(anonymous namespace)::TFImporter::populateNet(this = (cv::dnn::dnn4_v20221220::(anonymous namespace)::TFImporter *)0x7fffffffd840) {
                       ||||:
                       3034:         CV_LOG_DEBUG(NULL, "DNN/TF: removePhaseSwitches(model) => " << netBin.node_size() << " nodes");
                       3035:
                       3036:         RemoveIdentityOps(netBin);
                       ||||:
                       ----: }
                       at /home/htejeda/opencv-4.7.0/modules/dnn/src/tensorflow/tf_importer.cpp:3036

#2  0x00007ffff7a664a0 in cv::dnn::dnn4_v20221220::(anonymous namespace)::TFImporter::TFImporter (/home/htejeda/opencv-4.7.0/build/lib/libopencv_dnn.so.407)
                       ????: void cv::dnn::dnn4_v20221220::(anonymous namespace)::TFImporter::TFImporter(this = (cv::dnn::dnn4_v20221220::(anonymous namespace)::TFImporter *)0x7fffffffd840, net = (cv::dnn::dnn4_v20221220::Net &)@0x7fffffffdc48, dataModel = (const char *)0xe2e2c0 <__fuzz_alt> "\n\005\022\001R\b\037=%\b\001\022\262l\370'\n\n\"\nx\t\177\001\"\353\021\262p\v\b\200\377\377", lenModel = (size_t)<optimized out>, dataConfig = (const char *)0x0, lenConfig = (size_t)0) {
                       ||||:
                       ||||: /* Local reference: const char * dataConfig = 0x0; */
                       ||||: /* Local reference: size_t lenConfig = 0; */
                       2751:         ReadTFNetParamsFromTextBufferOrDie(dataConfig, lenConfig, &netTxt);
                       2752:     }
                       2753:     populateNet();
                       ||||:
                       ----: }
                       at /home/htejeda/opencv-4.7.0/modules/dnn/src/tensorflow/tf_importer.cpp:2753

#3  0x00007ffff7a664a0 in cv::dnn::dnn4_v20221220::detail::readNet<cv::dnn::dnn4_v20221220::(anonymous namespace)::TFImporter, char const*&, unsigned long&, char const*&, unsigned long&> (/home/htejeda/opencv-4.7.0/build/lib/libopencv_dnn.so.407)
                       73: cv::dnn::dnn4_v20221220::Net cv::dnn::dnn4_v20221220::detail::readNet<cv::dnn::dnn4_v20221220::(anonymous namespace)::TFImporter, char const*&, unsigned long&, char const*&, unsigned long&>(args = (const char *&)<optimized out>, args = (unsigned long &)<optimized out>, args = (const char *&)<optimized out>, args = (unsigned long &)<optimized out>) {
                       ||: /* Local reference: cv::dnn::dnn4_v20221220::(anonymous namespace)::TFImporter importer = {fp_denormals_ignore_scope = {saved_state = {reserved = {32832, 0, 5263472, 0, 4294958304, 32767, 4294958208, 32767, 4294958336, 3... */
                       ||: /* Local reference: unsigned long & args = <optimized out>; */
                       74: {
                       75:     Net net;
                       76:     Importer importer(net, std::forward<Args>(args)...);
                       ||:
                       --: }
                       at /home/htejeda/opencv-4.7.0/modules/dnn/src/tensorflow/../dnn_common.hpp:76

#4  0x00007ffff7a0eb5d in cv::dnn::dnn4_v20221220::detail::readNetDiagnostic<cv::dnn::dnn4_v20221220::(anonymous namespace)::TFImporter, char const*&, unsigned long&, char const*&, unsigned long&> (/home/htejeda/opencv-4.7.0/build/lib/libopencv_dnn.so.407)
                       ??: cv::dnn::dnn4_v20221220::Net cv::dnn::dnn4_v20221220::detail::readNetDiagnostic<cv::dnn::dnn4_v20221220::(anonymous namespace)::TFImporter, char const*&, unsigned long&, char const*&, unsigned long&>(args = (const char *&)@0x7fffffffdc40, args = (unsigned long &)@0x7fffffffdc38, args = (const char *&)@0x7fffffffdc30, args = (unsigned long &)@0x7fffffffdc28) {
                       ||:
                       ||: /* Local reference: unsigned long & args = @0x7fffffffdc28; */
                       ||: /* Local reference: cv::dnn::dnn4_v20221220::Net maybeDebugNet = {impl = {<std::shared_ptr<cv::dnn::dnn4_v20221220::Net::Impl>> = std::shared_ptr<cv::dnn::dnn4_v20221220::Net::Impl> (use count 1, weak count 0) = {get() =... */
                       81: Net readNetDiagnostic(Args&& ... args)
                       82: {
                       83:     Net maybeDebugNet = readNet<Importer>(std::forward<Args>(args)...);
                       ||:
                       --: }
                       at /home/htejeda/opencv-4.7.0/modules/dnn/src/tensorflow/../dnn_common.hpp:83

#5  0x00007ffff7a0eb5d in cv::dnn::dnn4_v20221220::readNetFromTensorflow (/home/htejeda/opencv-4.7.0/build/lib/libopencv_dnn.so.407)
                       3245: cv::dnn::dnn4_v20221220::Net cv::dnn::dnn4_v20221220::readNetFromTensorflow(bufferModel = (const char *)0xe2e2c0 <__fuzz_alt> "\n\005\022\001R\b\037=%\b\001\022\262l\370'\n\n\"\nx\t\177\001\"\353\021\262p\v\b\200\377\377", lenModel = (size_t)9712, bufferConfig = (const char *)0x0, lenConfig = (size_t)0) {
                       ||||: /* Local reference: const char * bufferConfig = 0x0; */
                       ||||: /* Local reference: size_t lenConfig = 0; */
                       ||||: /* Local reference: const char * bufferModel = 0xe2e2c0 <__fuzz_alt> "\n\005\022\001R\b\037=%\b\001\022\262l\370'\n\n\"\nx\t\177\001\"\353\021\262p\v\b\200\377\377"; */
                       ||||: /* Local reference: size_t lenModel = 9712; */
                       3246:                           const char* bufferConfig, size_t lenConfig)
                       3247: {
                       3248:     return detail::readNetDiagnostic<TFImporter>(bufferModel, lenModel, bufferConfig, lenConfig);
                       ||||:
                       ----: }
                       at /home/htejeda/opencv-4.7.0/modules/dnn/src/tensorflow/tf_importer.cpp:3248

#6  0x00000000004cf24c in main (/home/htejeda/opencv-4.7.0-asan/build/fuzzer)
                       30: int main(argc = (int)1, argv = (char **)0x7fffffffdfb8) {
                       ||:
                       ||: /* Local reference: unsigned char * data = 0xe2e2c0 <__fuzz_alt> "\n\005\022\001R\b\037=%\b\001\022\262l\370'\n\n\"\nx\t\177\001\"\353\021\262p\v\b\200\377\377"; */
                       ||: /* Local reference: size_t size = 9712; */
                       41:
                       42:               try {
                       43:                       readNetFromTensorflow((const char*)data, size);
                       ||:
                       --: }
                       at fuzzer.cc:43

Crash context:
/* Register reference: rbp - 0x0000602000005d50 (0x602000005d50) */
/* Register reference: rax - 0x0000000000000000 (0) */
Execution stopped here ==> 0x00007ffff79fdf26: mov    rbp,QWORD PTR [rax+0x8]

Register info:
   rax - 0x0000000000000000 (0)
   rbx - 0x0000000000000000 (0)
   rcx - 0x0000610000000840 (106652627896384)
   rdx - 0x0000000000000001 (1)
   rsi - 0x000060300001f3c0 (105759274824640)
   rdi - 0x0000602000005d50 (105690555243856)
   rbp - 0x0000602000005d50 (0x602000005d50)
   rsp - 0x00007fffffffd420 (0x7fffffffd420)
    r8 - 0x00007ffff6fa8000 (140737336999936)
    r9 - 0x0000000000000000 (0)
   r10 - 0x0000000000000002 (2)
   r11 - 0x0000000000000010 (16)
   r12 - 0x0000602000005d50 (105690555243856)
   r13 - 0x0000000000000001 (1)
   r14 - 0x0000000000000004 (4)
   r15 - 0x0000000000507ee0 (5275360)
   rip - 0x00007ffff79fdf26 (0x7ffff79fdf26 <cv::dnn::dnn4_v20221220::RemoveIdentityOps(opencv_tensorflow::GraphDef&)+1286>)
eflags - 0x00010202 ([ IF RF ])
    cs - 0x00000033 (51)
    ss - 0x0000002b (43)
    ds - 0x00000000 (0)
    es - 0x00000000 (0)
    fs - 0x00000000 (0)
    gs - 0x00000000 (0)

Services

Penetration Testing

Proactive assessment using tactics, techniques, and procedures of actual attackers to identify security flaws, incorrect configurations, and vulnerabilities.

Learn more

Application Security Testing

Comprehensive application protection, ensuring robust security throughout the entire software development lifecycle.

Learn more

Red Team Exercises

Simulate and emulate advanced cyber attacks to pinpoint vulnerabilities and test your organization's defense mechanisms, ensuring robust resilience against real-world threats.

Learn more

Vulnerability Management

Proactive process to identify, prioritize, and address security vulnerabilities in systems and software, enhancing an organization's defense against evolving cyber threats.

Learn more