From fc5b6e4ddaf338780d567a9ff2cc1eb619a55e7c Mon Sep 17 00:00:00 2001 From: Nicolas Ramz Date: Fri, 5 Jan 2024 17:09:29 +0100 Subject: [PATCH] LiGfx/ILBMLoader: Don't throw if malformed bitplane can be decoded Some apps seem to generate malformed images that are accepted by most readers. We now only throw if malformed data would lead to a write outside the chunky buffer. --- Tests/LibGfx/TestImageDecoder.cpp | 11 +++++++++++ .../test-inputs/ilbm/brush-transparent-color.iff | Bin 0 -> 4858 bytes .../Libraries/LibGfx/ImageFormats/ILBMLoader.cpp | 8 +++++++- 3 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 Tests/LibGfx/test-inputs/ilbm/brush-transparent-color.iff diff --git a/Tests/LibGfx/TestImageDecoder.cpp b/Tests/LibGfx/TestImageDecoder.cpp index f9f7022d1a..ffd47e6a3e 100644 --- a/Tests/LibGfx/TestImageDecoder.cpp +++ b/Tests/LibGfx/TestImageDecoder.cpp @@ -243,6 +243,17 @@ TEST_CASE(test_24bit) EXPECT_EQ(frame.image->get_pixel(158, 270), Gfx::Color(0xee, 0x3d, 0x3c, 255)); } +TEST_CASE(test_brush_transparent_color) +{ + auto file = MUST(Core::MappedFile::map(TEST_INPUT("ilbm/brush-transparent-color.iff"sv))); + EXPECT(Gfx::ILBMImageDecoderPlugin::sniff(file->bytes())); + auto plugin_decoder = TRY_OR_FAIL(Gfx::ILBMImageDecoderPlugin::create(file->bytes())); + + auto frame = TRY_OR_FAIL(expect_single_frame_of_size(*plugin_decoder, { 266, 309 })); + + EXPECT_EQ(frame.image->get_pixel(114, 103), Gfx::Color::NamedColor::Black); +} + TEST_CASE(test_ilbm_malformed_header) { Array test_inputs = { diff --git a/Tests/LibGfx/test-inputs/ilbm/brush-transparent-color.iff b/Tests/LibGfx/test-inputs/ilbm/brush-transparent-color.iff new file mode 100644 index 0000000000000000000000000000000000000000..ed5e7268f60a30bcce54d8bacb8af38027d40d7d GIT binary patch literal 4858 zcmZ?s5AtPT5c=fl*2z{z#ziN#c0Zq%V5RK#Mr>VAST7sz&OF#*D-*BfkEQT znKKLw4FCWC@95}QrNnSIl;PcO28Ip>_aH|n1_lNehE|4I&W^tBU^e3f7MB1|1u$ER zLCneDC6a+bsP#Sr`S2qHgTe=}{*Md{25?pZoK*p5)nH-$gNq?p|6yW`{~JDnjsC>I zgvvgEB>n&^oB96-xHu~N2V9)}{~sLee@Np0;cWi@a5gjl|Njl2ppFA^4q)fV|Ns90 zE`!ebfGqO^&awah|Hp3z2F9N-Y8dMO z{Rb&Q5nyQe!@$V?09g%0=mSjX?|+5^AT{U${6COXJov-Fh$8R-B=85K;xhvSD{;4j1f{|p~c)IC5GITb?ec&AGyM6-z|0JeJ*al5AOkZf0+Gc2{bK-$fg%hlYXAHHKL!T&fB&(H z9ryzaFZi>eH8sy&J3=Hg_{xdb;6g%)294ruZj0YGXv5L@&P3Qqg)dv)f9~l4qXTT!#14Y#j zkg7i@LVuV+k&Y?!4@Kx7NEMRM$NvoMzyBkYK==#||KOha_@ANu_kT2z{@?!@4xp$x zk0J8@_kV^52sN+Jc^^>Ze&FH#L6Jk{{X@vT{Ev&x)W87u&r47wBJ&R5mP45L>OTXL zO|QV&3l_H+JXF7+`V%!okizg4N*KRF#0mfF{|ty21Mv_MFaP>K10rRh^6XzDCnON> z0X&}TU;k%7Bv=ry0VekfnlFAcfb50jkv|L!jIY5(D9F!H9yBLHc^}{^L8a*55Acls zhk*f<=ITHGXMmOme;61*W$68n;5q?nB1q)>M|g?z2U6Vq{P-VIs6qMvKK*Ba7IS|X z803HdXW0MwKf@om8j#5Q&;J>qB`GND|NhVL`!l=@hKl_8{GS0@djDZysQ>k!!Tt-n z$oVh-8K9;9ABLa*89smc&j76}!2BOyptT8z$N10w+kXaVz4VuXf$_(GhW>B=8K9LH zROIou{|wLy?=J%b^N;@wAHV%)fYyl+5yn6D-~Tf}tJ1#=4D8?kGst6z9RL2G0a^q9 zWnkd{{-5FF_x}vgY8xWL_@n;Ee@I>bmjPr1<3IVI{~7)vgueY}X#e@2;SXE{>pP>P!;>&-=ANIfh z{{Uyie+&$aU;Z=x166SU5JI2-Gc<$BG`I*eDAxY`XZV3E!uY`+)GUAtv48&0_=o@R ze})GLp-=z8b^8Ih2>&Ng`v1?+fGooJp&nG_p$Pqu|M&kp%#re+{^&Ed0yBQ2zH~z5*4U zU%-tOP?-u9{LS#?KQpv|gbOjqe+3JIT73vX=C9yZQ$4700{2f%m)+5AzFfi2r_|FJxWr14n zpb-4Qz`zd@V*Ul!`2*B5`OowZT#!JkmhTJ<_P_o!{Q;4%hTnGv2IgP?nSOu^ZK%3$ z3=H+Z|1Uh&5%Zt_jQ{L0gg^y6+(n>j@8>sYmHQ1+F@8qo ze?Z9be}K0}LEa;pC;tId*n!KCZww3=Jh)rzKf;^W-xwG`JZQoJ@jk(;Sx{(yf>)Lh z9;BxQVuLDQ7!Op)!q}hTRnIpDP%#dv2);8gFn)&C0wDGmc;OD^L5plqtbhH_04;c- zJZPB;33x>qQ? z127(_C;8_MR3S6_|NjqQ947Yv|6fBTnArdSfV27kAAqqL`TxCwDq-Y*0An)9zk~`h NNI+PiqJi3&0RSYw8u0)C literal 0 HcmV?d00001 diff --git a/Userland/Libraries/LibGfx/ImageFormats/ILBMLoader.cpp b/Userland/Libraries/LibGfx/ImageFormats/ILBMLoader.cpp index 822f151b3c..8e2cebee1d 100644 --- a/Userland/Libraries/LibGfx/ImageFormats/ILBMLoader.cpp +++ b/Userland/Libraries/LibGfx/ImageFormats/ILBMLoader.cpp @@ -211,13 +211,19 @@ static ErrorOr planar_to_chunky(ReadonlyBytes bitplanes, ILBMLoading for (u8 p = 0; p < planes; p++) { u8 const plane_mask = 1 << (p % 8); size_t offset_base = (pitch * planes * y) + (p * pitch); - if (offset_base + pitch > bitplanes.size() || scanline + ((pitch - 1) * 8) + 7 >= chunky.size()) + if (offset_base + pitch > bitplanes.size()) return Error::from_string_literal("Malformed bitplane data"); for (u16 i = 0; i < pitch; i++) { u8 bit = bitplanes[offset_base + i]; u8 rgb_shift = p / 8; + // Only throw an error if we would actually attempt to write + // outside of the chunky buffer. Some apps like PPaint produce + // malformed bitplane data but files are still accepted by most readers. + if (bit && scanline + ((pitch - 1) * 8) + 7 >= chunky.size()) + return Error::from_string_literal("Malformed bitplane data"); + for (u8 b = 0; b < 8; b++) { u8 mask = 1 << (7 - b); // get current plane