diff --git a/src/read.c b/src/read.c index 5e6b73ca76..fee8456340 100644 --- a/src/read.c +++ b/src/read.c @@ -3995,6 +3995,10 @@ static avifResult avifParse(avifDecoder * decoder) } } else if (header.size > (UINT64_MAX - parseOffset)) { return AVIF_RESULT_BMFF_PARSE_FAILED; + } else if (header.size == 0) { + // An unknown top level box with size 0 was found. If we reach here it means we haven't completed parsing successfully + // since there are no futher boxes left. + return AVIF_RESULT_TRUNCATED_DATA; } parseOffset += header.size; diff --git a/tests/gtest/avifsize0test.cc b/tests/gtest/avifsize0test.cc index 99f3970287..1dc0968fbc 100644 --- a/tests/gtest/avifsize0test.cc +++ b/tests/gtest/avifsize0test.cc @@ -2,6 +2,7 @@ // SPDX-License-Identifier: BSD-2-Clause #include +#include #include #include @@ -89,6 +90,28 @@ TEST(AvifDecodeTest, FtypSize0) { ASSERT_EQ(avifDecoderParse(decoder.get()), AVIF_RESULT_BMFF_PARSE_FAILED); } +TEST(AvifDecodeTest, UnknownTopLevelBoxSize0) { + testutil::AvifRwData avif = + testutil::ReadFile(std::string(data_path) + "white_1x1.avif"); + // Edit the file to insert an unknown top level box with size 0 after ftyp + // (invalid). + testutil::AvifRwData avif_edited; + ASSERT_EQ(avifRWDataRealloc(&avif_edited, avif.size + 8), AVIF_RESULT_OK); + // Copy the ftyp box. + std::memcpy(avif_edited.data, avif.data, 32); + // Set 8 bytes to 0 (box type and size all 0s). + std::memset(avif_edited.data + 32, 0, 8); + // Copy the other boxes. + std::memcpy(avif_edited.data + 40, avif.data + 32, avif.size - 32); + + DecoderPtr decoder(avifDecoderCreate()); + ASSERT_NE(decoder, nullptr); + ASSERT_EQ( + avifDecoderSetIOMemory(decoder.get(), avif_edited.data, avif_edited.size), + AVIF_RESULT_OK); + ASSERT_EQ(avifDecoderParse(decoder.get()), AVIF_RESULT_TRUNCATED_DATA); +} + //------------------------------------------------------------------------------ } // namespace