From cc20e4a824af52160d2217da675f43348a6e3b4d Mon Sep 17 00:00:00 2001 From: jmestwa-coder Date: Sat, 16 May 2026 16:58:09 +0530 Subject: [PATCH 1/2] Reject oversized BMFF box sizes before serialization --- src/stream.c | 7 ++++--- tests/gtest/avifstreamtest.cc | 37 +++++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 3 deletions(-) diff --git a/src/stream.c b/src/stream.c index 60e6aa384c..349ff029b8 100644 --- a/src/stream.c +++ b/src/stream.c @@ -397,13 +397,11 @@ avifResult avifRWStreamWriteChars(avifRWStream * stream, const char * chars, siz avifResult avifRWStreamWriteFullBox(avifRWStream * stream, const char * type, size_t contentSize, int version, uint32_t flags, avifBoxMarker * marker) { assert(stream->numUsedBitsInPartialByte == 0); // Byte alignment is required. - if (marker) { - *marker = stream->offset; - } size_t headerSize = sizeof(uint32_t) + 4 /* size of type */; if (version != -1) { headerSize += 4; } + AVIF_CHECKERR(contentSize <= UINT32_MAX - headerSize, AVIF_RESULT_INVALID_ARGUMENT); AVIF_CHECKRES(makeRoom(stream, headerSize)); memset(stream->raw->data + stream->offset, 0, headerSize); @@ -416,6 +414,9 @@ avifResult avifRWStreamWriteFullBox(avifRWStream * stream, const char * type, si stream->raw->data[stream->offset + 10] = (uint8_t)((flags >> 8) & 0xff); stream->raw->data[stream->offset + 11] = (uint8_t)((flags >> 0) & 0xff); } + if (marker) { + *marker = stream->offset; + } stream->offset += headerSize; return AVIF_RESULT_OK; diff --git a/tests/gtest/avifstreamtest.cc b/tests/gtest/avifstreamtest.cc index 199b8bef12..199bf6e79e 100644 --- a/tests/gtest/avifstreamtest.cc +++ b/tests/gtest/avifstreamtest.cc @@ -202,6 +202,43 @@ TEST(StreamTest, WriteBitsLimit) { AVIF_RESULT_INVALID_ARGUMENT); } +TEST(StreamTest, WriteBoxSizeLimit) { + testutil::AvifRwData rw_data; + avifRWStream rw_stream; + avifRWStreamStart(&rw_stream, &rw_data); + const char box_type[] = "type"; + avifBoxMarker marker = 123; + + EXPECT_EQ(avifRWStreamWriteBox(&rw_stream, box_type, + std::numeric_limits::max() - + sizeof(uint32_t) - 4, + &marker), + AVIF_RESULT_OK); + EXPECT_EQ(marker, size_t{0}); + EXPECT_EQ(avifRWStreamOffset(&rw_stream), sizeof(uint32_t) + 4); + + EXPECT_EQ(avifRWStreamWriteBox(&rw_stream, box_type, + std::numeric_limits::max() - + sizeof(uint32_t) - 3, + &marker), + AVIF_RESULT_INVALID_ARGUMENT); + + EXPECT_EQ(avifRWStreamWriteFullBox( + &rw_stream, box_type, + std::numeric_limits::max() - sizeof(uint32_t) - 8, + /*version=*/0, /*flags=*/0, &marker), + AVIF_RESULT_OK); + EXPECT_EQ(marker, sizeof(uint32_t) + 4); + EXPECT_EQ(avifRWStreamOffset(&rw_stream), 2 * (sizeof(uint32_t) + 4) + 4); + + EXPECT_EQ(avifRWStreamWriteFullBox( + &rw_stream, box_type, + std::numeric_limits::max() - sizeof(uint32_t) - 7, + /*version=*/0, /*flags=*/0, &marker), + AVIF_RESULT_INVALID_ARGUMENT); + EXPECT_EQ(avifRWStreamOffset(&rw_stream), 2 * (sizeof(uint32_t) + 4) + 4); +} + // Test the overflow checks in the makeRoom() function in src/stream.c. TEST(StreamTest, OverflowChecksInMakeRoom) { testutil::AvifRwData rw_data; From 9a5bf546d4f6ee4cc3500bacfd8a5e9301216cca Mon Sep 17 00:00:00 2001 From: jmestwa-coder Date: Sat, 16 May 2026 16:58:09 +0530 Subject: [PATCH 2/2] Reject oversized BMFF box sizes before serialization --- src/stream.c | 7 ++++--- tests/gtest/avifstreamtest.cc | 37 +++++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 3 deletions(-) diff --git a/src/stream.c b/src/stream.c index 60e6aa384c..349ff029b8 100644 --- a/src/stream.c +++ b/src/stream.c @@ -397,13 +397,11 @@ avifResult avifRWStreamWriteChars(avifRWStream * stream, const char * chars, siz avifResult avifRWStreamWriteFullBox(avifRWStream * stream, const char * type, size_t contentSize, int version, uint32_t flags, avifBoxMarker * marker) { assert(stream->numUsedBitsInPartialByte == 0); // Byte alignment is required. - if (marker) { - *marker = stream->offset; - } size_t headerSize = sizeof(uint32_t) + 4 /* size of type */; if (version != -1) { headerSize += 4; } + AVIF_CHECKERR(contentSize <= UINT32_MAX - headerSize, AVIF_RESULT_INVALID_ARGUMENT); AVIF_CHECKRES(makeRoom(stream, headerSize)); memset(stream->raw->data + stream->offset, 0, headerSize); @@ -416,6 +414,9 @@ avifResult avifRWStreamWriteFullBox(avifRWStream * stream, const char * type, si stream->raw->data[stream->offset + 10] = (uint8_t)((flags >> 8) & 0xff); stream->raw->data[stream->offset + 11] = (uint8_t)((flags >> 0) & 0xff); } + if (marker) { + *marker = stream->offset; + } stream->offset += headerSize; return AVIF_RESULT_OK; diff --git a/tests/gtest/avifstreamtest.cc b/tests/gtest/avifstreamtest.cc index 199b8bef12..417918727c 100644 --- a/tests/gtest/avifstreamtest.cc +++ b/tests/gtest/avifstreamtest.cc @@ -202,6 +202,43 @@ TEST(StreamTest, WriteBitsLimit) { AVIF_RESULT_INVALID_ARGUMENT); } +TEST(StreamTest, WriteBoxSizeLimit) { + testutil::AvifRwData rw_data; + avifRWStream rw_stream; + avifRWStreamStart(&rw_stream, &rw_data); + const char box_type[] = "type"; + avifBoxMarker marker = 123; + + EXPECT_EQ( + avifRWStreamWriteBox( + &rw_stream, box_type, + std::numeric_limits::max() - sizeof(uint32_t) - 4, &marker), + AVIF_RESULT_OK); + EXPECT_EQ(marker, size_t{0}); + EXPECT_EQ(avifRWStreamOffset(&rw_stream), sizeof(uint32_t) + 4); + + EXPECT_EQ( + avifRWStreamWriteBox( + &rw_stream, box_type, + std::numeric_limits::max() - sizeof(uint32_t) - 3, &marker), + AVIF_RESULT_INVALID_ARGUMENT); + + EXPECT_EQ(avifRWStreamWriteFullBox( + &rw_stream, box_type, + std::numeric_limits::max() - sizeof(uint32_t) - 8, + /*version=*/0, /*flags=*/0, &marker), + AVIF_RESULT_OK); + EXPECT_EQ(marker, sizeof(uint32_t) + 4); + EXPECT_EQ(avifRWStreamOffset(&rw_stream), 2 * (sizeof(uint32_t) + 4) + 4); + + EXPECT_EQ(avifRWStreamWriteFullBox( + &rw_stream, box_type, + std::numeric_limits::max() - sizeof(uint32_t) - 7, + /*version=*/0, /*flags=*/0, &marker), + AVIF_RESULT_INVALID_ARGUMENT); + EXPECT_EQ(avifRWStreamOffset(&rw_stream), 2 * (sizeof(uint32_t) + 4) + 4); +} + // Test the overflow checks in the makeRoom() function in src/stream.c. TEST(StreamTest, OverflowChecksInMakeRoom) { testutil::AvifRwData rw_data;