Fix avifParseItemLocationBox() itemReferenceIndex (#2080)
Revert bug introduced with StreamReadBits().
Read item_reference_index even if construction_method!=2 to be
accurate with the ISOBMFF specification.
Add CHANGELOG.md entries. Verbose description:
* Fix 'iloc' box parsing when offset_size, length_size or
base_offset_size was equal to 1 or 2. Such rare files were wrongly
accepted.
* Fix 'iloc'v1/2 box parsing when base_offset_size!=0. Such rare files
were wrongly rejected.
* Fix 'iloc'v1/2 box parsing when index_size!=0. Such rare files were
parsed with corrupted extent offsets and sizes instead of ignoring
index_size.
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 7dc462f..b81d3a5 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -91,6 +91,9 @@
(https://crbug.com/oss-fuzz/65657).
* ext/libjpeg.cmd now pulls libjpeg-turbo instead of libjpeg and AVIF_JPEG=LOCAL
now expects the library dependency in ext/libjpeg-turbo/build.libavif.
+* Fix 'iloc' box parsing bugs that may have wrongly accepted, rejected or parsed
+ some files with rare values of offset_size, length_size, base_offset_size and
+ index_size.
## [1.0.4] - 2024-02-08
diff --git a/src/read.c b/src/read.c
index c4b3e5d..99b4eb9 100644
--- a/src/read.c
+++ b/src/read.c
@@ -1744,6 +1744,7 @@
{
BEGIN_STREAM(s, raw, rawLen, diag, "Box[iloc]");
+ // Section 8.11.3.2 of ISO/IEC 14496-12.
uint8_t version;
AVIF_CHECKERR(avifROStreamReadVersionAndFlags(&s, &version, NULL), AVIF_RESULT_BMFF_PARSE_FAILED);
if (version > 2) {
@@ -1751,16 +1752,23 @@
return AVIF_RESULT_BMFF_PARSE_FAILED;
}
- uint8_t offsetSize, lengthSize, baseOffsetSize;
+ uint8_t offsetSize, lengthSize, baseOffsetSize, indexSize = 0;
+ uint32_t reserved;
AVIF_CHECKERR(avifROStreamReadBits8(&s, &offsetSize, /*bitCount=*/4), AVIF_RESULT_BMFF_PARSE_FAILED); // unsigned int(4) offset_size;
AVIF_CHECKERR(avifROStreamReadBits8(&s, &lengthSize, /*bitCount=*/4), AVIF_RESULT_BMFF_PARSE_FAILED); // unsigned int(4) length_size;
AVIF_CHECKERR(avifROStreamReadBits8(&s, &baseOffsetSize, /*bitCount=*/4), AVIF_RESULT_BMFF_PARSE_FAILED); // unsigned int(4) base_offset_size;
- if (((version == 1) || (version == 2)) && (baseOffsetSize != 0)) {
- avifDiagnosticsPrintf(diag, "Box[iloc] has an unsupported base_offset_size [%u]", baseOffsetSize);
+ if (version == 1 || version == 2) {
+ AVIF_CHECKERR(avifROStreamReadBits8(&s, &indexSize, /*bitCount=*/4), AVIF_RESULT_BMFF_PARSE_FAILED); // unsigned int(4) index_size;
+ } else {
+ AVIF_CHECKERR(avifROStreamReadBits(&s, &reserved, /*bitCount=*/4), AVIF_RESULT_BMFF_PARSE_FAILED); // unsigned int(4) reserved;
+ }
+
+ // Section 8.11.3.3 of ISO/IEC 14496-12.
+ if ((offsetSize != 0 && offsetSize != 4 && offsetSize != 8) || (lengthSize != 0 && lengthSize != 4 && lengthSize != 8) ||
+ (baseOffsetSize != 0 && baseOffsetSize != 4 && baseOffsetSize != 8) || (indexSize != 0 && indexSize != 4 && indexSize != 8)) {
+ avifDiagnosticsPrintf(diag, "Box[iloc] has an invalid size");
return AVIF_RESULT_BMFF_PARSE_FAILED;
}
- uint32_t reserved;
- AVIF_CHECKERR(avifROStreamReadBits(&s, &reserved, /*bitCount=*/4), AVIF_RESULT_BMFF_PARSE_FAILED); // unsigned int(4) reserved;
uint16_t tmp16;
uint32_t itemCount;
@@ -1796,7 +1804,7 @@
return AVIF_RESULT_BMFF_PARSE_FAILED;
}
- if ((version == 1) || (version == 2)) {
+ if (version == 1 || version == 2) {
AVIF_CHECKERR(avifROStreamReadBits(&s, &reserved, /*bitCount=*/12), AVIF_RESULT_BMFF_PARSE_FAILED); // unsigned int(12) reserved = 0;
if (reserved) {
avifDiagnosticsPrintf(diag, "Box[iloc] has a non null reserved field [%u]", reserved);
@@ -1805,8 +1813,8 @@
uint8_t constructionMethod;
AVIF_CHECKERR(avifROStreamReadBits8(&s, &constructionMethod, /*bitCount=*/4),
AVIF_RESULT_BMFF_PARSE_FAILED); // unsigned int(4) construction_method;
- if ((constructionMethod != 0 /* file */) && (constructionMethod != 1 /* idat */)) {
- // construction method item(2) unsupported
+ if (constructionMethod != 0 /* file offset */ && constructionMethod != 1 /* idat offset */) {
+ // construction method item(2) unsupported (item offset)
avifDiagnosticsPrintf(diag, "Box[iloc] has an unsupported construction method [%u]", constructionMethod);
return AVIF_RESULT_BMFF_PARSE_FAILED;
}
@@ -1830,10 +1838,8 @@
uint16_t extentCount; // unsigned int(16) extent_count;
AVIF_CHECKERR(avifROStreamReadU16(&s, &extentCount), AVIF_RESULT_BMFF_PARSE_FAILED); //
for (int extentIter = 0; extentIter < extentCount; ++extentIter) {
- // If extent_index is ever supported, this spec must be implemented here:
- // :: if (((version == 1) || (version == 2)) && (index_size > 0)) {
- // :: unsigned int(index_size*8) extent_index;
- // :: }
+ uint64_t itemReferenceIndex; // unsigned int(index_size*8) item_reference_index; (ignored unless construction_method=2)
+ AVIF_CHECKERR(avifROStreamReadUX8(&s, &itemReferenceIndex, indexSize), AVIF_RESULT_BMFF_PARSE_FAILED);
uint64_t extentOffset; // unsigned int(offset_size*8) extent_offset;
AVIF_CHECKERR(avifROStreamReadUX8(&s, &extentOffset, offsetSize), AVIF_RESULT_BMFF_PARSE_FAILED);