Handle unknown top level boxes with size == 0
In avifParse() right now we skip over unknown top level boxes with
size == 0 incorrectly.
The correct behavior is to simply fail on them because if we reach
that point it means that:
1) there are no more boxes left to parse (since the current unknown
box goes on until the end of stream).
2) we haven't found all the necessary boxes for the parsing to be
considered a succeess (either ftyp or moov or meta was not yet
seen).
diff --git a/src/read.c b/src/read.c
index 5e6b73c..fee8456 100644
--- a/src/read.c
+++ b/src/read.c
@@ -3995,6 +3995,10 @@
}
} 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 99f3970..1dc0968 100644
--- a/tests/gtest/avifsize0test.cc
+++ b/tests/gtest/avifsize0test.cc
@@ -2,6 +2,7 @@
// SPDX-License-Identifier: BSD-2-Clause
#include <algorithm>
+#include <cstring>
#include <iostream>
#include <string>
@@ -89,6 +90,28 @@
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