From b8cbc282f3e59f0713e7cbcb61d444fdb982b921 Mon Sep 17 00:00:00 2001 From: Lucas CHOLLET Date: Fri, 29 Dec 2023 23:54:47 -0500 Subject: [PATCH] LibGfx/TIFF: Don't stop decoding when failing to decode a tag TIFF files are made in a way that make them easily extendable and over the years people have made sure to exploit that. In other words, it's easy to find images with non-standard tags. Instead of returning an error for that, let's skip them. Note that we need to make sure to realign the reading head in the file. The test case was originally a 10x10 checkerboard image with required tags, and also the `DocumentName` tag. Then, I modified this tag in a hexadecimal editor and replaced its id with 30 000 (0x3075 as a LE u16) and the type with the same value as well. This is AFAIK, never used as a custom TIFF tag, so this should remain an invalid tag id and type. --- Tests/LibGfx/TestImageDecoder.cpp | 12 ++++++++++++ Tests/LibGfx/test-inputs/tiff/invalid_tag.tiff | Bin 0 -> 191 bytes .../Libraries/LibGfx/ImageFormats/TIFFLoader.cpp | 13 +++++++++++-- 3 files changed, 23 insertions(+), 2 deletions(-) create mode 100644 Tests/LibGfx/test-inputs/tiff/invalid_tag.tiff diff --git a/Tests/LibGfx/TestImageDecoder.cpp b/Tests/LibGfx/TestImageDecoder.cpp index e309bd6ec3..0a72e09ad9 100644 --- a/Tests/LibGfx/TestImageDecoder.cpp +++ b/Tests/LibGfx/TestImageDecoder.cpp @@ -546,6 +546,18 @@ TEST_CASE(test_tiff_16_bits) EXPECT_EQ(frame.image->get_pixel(60, 75), Gfx::Color::NamedColor::Red); } +TEST_CASE(test_tiff_invalid_tag) +{ + auto file = MUST(Core::MappedFile::map(TEST_INPUT("tiff/invalid_tag.tiff"sv))); + EXPECT(Gfx::TIFFImageDecoderPlugin::sniff(file->bytes())); + auto plugin_decoder = TRY_OR_FAIL(Gfx::TIFFImageDecoderPlugin::create(file->bytes())); + + auto frame = TRY_OR_FAIL(expect_single_frame_of_size(*plugin_decoder, { 10, 10 })); + + EXPECT_EQ(frame.image->get_pixel(0, 0), Gfx::Color::NamedColor::Black); + EXPECT_EQ(frame.image->get_pixel(0, 9), Gfx::Color::NamedColor::White); +} + TEST_CASE(test_webp_simple_lossy) { auto file = MUST(Core::MappedFile::map(TEST_INPUT("webp/simple-vp8.webp"sv))); diff --git a/Tests/LibGfx/test-inputs/tiff/invalid_tag.tiff b/Tests/LibGfx/test-inputs/tiff/invalid_tag.tiff new file mode 100644 index 0000000000000000000000000000000000000000..501070fb1ae23143e6505b324ee21fbb4a67d0b5 GIT binary patch literal 191 zcmebD)MC(JU|?uqkpG~e!uy}C>7b%PhmD>nPty@affpuT@*>?14-^=<7#J9t85kKD zKr9AEBsLS2&B4IHzzk)xGB7Z(LD?WZ2Bik2k_-$C%NQ6K1Q}Vt=77|TBB>FBvbh)- l7{sA!seek(m_next_ifd.value())); auto const number_of_field = TRY(read_value()); + auto next_tag_offset = TRY(m_stream->tell()); - for (u16 i = 0; i < number_of_field; ++i) - TRY(read_tag()); + for (u16 i = 0; i < number_of_field; ++i) { + TRY(m_stream->seek(next_tag_offset)); + if (auto maybe_error = read_tag(); maybe_error.is_error() && TIFF_DEBUG) + dbgln("Unable to decode tag {}/{}", i + 1, number_of_field); + + // Section 2: TIFF Structure + // IFD Entry + // Size of tag(u16) + type(u16) + count(u32) + value_or_offset(u32) = 12 + next_tag_offset += 12; + } TRY(read_next_idf_offset()); return {};