From 321c74ccd6077bdea1d47450ca4fe955cb5b6330 Mon Sep 17 00:00:00 2001
From: Alexander Alekhin <alexander.alekhin@intel.com>
Date: Thu, 25 Jul 2019 17:15:59 +0300
Subject: [PATCH] objdetect: validate feature rectangle on reading

---
 modules/objdetect/src/cascadedetect.cpp | 43 +++++++++++++++++++++----
 modules/objdetect/src/cascadedetect.hpp |  6 ++--
 2 files changed, 40 insertions(+), 9 deletions(-)

diff --git a/modules/objdetect/src/cascadedetect.cpp b/modules/objdetect/src/cascadedetect.cpp
index 4b2078306..bd62cd21a 100644
--- a/modules/objdetect/src/cascadedetect.cpp
+++ b/modules/objdetect/src/cascadedetect.cpp
@@ -47,6 +47,10 @@
 #include "opencv2/objdetect/objdetect_c.h"
 #include "opencl_kernels_objdetect.hpp"
 
+#if defined(_MSC_VER)
+#  pragma warning(disable:4458)  // declaration of 'origWinSize' hides class member
+#endif
+
 namespace cv
 {
 
@@ -537,7 +541,7 @@ bool FeatureEvaluator::setImage( InputArray _image, const std::vector<float>& _s
 
 //----------------------------------------------  HaarEvaluator ---------------------------------------
 
-bool HaarEvaluator::Feature :: read( const FileNode& node )
+bool HaarEvaluator::Feature::read(const FileNode& node, const Size& origWinSize)
 {
     FileNode rnode = node[CC_RECTS];
     FileNodeIterator it = rnode.begin(), it_end = rnode.end();
@@ -549,11 +553,23 @@ bool HaarEvaluator::Feature :: read( const FileNode& node )
         rect[ri].weight = 0.f;
     }
 
+    const int W = origWinSize.width;
+    const int H = origWinSize.height;
+
     for(ri = 0; it != it_end; ++it, ri++)
     {
         FileNodeIterator it2 = (*it).begin();
-        it2 >> rect[ri].r.x >> rect[ri].r.y >>
-            rect[ri].r.width >> rect[ri].r.height >> rect[ri].weight;
+        Feature::RectWeigth& rw = rect[ri];
+        it2 >> rw.r.x >> rw.r.y >> rw.r.width >> rw.r.height >> rw.weight;
+        // input validation
+        {
+            CV_CheckGE(rw.r.x, 0, "Invalid HAAR feature");
+            CV_CheckGE(rw.r.y, 0, "Invalid HAAR feature");
+            CV_CheckLT(rw.r.x, W, "Invalid HAAR feature");  // necessary for overflow checks
+            CV_CheckLT(rw.r.y, H, "Invalid HAAR feature");  // necessary for overflow checks
+            CV_CheckLE(rw.r.x + rw.r.width, W, "Invalid HAAR feature");
+            CV_CheckLE(rw.r.y + rw.r.height, H, "Invalid HAAR feature");
+        }
     }
 
     tilted = (int)node[CC_TILTED] != 0;
@@ -598,7 +614,7 @@ bool HaarEvaluator::read(const FileNode& node, Size _origWinSize)
 
     for(i = 0; i < n; i++, ++it)
     {
-        if(!ff[i].read(*it))
+        if(!ff[i].read(*it, _origWinSize))
             return false;
         if( ff[i].tilted )
             hasTiltedFeatures = true;
@@ -759,11 +775,24 @@ int HaarEvaluator::getSquaresOffset() const
 }
 
 //----------------------------------------------  LBPEvaluator -------------------------------------
-bool LBPEvaluator::Feature :: read(const FileNode& node )
+bool LBPEvaluator::Feature::read(const FileNode& node, const Size& origWinSize)
 {
     FileNode rnode = node[CC_RECT];
     FileNodeIterator it = rnode.begin();
     it >> rect.x >> rect.y >> rect.width >> rect.height;
+
+    const int W = origWinSize.width;
+    const int H = origWinSize.height;
+    // input validation
+    {
+        CV_CheckGE(rect.x, 0, "Invalid LBP feature");
+        CV_CheckGE(rect.y, 0, "Invalid LBP feature");
+        CV_CheckLT(rect.x, W, "Invalid LBP feature");
+        CV_CheckLT(rect.y, H, "Invalid LBP feature");
+        CV_CheckLE(rect.x + rect.width, W, "Invalid LBP feature");
+        CV_CheckLE(rect.y + rect.height, H, "Invalid LBP feature");
+    }
+
     return true;
 }
 
@@ -797,7 +826,7 @@ bool LBPEvaluator::read( const FileNode& node, Size _origWinSize )
     std::vector<Feature>& ff = *features;
     for(int i = 0; it != it_end; ++it, i++)
     {
-        if(!ff[i].read(*it))
+        if(!ff[i].read(*it, _origWinSize))
             return false;
     }
     nchannels = 1;
@@ -1477,6 +1506,8 @@ bool CascadeClassifierImpl::Data::read(const FileNode &root)
     origWinSize.width = (int)root[CC_WIDTH];
     origWinSize.height = (int)root[CC_HEIGHT];
     CV_Assert( origWinSize.height > 0 && origWinSize.width > 0 );
+    CV_CheckLE(origWinSize.width, 1000000, "Invalid window size (too large)");
+    CV_CheckLE(origWinSize.height, 1000000, "Invalid window size (too large)");
 
     // load feature params
     FileNode fn = root[CC_FEATURE_PARAMS];
diff --git a/modules/objdetect/src/cascadedetect.hpp b/modules/objdetect/src/cascadedetect.hpp
index f9910530b..d9a288fcd 100644
--- a/modules/objdetect/src/cascadedetect.hpp
+++ b/modules/objdetect/src/cascadedetect.hpp
@@ -317,12 +317,12 @@ public:
     struct Feature
     {
         Feature();
-        bool read( const FileNode& node );
+        bool read(const FileNode& node, const Size& origWinSize);
 
         bool tilted;
 
         enum { RECT_NUM = 3 };
-        struct
+        struct RectWeigth
         {
             Rect r;
             float weight;
@@ -412,7 +412,7 @@ public:
         Feature( int x, int y, int _block_w, int _block_h  ) :
                  rect(x, y, _block_w, _block_h) {}
 
-        bool read(const FileNode& node );
+        bool read(const FileNode& node, const Size& origWinSize);
 
         Rect rect; // weight and height for block
     };
-- 
2.23.0

