From 15fe69b5af177d7bcd089d4d4cad7d0851c7d7ca Mon Sep 17 00:00:00 2001 From: satyam yadav Date: Mon, 22 Dec 2025 13:52:12 +0530 Subject: [PATCH] Merge pull request #28250 from satyam102006:fix/stackblur-overflow-28233 imgproc: fix heap-buffer-overflow in stackBlur #28233 #28250 ### Summary Fixes a heap-buffer-overflow in `cv::stackBlur` when the kernel size is larger than the image dimensions ### Changes * Added input validation to clamp the kernel size to the image dimensions. * Added a regression test (`regression_28233`) covering 1x1 and small image cases. Fixes #28233 --- modules/imgproc/src/stackblur.cpp | 12 +++++++++--- modules/imgproc/test/test_stackblur.cpp | 13 +++++++++++++ modules/js/test/test_imgproc.js | 2 +- 3 files changed, 23 insertions(+), 4 deletions(-) diff --git a/modules/imgproc/src/stackblur.cpp b/modules/imgproc/src/stackblur.cpp index a69e4b4101..da34d3249d 100644 --- a/modules/imgproc/src/stackblur.cpp +++ b/modules/imgproc/src/stackblur.cpp @@ -41,6 +41,7 @@ OTHER DEALINGS IN THE SOFTWARE. #include "opencv2/core/hal/intrin.hpp" #include +#include using namespace std; @@ -1199,12 +1200,17 @@ void stackBlur(InputArray _src, OutputArray _dst, Size ksize) CV_Assert( ksize.width > 0 && ksize.width % 2 == 1 && ksize.height > 0 && ksize.height % 2 == 1 ); - int radiusH = ksize.height / 2; - int radiusW = ksize.width / 2; - int stype = _src.type(), sdepth = _src.depth(); Mat src = _src.getMat(); + if (ksize.width > src.cols) + ksize.width = (src.cols % 2 == 0) ? std::max(1, src.cols - 1) : src.cols; + if (ksize.height > src.rows) + ksize.height = (src.rows % 2 == 0) ? std::max(1, src.rows - 1) : src.rows; + + int radiusH = ksize.height / 2; + int radiusW = ksize.width / 2; + if (ksize.width == 1) { _src.copyTo(_dst); diff --git a/modules/imgproc/test/test_stackblur.cpp b/modules/imgproc/test/test_stackblur.cpp index b7525467b3..6c6dd42a67 100644 --- a/modules/imgproc/test/test_stackblur.cpp +++ b/modules/imgproc/test/test_stackblur.cpp @@ -311,5 +311,18 @@ TEST_P(StackBlur_GaussianBlur, compare) } INSTANTIATE_TEST_CASE_P(Imgproc, StackBlur_GaussianBlur, testing::Values(CV_8U, CV_16S, CV_16U, CV_32F)); + +TEST(Imgproc_StackBlur, regression_28233) +{ + Mat src1(1, 1, CV_8UC1, Scalar(123)); + Mat dst1; + EXPECT_NO_THROW(stackBlur(src1, dst1, Size(9, 1))); + EXPECT_EQ(dst1.at(0, 0), 123); + + Mat src2(3, 3, CV_8UC1, Scalar(50)); + Mat dst2; + EXPECT_NO_THROW(stackBlur(src2, dst2, Size(11, 11))); + EXPECT_EQ(dst2.at(1, 1), 50); +} } } diff --git a/modules/js/test/test_imgproc.js b/modules/js/test/test_imgproc.js index 786a7ba4d2..47228e712c 100644 --- a/modules/js/test/test_imgproc.js +++ b/modules/js/test/test_imgproc.js @@ -552,7 +552,7 @@ QUnit.test('test_filter', function(assert) { cv.stackBlur(src, src, new cv.Size(3, 3)); // Verify result. - let expected = new Uint8Array([22,29,36,38,43,50]); + let expected = new Uint8Array([14,22,29,46,51,58]); assert.deepEqual(src.data, expected); src.delete();