Skip to content

imwrite() with params which has odd elements may make out-of-boundary memory access . #22752

@Kumataro

Description

@Kumataro

System Information

OpenCV version: 4.x
Operating System / Platform: Ubuntu 22.10
Compiler & compiler version: GCC 12.2.0

Detailed description

This is a low priority issue due to a user implementation error.
However, as compilers and libraries improve, this problem will occur some compile/runtime errors.

What is problem.

The params for imwrite() is expected to store even number integer array .

https://docs.opencv.org/4.x/d4/da8/group__imgcodecs.html#gabbc7ef1aa2edfaa87772f1202d67e0ce

params Format-specific parameters encoded as pairs (paramId_1, paramValue_1, paramId_2, paramValue_2, ... .) see cv::ImwriteFlags

params = [ IMWRITE_JPEG_QUALITY, 100, IMWRITE_JPEG_xxxx, yyy ] ;

(All or almost) decoder believe this condition must be kept.

for( size_t i = 0; i < params.size(); i += 2 )
{
if( params[i] == IMWRITE_JPEG_QUALITY )
{
quality = params[i+1];
quality = MIN(MAX(quality, 0), 100);
}
if( params[i] == IMWRITE_JPEG_PROGRESSIVE )
{
progressive = params[i+1];
}

However, if user-application breaks this condition, those codecs makes out-of-boundary memory access.

For example, params has only 1 ID which is interesting by codec..

params = [ IMWRITE_JPEG_QUALITY };

step 1. i = 0
step 2. if ( i < params.size() ) -> true.
step 3. if( params[i] == IMWRITE_JPEG_QUALITY ) -> true 
step 4. quality = params[i+1];   // out-of-boundary

error log

[ RUN      ] Imgcodecs.write_parameter_length
==103191== Invalid read of size 4
==103191==    at 0x48A6D80: cv::JpegEncoder::write(cv::Mat const&, std::vector<int, std::allocator<int> > const&) (grfmt_jpeg.cpp:647)
==103191==    by 0x487ED7A: cv::imwrite_(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::vector<cv::Mat, std::allocator<cv::Mat> > const&, std::vector<int, std::allocator<int> > const&, bool) (loadsave.cpp:xxx)
==103191==    by 0x487F48F: cv::imwrite(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, cv::_InputArray const&, std::vector<int, std::allocator<int> > const&) (loadsave.cpp:xxx)

(sorry, loadsave.cpp is modified to investigate. so line number is invalid.)

How to fix

I think it is better to check in imwrite_() and imencode() at loadsave.cpp. And imencode() shoule be add CV_Assert(params.size() <= CV_IO_MAX_IMAGE_PARAMS*2);,

}
encoder->setDestination( filename );
CV_Assert(params.size() <= CV_IO_MAX_IMAGE_PARAMS*2);
bool code = false;
try

bool imencode( const String& ext, InputArray _image,
std::vector<uchar>& buf, const std::vector<int>& params )
{
CV_TRACE_FUNCTION();
Mat image = _image.getMat();
CV_Assert(!image.empty());
int channels = image.channels();
CV_Assert( channels == 1 || channels == 3 || channels == 4 );
ImageEncoder encoder = findEncoder( ext );
if( !encoder )
CV_Error( Error::StsError, "could not find encoder for the specified extension" );
if( !encoder->isFormatSupported(image.depth()) )
{
CV_Assert( encoder->isFormatSupported(CV_8U) );
Mat temp;
image.convertTo(temp, CV_8U);
image = temp;
}
bool code;
if( encoder->setDestination(buf) )
{
code = encoder->write(image, params);

I feels that it is not bad idea to add CV_Assert( (params.count() % 2) == 0 ) .

Steps to reproduce

sample code

/**
 * $ g++ main.cpp -o a,out -I /usr/local/include/opencv4 -lopencv_core -lopencv_imgcodecs
 * $ valgrind ./a.out
 */
#include <opencv2/core.hpp>
#include <opencv2/imgcodecs.hpp>

#include <string>
#include <vector>

using namespace std;
using namespace cv;
int main(void)
{
    const Mat img( 16, 16, CV_8UC3, cv::Scalar::all(0) );
    vector<int> params;
    params.push_back(IMWRITE_JPEG_QUALITY);
//  params.push_back(100)); // Forget it.
    cv::imwrite("test.jpg", img, params);
}

Issue submission checklist

  • I report the issue, it's not a question
  • I checked the problem with documentation, FAQ, open issues, forum.opencv.org, Stack Overflow, etc and have not found any solution
  • I updated to the latest OpenCV version and the issue is still there
  • There is reproducer code and related data files (videos, images, onnx, etc)

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions