blob: 39f33af9de5cb395b04c77618e84a4c0e5dadf91 [file] [log] [blame]
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001Upstream-Status: Backport [https://github.com/opencv/opencv/pull/9376/commits/999f41fb4f4aa94a0cb47256919ae8b5c29ca5f3]
2
3Fix CVEs for opencv 3.3:
4
5* CVE-2017-12597
6* CVE-2017-12598
7* CVE-2017-12599
8* CVE-2017-12600
9* CVE-2017-12601
10* CVE-2017-12602
11* CVE-2017-12603
12* CVE-2017-12604
13* CVE-2017-12605
14* CVE-2017-12606
15* CVE-2017-12862
16* CVE-2017-12863
17* CVE-2017-12864
18
19Signed-off-by: Kai Kang <kai.kang@windriver.com>
20---
21From 999f41fb4f4aa94a0cb47256919ae8b5c29ca5f3 Mon Sep 17 00:00:00 2001
22From: Alexander Alekhin <alexander.a.alekhin@gmail.com>
23Date: Tue, 15 Aug 2017 22:04:55 +0000
24Subject: [PATCH 2/3] imgcodecs: refactoring, improve code quality
25
26---
27 modules/imgcodecs/src/bitstrm.cpp | 2 +
28 modules/imgcodecs/src/bitstrm.hpp | 19 +++--
29 modules/imgcodecs/src/grfmt_bmp.cpp | 13 ++-
30 modules/imgcodecs/src/grfmt_pxm.cpp | 122 ++++++++++++++++-----------
31 modules/imgcodecs/src/loadsave.cpp | 164 +++++++++++++++++++++++++++++-------
32 5 files changed, 231 insertions(+), 89 deletions(-)
33
34diff --git a/modules/imgcodecs/src/bitstrm.cpp b/modules/imgcodecs/src/bitstrm.cpp
35index a7e187fa0..0a8941aec 100644
36--- a/modules/imgcodecs/src/bitstrm.cpp
37+++ b/modules/imgcodecs/src/bitstrm.cpp
38@@ -209,6 +209,8 @@ int RLByteStream::getByte()
39 current = m_current;
40 }
41
42+ CV_Assert(current < m_end);
43+
44 val = *((uchar*)current);
45 m_current = current + 1;
46 return val;
47diff --git a/modules/imgcodecs/src/bitstrm.hpp b/modules/imgcodecs/src/bitstrm.hpp
48index 465c0a847..26947971f 100644
49--- a/modules/imgcodecs/src/bitstrm.hpp
50+++ b/modules/imgcodecs/src/bitstrm.hpp
51@@ -48,13 +48,20 @@
52 namespace cv
53 {
54
55-enum
56-{
57- RBS_THROW_EOS=-123, // <end of stream> exception code
58- RBS_THROW_FORB=-124, // <forrbidden huffman code> exception code
59- RBS_HUFF_FORB=2047, // forrbidden huffman code "value"
60- RBS_BAD_HEADER=-125 // invalid header
61+#define DECLARE_RBS_EXCEPTION(name) \
62+class RBS_ ## name ## _Exception : public cv::Exception \
63+{ \
64+public: \
65+ RBS_ ## name ## _Exception(int code_, const String& err_, const String& func_, const String& file_, int line_) : \
66+ cv::Exception(code_, err_, func_, file_, line_) \
67+ {} \
68 };
69+DECLARE_RBS_EXCEPTION(THROW_EOS)
70+#define RBS_THROW_EOS RBS_THROW_EOS_Exception(cv::Error::StsError, "Unexpected end of input stream", CV_Func, __FILE__, __LINE__)
71+DECLARE_RBS_EXCEPTION(THROW_FORB)
72+#define RBS_THROW_FORB RBS_THROW_FORB_Exception(cv::Error::StsError, "Forrbidden huffman code", CV_Func, __FILE__, __LINE__)
73+DECLARE_RBS_EXCEPTION(BAD_HEADER)
74+#define RBS_BAD_HEADER RBS_BAD_HEADER_Exception(cv::Error::StsError, "Invalid header", CV_Func, __FILE__, __LINE__)
75
76 typedef unsigned long ulong;
77
78diff --git a/modules/imgcodecs/src/grfmt_bmp.cpp b/modules/imgcodecs/src/grfmt_bmp.cpp
79index 86cacd316..257f97c2d 100644
80--- a/modules/imgcodecs/src/grfmt_bmp.cpp
81+++ b/modules/imgcodecs/src/grfmt_bmp.cpp
82@@ -118,8 +118,9 @@ bool BmpDecoder::readHeader()
83
84 if( m_bpp <= 8 )
85 {
86- memset( m_palette, 0, sizeof(m_palette));
87- m_strm.getBytes( m_palette, (clrused == 0? 1<<m_bpp : clrused)*4 );
88+ CV_Assert(clrused < 256);
89+ memset(m_palette, 0, sizeof(m_palette));
90+ m_strm.getBytes(m_palette, (clrused == 0? 1<<m_bpp : clrused)*4 );
91 iscolor = IsColorPalette( m_palette, m_bpp );
92 }
93 else if( m_bpp == 16 && m_rle_code == BMP_BITFIELDS )
94@@ -290,7 +291,9 @@ bool BmpDecoder::readData( Mat& img )
95 else if( code > 2 ) // absolute mode
96 {
97 if( data + code*nch > line_end ) goto decode_rle4_bad;
98- m_strm.getBytes( src, (((code + 1)>>1) + 1) & -2 );
99+ int sz = (((code + 1)>>1) + 1) & (~1);
100+ CV_Assert((size_t)sz < _src.size());
101+ m_strm.getBytes(src, sz);
102 if( color )
103 data = FillColorRow4( data, src, code, m_palette );
104 else
105@@ -379,7 +382,9 @@ decode_rle4_bad: ;
106
107 if( data + code3 > line_end )
108 goto decode_rle8_bad;
109- m_strm.getBytes( src, (code + 1) & -2 );
110+ int sz = (code + 1) & (~1);
111+ CV_Assert((size_t)sz < _src.size());
112+ m_strm.getBytes(src, sz);
113 if( color )
114 data = FillColorRow8( data, src, code, m_palette );
115 else
116diff --git a/modules/imgcodecs/src/grfmt_pxm.cpp b/modules/imgcodecs/src/grfmt_pxm.cpp
117index 1750cb705..68bd8fd93 100644
118--- a/modules/imgcodecs/src/grfmt_pxm.cpp
119+++ b/modules/imgcodecs/src/grfmt_pxm.cpp
120@@ -43,50 +43,58 @@
121 #include "precomp.hpp"
122 #include "utils.hpp"
123 #include "grfmt_pxm.hpp"
124+#include <iostream>
125
126 namespace cv
127 {
128
129 ///////////////////////// P?M reader //////////////////////////////
130
131-static int ReadNumber( RLByteStream& strm, int maxdigits )
132+static int ReadNumber(RLByteStream& strm, int maxdigits = 0)
133 {
134 int code;
135- int val = 0;
136+ int64 val = 0;
137 int digits = 0;
138
139 code = strm.getByte();
140
141- if( !isdigit(code))
142+ while (!isdigit(code))
143 {
144- do
145+ if (code == '#' )
146 {
147- if( code == '#' )
148+ do
149 {
150- do
151- {
152- code = strm.getByte();
153- }
154- while( code != '\n' && code != '\r' );
155+ code = strm.getByte();
156 }
157-
158+ while (code != '\n' && code != '\r');
159 code = strm.getByte();
160-
161- while( isspace(code))
162+ }
163+ else if (isspace(code))
164+ {
165+ while (isspace(code))
166 code = strm.getByte();
167 }
168- while( !isdigit( code ));
169+ else
170+ {
171+#if 1
172+ CV_ErrorNoReturn_(Error::StsError, ("PXM: Unexpected code in ReadNumber(): 0x%x (%d)", code, code));
173+#else
174+ code = strm.getByte();
175+#endif
176+ }
177 }
178
179 do
180 {
181- val = val*10 + code - '0';
182- if( ++digits >= maxdigits ) break;
183+ val = val*10 + (code - '0');
184+ CV_Assert(val <= INT_MAX && "PXM: ReadNumber(): result is too large");
185+ digits++;
186+ if (maxdigits != 0 && digits >= maxdigits) break;
187 code = strm.getByte();
188 }
189- while( isdigit(code));
190+ while (isdigit(code));
191
192- return val;
193+ return (int)val;
194 }
195
196
197@@ -122,13 +130,13 @@ ImageDecoder PxMDecoder::newDecoder() const
198 return makePtr<PxMDecoder>();
199 }
200
201-void PxMDecoder::close()
202+void PxMDecoder::close()
203 {
204 m_strm.close();
205 }
206
207
208-bool PxMDecoder::readHeader()
209+bool PxMDecoder::readHeader()
210 {
211 bool result = false;
212
213@@ -158,10 +166,10 @@ bool PxMDecoder::readHeader()
214 m_binary = code >= '4';
215 m_type = m_bpp > 8 ? CV_8UC3 : CV_8UC1;
216
217- m_width = ReadNumber( m_strm, INT_MAX );
218- m_height = ReadNumber( m_strm, INT_MAX );
219+ m_width = ReadNumber(m_strm);
220+ m_height = ReadNumber(m_strm);
221
222- m_maxval = m_bpp == 1 ? 1 : ReadNumber( m_strm, INT_MAX );
223+ m_maxval = m_bpp == 1 ? 1 : ReadNumber(m_strm);
224 if( m_maxval > 65535 )
225 throw RBS_BAD_HEADER;
226
227@@ -175,8 +183,14 @@ bool PxMDecoder::readHeader()
228 result = true;
229 }
230 }
231- catch(...)
232+ catch (const cv::Exception&)
233+ {
234+ throw;
235+ }
236+ catch (...)
237 {
238+ std::cerr << "PXM::readHeader(): unknown C++ exception" << std::endl << std::flush;
239+ throw;
240 }
241
242 if( !result )
243@@ -189,33 +203,28 @@ bool PxMDecoder::readHeader()
244 }
245
246
247-bool PxMDecoder::readData( Mat& img )
248+bool PxMDecoder::readData( Mat& img )
249 {
250 int color = img.channels() > 1;
251 uchar* data = img.ptr();
252 PaletteEntry palette[256];
253 bool result = false;
254- int bit_depth = CV_ELEM_SIZE1(m_type)*8;
255- int src_pitch = (m_width*m_bpp*bit_depth/8 + 7)/8;
256+ const int bit_depth = CV_ELEM_SIZE1(m_type)*8;
257+ const int src_pitch = divUp(m_width*m_bpp*(bit_depth/8), 8);
258 int nch = CV_MAT_CN(m_type);
259 int width3 = m_width*nch;
260- int i, x, y;
261
262 if( m_offset < 0 || !m_strm.isOpened())
263 return false;
264
265- AutoBuffer<uchar> _src(src_pitch + 32);
266- uchar* src = _src;
267- AutoBuffer<uchar> _gray_palette;
268- uchar* gray_palette = _gray_palette;
269+ uchar gray_palette[256] = {0};
270
271 // create LUT for converting colors
272 if( bit_depth == 8 )
273 {
274- _gray_palette.allocate(m_maxval + 1);
275- gray_palette = _gray_palette;
276+ CV_Assert(m_maxval < 256);
277
278- for( i = 0; i <= m_maxval; i++ )
279+ for (int i = 0; i <= m_maxval; i++)
280 gray_palette[i] = (uchar)((i*255/m_maxval)^(m_bpp == 1 ? 255 : 0));
281
282 FillGrayPalette( palette, m_bpp==1 ? 1 : 8 , m_bpp == 1 );
283@@ -229,12 +238,16 @@ bool PxMDecoder::readData( Mat& img )
284 {
285 ////////////////////////// 1 BPP /////////////////////////
286 case 1:
287+ CV_Assert(CV_MAT_DEPTH(m_type) == CV_8U);
288 if( !m_binary )
289 {
290- for( y = 0; y < m_height; y++, data += img.step )
291+ AutoBuffer<uchar> _src(m_width);
292+ uchar* src = _src;
293+
294+ for (int y = 0; y < m_height; y++, data += img.step)
295 {
296- for( x = 0; x < m_width; x++ )
297- src[x] = ReadNumber( m_strm, 1 ) != 0;
298+ for (int x = 0; x < m_width; x++)
299+ src[x] = ReadNumber(m_strm, 1) != 0;
300
301 if( color )
302 FillColorRow8( data, src, m_width, palette );
303@@ -244,7 +257,10 @@ bool PxMDecoder::readData( Mat& img )
304 }
305 else
306 {
307- for( y = 0; y < m_height; y++, data += img.step )
308+ AutoBuffer<uchar> _src(src_pitch);
309+ uchar* src = _src;
310+
311+ for (int y = 0; y < m_height; y++, data += img.step)
312 {
313 m_strm.getBytes( src, src_pitch );
314
315@@ -260,13 +276,17 @@ bool PxMDecoder::readData( Mat& img )
316 ////////////////////////// 8 BPP /////////////////////////
317 case 8:
318 case 24:
319- for( y = 0; y < m_height; y++, data += img.step )
320+ {
321+ AutoBuffer<uchar> _src(std::max<size_t>(width3*2, src_pitch));
322+ uchar* src = _src;
323+
324+ for (int y = 0; y < m_height; y++, data += img.step)
325 {
326 if( !m_binary )
327 {
328- for( x = 0; x < width3; x++ )
329+ for (int x = 0; x < width3; x++)
330 {
331- int code = ReadNumber( m_strm, INT_MAX );
332+ int code = ReadNumber(m_strm);
333 if( (unsigned)code > (unsigned)m_maxval ) code = m_maxval;
334 if( bit_depth == 8 )
335 src[x] = gray_palette[code];
336@@ -279,7 +299,7 @@ bool PxMDecoder::readData( Mat& img )
337 m_strm.getBytes( src, src_pitch );
338 if( bit_depth == 16 && !isBigEndian() )
339 {
340- for( x = 0; x < width3; x++ )
341+ for (int x = 0; x < width3; x++)
342 {
343 uchar v = src[x * 2];
344 src[x * 2] = src[x * 2 + 1];
345@@ -290,7 +310,7 @@ bool PxMDecoder::readData( Mat& img )
346
347 if( img.depth() == CV_8U && bit_depth == 16 )
348 {
349- for( x = 0; x < width3; x++ )
350+ for (int x = 0; x < width3; x++)
351 {
352 int v = ((ushort *)src)[x];
353 src[x] = (uchar)(v >> 8);
354@@ -331,12 +351,19 @@ bool PxMDecoder::readData( Mat& img )
355 }
356 result = true;
357 break;
358+ }
359 default:
360- assert(0);
361+ CV_ErrorNoReturn(Error::StsError, "m_bpp is not supported");
362 }
363 }
364- catch(...)
365+ catch (const cv::Exception&)
366+ {
367+ throw;
368+ }
369+ catch (...)
370 {
371+ std::cerr << "PXM::readData(): unknown exception" << std::endl << std::flush;
372+ throw;
373 }
374
375 return result;
376@@ -412,8 +439,9 @@ bool PxMEncoder::write( const Mat& img, const std::vector<int>& params )
377 char* buffer = _buffer;
378
379 // write header;
380- sprintf( buffer, "P%c\n%d %d\n%d\n",
381+ sprintf( buffer, "P%c\n# Generated by OpenCV %s\n%d %d\n%d\n",
382 '2' + (channels > 1 ? 1 : 0) + (isBinary ? 3 : 0),
383+ CV_VERSION,
384 width, height, (1 << depth) - 1 );
385
386 strm.putBytes( buffer, (int)strlen(buffer) );
387diff --git a/modules/imgcodecs/src/loadsave.cpp b/modules/imgcodecs/src/loadsave.cpp
388index 3b2366217..5ee4ca354 100644
389--- a/modules/imgcodecs/src/loadsave.cpp
390+++ b/modules/imgcodecs/src/loadsave.cpp
391@@ -55,6 +55,27 @@
392 /****************************************************************************************\
393 * Image Codecs *
394 \****************************************************************************************/
395+
396+namespace cv {
397+
398+// TODO Add runtime configuration
399+#define CV_IO_MAX_IMAGE_PARAMS (50)
400+#define CV_IO_MAX_IMAGE_WIDTH (1<<20)
401+#define CV_IO_MAX_IMAGE_HEIGHT (1<<20)
402+#define CV_IO_MAX_IMAGE_PIXELS (1<<30) // 1 Gigapixel
403+
404+static Size validateInputImageSize(const Size& size)
405+{
406+ CV_Assert(size.width > 0);
407+ CV_Assert(size.width <= CV_IO_MAX_IMAGE_WIDTH);
408+ CV_Assert(size.height > 0);
409+ CV_Assert(size.height <= CV_IO_MAX_IMAGE_HEIGHT);
410+ uint64 pixels = (uint64)size.width * (uint64)size.height;
411+ CV_Assert(pixels <= CV_IO_MAX_IMAGE_PIXELS);
412+ return size;
413+}
414+
415+
416 namespace {
417
418 class ByteStreamBuffer: public std::streambuf
419@@ -94,9 +115,6 @@ protected:
420
421 }
422
423-namespace cv
424-{
425-
426 /**
427 * @struct ImageCodecInitializer
428 *
429@@ -408,14 +426,26 @@ imread_( const String& filename, int flags, int hdrtype, Mat* mat=0 )
430 /// set the filename in the driver
431 decoder->setSource( filename );
432
433- // read the header to make sure it succeeds
434- if( !decoder->readHeader() )
435+ try
436+ {
437+ // read the header to make sure it succeeds
438+ if( !decoder->readHeader() )
439+ return 0;
440+ }
441+ catch (const cv::Exception& e)
442+ {
443+ std::cerr << "imread_('" << filename << "'): can't read header: " << e.what() << std::endl << std::flush;
444 return 0;
445+ }
446+ catch (...)
447+ {
448+ std::cerr << "imread_('" << filename << "'): can't read header: unknown exception" << std::endl << std::flush;
449+ return 0;
450+ }
451+
452
453 // established the required input image size
454- CvSize size;
455- size.width = decoder->width();
456- size.height = decoder->height();
457+ Size size = validateInputImageSize(Size(decoder->width(), decoder->height()));
458
459 // grab the decoded type
460 int type = decoder->type();
461@@ -451,7 +481,21 @@ imread_( const String& filename, int flags, int hdrtype, Mat* mat=0 )
462 }
463
464 // read the image data
465- if( !decoder->readData( *data ))
466+ bool success = false;
467+ try
468+ {
469+ if (decoder->readData(*data))
470+ success = true;
471+ }
472+ catch (const cv::Exception& e)
473+ {
474+ std::cerr << "imread_('" << filename << "'): can't read data: " << e.what() << std::endl << std::flush;
475+ }
476+ catch (...)
477+ {
478+ std::cerr << "imread_('" << filename << "'): can't read data: unknown exception" << std::endl << std::flush;
479+ }
480+ if (!success)
481 {
482 cvReleaseImage( &image );
483 cvReleaseMat( &matrix );
484@@ -504,8 +548,22 @@ imreadmulti_(const String& filename, int flags, std::vector<Mat>& mats)
485 decoder->setSource(filename);
486
487 // read the header to make sure it succeeds
488- if (!decoder->readHeader())
489+ try
490+ {
491+ // read the header to make sure it succeeds
492+ if( !decoder->readHeader() )
493+ return 0;
494+ }
495+ catch (const cv::Exception& e)
496+ {
497+ std::cerr << "imreadmulti_('" << filename << "'): can't read header: " << e.what() << std::endl << std::flush;
498 return 0;
499+ }
500+ catch (...)
501+ {
502+ std::cerr << "imreadmulti_('" << filename << "'): can't read header: unknown exception" << std::endl << std::flush;
503+ return 0;
504+ }
505
506 for (;;)
507 {
508@@ -523,17 +581,32 @@ imreadmulti_(const String& filename, int flags, std::vector<Mat>& mats)
509 type = CV_MAKETYPE(CV_MAT_DEPTH(type), 1);
510 }
511
512+ // established the required input image size
513+ Size size = validateInputImageSize(Size(decoder->width(), decoder->height()));
514+
515 // read the image data
516- Mat mat(decoder->height(), decoder->width(), type);
517- if (!decoder->readData(mat))
518+ Mat mat(size.height, size.width, type);
519+ bool success = false;
520+ try
521 {
522- // optionally rotate the data if EXIF' orientation flag says so
523- if( (flags & IMREAD_IGNORE_ORIENTATION) == 0 && flags != IMREAD_UNCHANGED )
524- {
525- ApplyExifOrientation(filename, mat);
526- }
527-
528+ if (decoder->readData(mat))
529+ success = true;
530+ }
531+ catch (const cv::Exception& e)
532+ {
533+ std::cerr << "imreadmulti_('" << filename << "'): can't read data: " << e.what() << std::endl << std::flush;
534+ }
535+ catch (...)
536+ {
537+ std::cerr << "imreadmulti_('" << filename << "'): can't read data: unknown exception" << std::endl << std::flush;
538+ }
539+ if (!success)
540 break;
541+
542+ // optionally rotate the data if EXIF' orientation flag says so
543+ if( (flags & IMREAD_IGNORE_ORIENTATION) == 0 && flags != IMREAD_UNCHANGED )
544+ {
545+ ApplyExifOrientation(filename, mat);
546 }
547
548 mats.push_back(mat);
549@@ -616,6 +689,7 @@ static bool imwrite_( const String& filename, const Mat& image,
550 }
551
552 encoder->setDestination( filename );
553+ CV_Assert(params.size() <= CV_IO_MAX_IMAGE_PARAMS*2);
554 bool code = encoder->write( *pimage, params );
555
556 // CV_Assert( code );
557@@ -663,22 +737,35 @@ imdecode_( const Mat& buf, int flags, int hdrtype, Mat* mat=0 )
558 decoder->setSource(filename);
559 }
560
561- if( !decoder->readHeader() )
562+ bool success = false;
563+ try
564+ {
565+ if (decoder->readHeader())
566+ success = true;
567+ }
568+ catch (const cv::Exception& e)
569+ {
570+ std::cerr << "imdecode_('" << filename << "'): can't read header: " << e.what() << std::endl << std::flush;
571+ }
572+ catch (...)
573+ {
574+ std::cerr << "imdecode_('" << filename << "'): can't read header: unknown exception" << std::endl << std::flush;
575+ }
576+ if (!success)
577 {
578 decoder.release();
579- if ( !filename.empty() )
580+ if (!filename.empty())
581 {
582- if ( remove(filename.c_str()) != 0 )
583+ if (0 != remove(filename.c_str()))
584 {
585- CV_Error( CV_StsError, "unable to remove temporary file" );
586+ std::cerr << "unable to remove temporary file:" << filename << std::endl << std::flush;
587 }
588 }
589 return 0;
590 }
591
592- CvSize size;
593- size.width = decoder->width();
594- size.height = decoder->height();
595+ // established the required input image size
596+ Size size = validateInputImageSize(Size(decoder->width(), decoder->height()));
597
598 int type = decoder->type();
599 if( (flags & IMREAD_LOAD_GDAL) != IMREAD_LOAD_GDAL && flags != IMREAD_UNCHANGED )
600@@ -712,17 +799,30 @@ imdecode_( const Mat& buf, int flags, int hdrtype, Mat* mat=0 )
601 temp = cvarrToMat(image);
602 }
603
604- bool code = decoder->readData( *data );
605+ success = false;
606+ try
607+ {
608+ if (decoder->readData(*data))
609+ success = true;
610+ }
611+ catch (const cv::Exception& e)
612+ {
613+ std::cerr << "imdecode_('" << filename << "'): can't read data: " << e.what() << std::endl << std::flush;
614+ }
615+ catch (...)
616+ {
617+ std::cerr << "imdecode_('" << filename << "'): can't read data: unknown exception" << std::endl << std::flush;
618+ }
619 decoder.release();
620- if ( !filename.empty() )
621+ if (!filename.empty())
622 {
623- if ( remove(filename.c_str()) != 0 )
624+ if (0 != remove(filename.c_str()))
625 {
626- CV_Error( CV_StsError, "unable to remove temporary file" );
627+ std::cerr << "unable to remove temporary file:" << filename << std::endl << std::flush;
628 }
629 }
630
631- if( !code )
632+ if (!success)
633 {
634 cvReleaseImage( &image );
635 cvReleaseMat( &matrix );
636@@ -859,7 +959,7 @@ cvSaveImage( const char* filename, const CvArr* arr, const int* _params )
637 if( _params )
638 {
639 for( ; _params[i] > 0; i += 2 )
640- ;
641+ CV_Assert(i < CV_IO_MAX_IMAGE_PARAMS*2); // Limit number of params for security reasons
642 }
643 return cv::imwrite_(filename, cv::cvarrToMat(arr),
644 i > 0 ? std::vector<int>(_params, _params+i) : std::vector<int>(),
645@@ -890,7 +990,7 @@ cvEncodeImage( const char* ext, const CvArr* arr, const int* _params )
646 if( _params )
647 {
648 for( ; _params[i] > 0; i += 2 )
649- ;
650+ CV_Assert(i < CV_IO_MAX_IMAGE_PARAMS*2); // Limit number of params for security reasons
651 }
652 cv::Mat img = cv::cvarrToMat(arr);
653 if( CV_IS_IMAGE(arr) && ((const IplImage*)arr)->origin == IPL_ORIGIN_BL )
654--
6552.14.1
656