From 20208cc81f1e8d73ca6d3c66b1fa923dfecfe186 Mon Sep 17 00:00:00 2001 From: David Costanzo Date: Fri, 5 Nov 2021 19:30:24 -0700 Subject: [PATCH] Fix loading bitmaps with malformed biClrUsed field Stop throwing std::bad_alloc when BMP has large/negative biClrUsed by checking that biClrUsed has a reasonable value before attempting to allocate however much memory it indicates. Add unit tests showing the loading such invalid bitmaps now correctly returns an error rather than throwing an exception. Closes https://github.com/wxWidgets/wxWidgets/pull/2583 Closes #19295. --- src/common/imagbmp.cpp | 18 +++++++++++++++++- tests/Makefile.in | 2 +- tests/image/8bpp-colorsused-large.bmp | Bin 0 -> 76878 bytes tests/image/8bpp-colorsused-negative.bmp | Bin 0 -> 76878 bytes tests/image/image.cpp | 21 +++++++++++++++++++++ tests/makefile.gcc | 2 +- tests/makefile.vc | 2 +- tests/test.bkl | 3 +++ 8 files changed, 44 insertions(+), 4 deletions(-) create mode 100644 tests/image/8bpp-colorsused-large.bmp create mode 100644 tests/image/8bpp-colorsused-negative.bmp diff --git a/src/common/imagbmp.cpp b/src/common/imagbmp.cpp index b5ba0d2af8..ba10eb0664 100644 --- a/src/common/imagbmp.cpp +++ b/src/common/imagbmp.cpp @@ -518,8 +518,24 @@ bool wxBMPHandler::DoLoadDib(wxImage * image, int width, int height, // allocate space for palette if needed: BMPPalette *cmap; - if ( bpp < 16 ) + if ( bpp <= 8 ) { + // The bit depth is 8bpp, 4bpp, or 1bpp, which means that ncolors is + // the size of a palette. The largest useful palette is 256 since + // anything larger couldn't be referenced by a pixel. Since ncolors + // comes from the file, which could be corrupt or malicious, reject + // any bitmaps that have a dubious palette size. + if ( ncolors < 0 || 256 < ncolors ) + { + if ( verbose ) + { + wxLogError( + _("BMP: header has biClrUsed=%d when biBitCount=%d."), + ncolors, bpp); + } + return false; + } + cmap = new BMPPalette[ncolors]; if ( !cmap ) { diff --git a/tests/Makefile.in b/tests/Makefile.in index afefe8f5f7..da4b85106c 100644 --- a/tests/Makefile.in +++ b/tests/Makefile.in @@ -565,7 +565,7 @@ data: data-images: @mkdir -p image - @for f in horse_grey.bmp horse_grey_flipped.bmp horse_rle4.bmp horse_rle4_flipped.bmp horse_rle8.bmp horse_rle8_flipped.bmp horse_bicubic_50x50.png horse_bicubic_100x100.png horse_bicubic_150x150.png horse_bicubic_300x300.png horse_bilinear_50x50.png horse_bilinear_100x100.png horse_bilinear_150x150.png horse_bilinear_300x300.png horse_box_average_50x50.png horse_box_average_100x100.png horse_box_average_150x150.png horse_box_average_300x300.png cross_bicubic_256x256.png cross_bilinear_256x256.png cross_box_average_256x256.png cross_nearest_neighb_256x256.png paste_input_background.png paste_input_black.png paste_input_overlay_transparent_border_opaque_square.png paste_input_overlay_transparent_border_semitransparent_circle.png paste_input_overlay_transparent_border_semitransparent_square.png paste_result_background_plus_circle_plus_square.png paste_result_background_plus_overlay_transparent_border_opaque_square.png paste_result_background_plus_overlay_transparent_border_semitransparent_square.png paste_result_no_background_square_over_circle.png wx.png wx.ico toucan.png toucan_hue_0.538.png toucan_sat_-0.41.png toucan_bright_-0.259.png toucan_hsv_0.538_-0.41_-0.259.png toucan_light_46.png toucan_dis_240.png toucan_grey.png toucan_mono_255_255_255.png; do \ + @for f in 8bpp-colorsused-large.bmp 8bpp-colorsused-negative.bmp horse_grey.bmp horse_grey_flipped.bmp horse_rle4.bmp horse_rle4_flipped.bmp horse_rle8.bmp horse_rle8_flipped.bmp horse_bicubic_50x50.png horse_bicubic_100x100.png horse_bicubic_150x150.png horse_bicubic_300x300.png horse_bilinear_50x50.png horse_bilinear_100x100.png horse_bilinear_150x150.png horse_bilinear_300x300.png horse_box_average_50x50.png horse_box_average_100x100.png horse_box_average_150x150.png horse_box_average_300x300.png cross_bicubic_256x256.png cross_bilinear_256x256.png cross_box_average_256x256.png cross_nearest_neighb_256x256.png paste_input_background.png paste_input_black.png paste_input_overlay_transparent_border_opaque_square.png paste_input_overlay_transparent_border_semitransparent_circle.png paste_input_overlay_transparent_border_semitransparent_square.png paste_result_background_plus_circle_plus_square.png paste_result_background_plus_overlay_transparent_border_opaque_square.png paste_result_background_plus_overlay_transparent_border_semitransparent_square.png paste_result_no_background_square_over_circle.png wx.png wx.ico toucan.png toucan_hue_0.538.png toucan_sat_-0.41.png toucan_bright_-0.259.png toucan_hsv_0.538_-0.41_-0.259.png toucan_light_46.png toucan_dis_240.png toucan_grey.png toucan_mono_255_255_255.png; do \ if test ! -f image/$$f -a ! -d image/$$f ; \ then x=yep ; \ else x=`find $(srcdir)/image/$$f -newer image/$$f -print` ; \ diff --git a/tests/image/8bpp-colorsused-large.bmp b/tests/image/8bpp-colorsused-large.bmp new file mode 100644 index 0000000000000000000000000000000000000000..672e70f8502e0dd66b2587948f840d67d8105b19 GIT binary patch literal 76878 zcmeIzO>Wa*00!Z>NhFTKfyPm{oj#1~IOG2J^J)3H-EQCJbQ^!xGd|b9r*ZEzb&d&KI|l@&>H6}d zbAH;nJndZbJ7k^TA-+p~`SI84F%$Ezd;W|TxB1b;l>CeqxB1b;l>CeqxB1b;l>Ceq zxB1b;l>CeqxB1b;l>CeqxB1b;l>CeqxB1b;l>CeqxB1b;l>CeqxB1b;l>CeqxB1b; zl>CeqxB1b;l>CeqxB1b;l>CeqxB1b;l>CeqxB1b;l>CeqxB1b;l>CeqxB1b;l>Ceq zxB1b;l>CeqxB1b;l>CeqxB1b;l>CeqxB1b;l>CeqxB1b;l>CeqxB1b;l>CeqxB1b; zl>CeqxB1b;l>CeqxB1b;l>CeqxB1b;l>CeqxB1b;l>CeqxB1b;l>CeqxB1b;l>Ceq zxB1b;l>CeqxB1b;l>CeqxB1b;l>CeqxB1b;l>CeqxB1b;l>CeqxB1b;l>CeqxB1b; zl>CeqxB1b;l>CeqxB1b;l>CeqxB1b;l>CeqxB1b;l>CeqxB1b;l>CeqxB1b;l>Ceq zxB1b;l>CeqxB1b;l>CeqxB1b;l>CeqxB1b;l>CeqxB1b;l>CeqxB1b;l>CeqxB1b; zl>CeqxB1b;l>CeqxB1b;l>CeqxB1b;l>CeqxB1b;l>CeqxB1b;l>CeqxB1b;l>Ceq zxB1b;l>CeqxB1b;l>CeqxB1b;l>CeqxB1b;l>CeqxB1b;l>CeqxB1b;l>CeqxB1b; zl>CeqxB1b;l>CeqxB1b;l>CeqxB1b;l>CeqxB1b;l>CeqxB1b;l>CeqxB1b;l>Ceq zxB1b;l>CeqxB1b;l>CeqxB1b;l>CeqxB1b;l>CeqxB1b;l>CeqxB1b;l>CeqxB1b; zl>CeqxB1b;l>CeqxB1b;l>CeqxB1b;l>CeqxB1b;l>CeqxB1b;l>CeqxB1b;l>Ceq zxB1b;l>CeqxB1b;l>CeqxB1b;l>CeqxB1b;l>CeqxB1b;l>CeqxB1b;l>CeqxB1b; zl>CeqxB1b;l>CeqxB1b;l>CeqxB1b;l>CeqxB1b;l>CeqxB1b;l>CeqxB1b;l>Ceq zxB1b;l>CeqxB1b;l>CeqxB1b;l>CeqxB1b;l>CeqxB1b;l>CeqxB1b;l>CeqxB1b; zl>CeqxB1b;l>CeqxB1b;l>CeqxB1b;l>CeqxB1b;l>CeqxB1b;l>CeqxB1b;l>Ceq zxB1b;l>CeqxB1b;l>CeqxB1b;l-Y0k$MYi3`Dw=p9NXsizx>w6@Oqs;_eXMkpNZG& z{W;xk%g68KX^-Fen2Gtl{WwY literal 0 HcmV?d00001 diff --git a/tests/image/8bpp-colorsused-negative.bmp b/tests/image/8bpp-colorsused-negative.bmp new file mode 100644 index 0000000000000000000000000000000000000000..97aeb2d8c0c4f4fa6c89447793994c92bf995713 GIT binary patch literal 76878 zcmeIzO>Wa*00!YWKN3ga2rM`RVo&dX1eP2CDSWn*7%^?dV3gH-P)8ZRY#!O=>$jKB z(_ua@H?|d*v774ePFx-z!G%rTfD+-p%Fp wTrRi&Z?|Xeac`clXWZ=f-|z45tmRIA`MvjU{>{DZg}l9&eK-O4%C?5UFBR65%>V!Z literal 0 HcmV?d00001 diff --git a/tests/image/image.cpp b/tests/image/image.cpp index 81a3ee510c..711d0b105f 100644 --- a/tests/image/image.cpp +++ b/tests/image/image.cpp @@ -98,6 +98,7 @@ private: CPPUNIT_TEST( BMPFlippingAndRLECompression ); CPPUNIT_TEST( ScaleCompare ); CPPUNIT_TEST( CreateBitmapFromCursor ); + CPPUNIT_TEST( MalformedBMP ); CPPUNIT_TEST_SUITE_END(); void LoadFromSocketStream(); @@ -119,6 +120,7 @@ private: void BMPFlippingAndRLECompression(); void ScaleCompare(); void CreateBitmapFromCursor(); + void MalformedBMP(); wxDECLARE_NO_COPY_CLASS(ImageTestCase); }; @@ -1520,6 +1522,25 @@ void ImageTestCase::CreateBitmapFromCursor() #endif } +// This function assumes that the file is malformed in a way that it cannot +// be loaded. If the file is malformed such that wxImage can salvage part +// of it, then CompareBMPImage should be called instead. +static void LoadMalformedBMP(const wxString& file) +{ + wxImage image(file); + WX_ASSERT_MESSAGE + ( + ("wxImage::isOk() returned true after loading \"%s\"", file), + !image.IsOk() + ); +} + +void ImageTestCase::MalformedBMP() +{ + LoadMalformedBMP("image/8bpp-colorsused-negative.bmp"); + LoadMalformedBMP("image/8bpp-colorsused-large.bmp"); +} + #endif //wxUSE_IMAGE TEST_CASE("wxImage::Paste", "[image][paste]") diff --git a/tests/makefile.gcc b/tests/makefile.gcc index 8b0ebd8054..2e1c9805d0 100644 --- a/tests/makefile.gcc +++ b/tests/makefile.gcc @@ -555,7 +555,7 @@ data: data-images: if not exist image mkdir image - for %%f in (horse_grey.bmp horse_grey_flipped.bmp horse_rle4.bmp horse_rle4_flipped.bmp horse_rle8.bmp horse_rle8_flipped.bmp horse_bicubic_50x50.png horse_bicubic_100x100.png horse_bicubic_150x150.png horse_bicubic_300x300.png horse_bilinear_50x50.png horse_bilinear_100x100.png horse_bilinear_150x150.png horse_bilinear_300x300.png horse_box_average_50x50.png horse_box_average_100x100.png horse_box_average_150x150.png horse_box_average_300x300.png cross_bicubic_256x256.png cross_bilinear_256x256.png cross_box_average_256x256.png cross_nearest_neighb_256x256.png paste_input_background.png paste_input_black.png paste_input_overlay_transparent_border_opaque_square.png paste_input_overlay_transparent_border_semitransparent_circle.png paste_input_overlay_transparent_border_semitransparent_square.png paste_result_background_plus_circle_plus_square.png paste_result_background_plus_overlay_transparent_border_opaque_square.png paste_result_background_plus_overlay_transparent_border_semitransparent_square.png paste_result_no_background_square_over_circle.png wx.png wx.ico toucan.png toucan_hue_0.538.png toucan_sat_-0.41.png toucan_bright_-0.259.png toucan_hsv_0.538_-0.41_-0.259.png toucan_light_46.png toucan_dis_240.png toucan_grey.png toucan_mono_255_255_255.png) do if not exist image\%%f copy .\image\%%f image + for %%f in (8bpp-colorsused-large.bmp 8bpp-colorsused-negative.bmp horse_grey.bmp horse_grey_flipped.bmp horse_rle4.bmp horse_rle4_flipped.bmp horse_rle8.bmp horse_rle8_flipped.bmp horse_bicubic_50x50.png horse_bicubic_100x100.png horse_bicubic_150x150.png horse_bicubic_300x300.png horse_bilinear_50x50.png horse_bilinear_100x100.png horse_bilinear_150x150.png horse_bilinear_300x300.png horse_box_average_50x50.png horse_box_average_100x100.png horse_box_average_150x150.png horse_box_average_300x300.png cross_bicubic_256x256.png cross_bilinear_256x256.png cross_box_average_256x256.png cross_nearest_neighb_256x256.png paste_input_background.png paste_input_black.png paste_input_overlay_transparent_border_opaque_square.png paste_input_overlay_transparent_border_semitransparent_circle.png paste_input_overlay_transparent_border_semitransparent_square.png paste_result_background_plus_circle_plus_square.png paste_result_background_plus_overlay_transparent_border_opaque_square.png paste_result_background_plus_overlay_transparent_border_semitransparent_square.png paste_result_no_background_square_over_circle.png wx.png wx.ico toucan.png toucan_hue_0.538.png toucan_sat_-0.41.png toucan_bright_-0.259.png toucan_hsv_0.538_-0.41_-0.259.png toucan_light_46.png toucan_dis_240.png toucan_grey.png toucan_mono_255_255_255.png) do if not exist image\%%f copy .\image\%%f image fr: if not exist $(OBJS)\intl\fr mkdir $(OBJS)\intl\fr diff --git a/tests/makefile.vc b/tests/makefile.vc index 8e656f802a..d8f544746e 100644 --- a/tests/makefile.vc +++ b/tests/makefile.vc @@ -989,7 +989,7 @@ data: data-images: if not exist image mkdir image - for %f in (horse_grey.bmp horse_grey_flipped.bmp horse_rle4.bmp horse_rle4_flipped.bmp horse_rle8.bmp horse_rle8_flipped.bmp horse_bicubic_50x50.png horse_bicubic_100x100.png horse_bicubic_150x150.png horse_bicubic_300x300.png horse_bilinear_50x50.png horse_bilinear_100x100.png horse_bilinear_150x150.png horse_bilinear_300x300.png horse_box_average_50x50.png horse_box_average_100x100.png horse_box_average_150x150.png horse_box_average_300x300.png cross_bicubic_256x256.png cross_bilinear_256x256.png cross_box_average_256x256.png cross_nearest_neighb_256x256.png paste_input_background.png paste_input_black.png paste_input_overlay_transparent_border_opaque_square.png paste_input_overlay_transparent_border_semitransparent_circle.png paste_input_overlay_transparent_border_semitransparent_square.png paste_result_background_plus_circle_plus_square.png paste_result_background_plus_overlay_transparent_border_opaque_square.png paste_result_background_plus_overlay_transparent_border_semitransparent_square.png paste_result_no_background_square_over_circle.png wx.png wx.ico toucan.png toucan_hue_0.538.png toucan_sat_-0.41.png toucan_bright_-0.259.png toucan_hsv_0.538_-0.41_-0.259.png toucan_light_46.png toucan_dis_240.png toucan_grey.png toucan_mono_255_255_255.png) do if not exist image\%f copy .\image\%f image + for %f in (8bpp-colorsused-large.bmp 8bpp-colorsused-negative.bmp horse_grey.bmp horse_grey_flipped.bmp horse_rle4.bmp horse_rle4_flipped.bmp horse_rle8.bmp horse_rle8_flipped.bmp horse_bicubic_50x50.png horse_bicubic_100x100.png horse_bicubic_150x150.png horse_bicubic_300x300.png horse_bilinear_50x50.png horse_bilinear_100x100.png horse_bilinear_150x150.png horse_bilinear_300x300.png horse_box_average_50x50.png horse_box_average_100x100.png horse_box_average_150x150.png horse_box_average_300x300.png cross_bicubic_256x256.png cross_bilinear_256x256.png cross_box_average_256x256.png cross_nearest_neighb_256x256.png paste_input_background.png paste_input_black.png paste_input_overlay_transparent_border_opaque_square.png paste_input_overlay_transparent_border_semitransparent_circle.png paste_input_overlay_transparent_border_semitransparent_square.png paste_result_background_plus_circle_plus_square.png paste_result_background_plus_overlay_transparent_border_opaque_square.png paste_result_background_plus_overlay_transparent_border_semitransparent_square.png paste_result_no_background_square_over_circle.png wx.png wx.ico toucan.png toucan_hue_0.538.png toucan_sat_-0.41.png toucan_bright_-0.259.png toucan_hsv_0.538_-0.41_-0.259.png toucan_light_46.png toucan_dis_240.png toucan_grey.png toucan_mono_255_255_255.png) do if not exist image\%f copy .\image\%f image fr: if not exist $(OBJS)\intl\fr mkdir $(OBJS)\intl\fr diff --git a/tests/test.bkl b/tests/test.bkl index 49fbc02f34..ffdd240cf1 100644 --- a/tests/test.bkl +++ b/tests/test.bkl @@ -349,6 +349,9 @@ $(SRCDIR)/image image + 8bpp-colorsused-large.bmp + 8bpp-colorsused-negative.bmp + horse_grey.bmp horse_grey_flipped.bmp horse_rle4.bmp horse_rle4_flipped.bmp horse_rle8.bmp horse_rle8_flipped.bmp