| Index: media/formats/mp4/box_reader_unittest.cc
|
| diff --git a/media/formats/mp4/box_reader_unittest.cc b/media/formats/mp4/box_reader_unittest.cc
|
| index 09df3d7f3d36c3f88a5b6da421ff559512435442..818d80767fdd2766111275f1cc43fd2ed12ef162 100644
|
| --- a/media/formats/mp4/box_reader_unittest.cc
|
| +++ b/media/formats/mp4/box_reader_unittest.cc
|
| @@ -103,6 +103,51 @@ class BoxReaderTest : public testing::Test {
|
| EXPECT_EQ(reader->box_size(), data_size);
|
| }
|
|
|
| + template <typename ChildType>
|
| + void TestParsing32bitOverflow(const uint8_t* buffer,
|
| + size_t size,
|
| + const std::string& overflow_error) {
|
| + // Wrap whatever we're passed in a dummy EMSG so we can satisfy requirements
|
| + // for ReadTopLevelBox and to kick off parsing.
|
| + std::vector<uint8_t> buffer_wrapper = {
|
| + 0x00, 0x00, 0x00, 0x00, // dummy size
|
| + 'e', 'm', 's', 'g', // fourcc
|
| + };
|
| + buffer_wrapper.insert(buffer_wrapper.end(), buffer, buffer + size);
|
| +
|
| + // Basic check of the nested buffer size. If box_size > buffer size the test
|
| + // will exit early (waiting for more bytes to be appended).
|
| + ASSERT_TRUE(base::IsValueInRangeForNumericType<uint8_t>(size));
|
| + ASSERT_LE(buffer[3], size);
|
| +
|
| + // Update the size (keep it simple).
|
| + ASSERT_TRUE(
|
| + base::IsValueInRangeForNumericType<uint8_t>(buffer_wrapper.size()));
|
| + buffer_wrapper[3] = buffer_wrapper.size();
|
| +
|
| + bool err;
|
| + std::unique_ptr<BoxReader> reader(BoxReader::ReadTopLevelBox(
|
| + &buffer_wrapper[0], buffer_wrapper.size(), media_log_, &err));
|
| + EXPECT_FALSE(err);
|
| + EXPECT_TRUE(reader);
|
| + EXPECT_EQ(FOURCC_EMSG, reader->type());
|
| +
|
| +// Overflow is only triggered/caught on 32-bit systems. 64-bit systems will
|
| +// instead fail parsing because tests are written such that |buffer| never
|
| +// contains enough bytes for parsing to succeed.
|
| +#if defined(ARCH_CPU_32_BITS)
|
| + const int kOverflowLogCount = 1;
|
| +#else
|
| + const int kOverflowLogCount = 0;
|
| +#endif
|
| +
|
| + if (!overflow_error.empty())
|
| + EXPECT_MEDIA_LOG(HasSubstr(overflow_error)).Times(kOverflowLogCount);
|
| +
|
| + std::vector<ChildType> children;
|
| + EXPECT_FALSE(reader->ReadAllChildrenAndCheckFourCC(&children));
|
| + }
|
| +
|
| scoped_refptr<StrictMock<MockMediaLog>> media_log_;
|
| };
|
|
|
| @@ -276,13 +321,11 @@ TEST_F(BoxReaderTest, ScanChildrenWithInvalidChild) {
|
| // The sample specifies a large number of EditListEntry's, but only 1 is
|
| // actually included in the box. This test verifies that the code checks
|
| // properly that the buffer contains the specified number of EditListEntry's
|
| - // (does not cause an int32_t overflow when checking that the bytes are
|
| - // available, and does not read past the end of the buffer).
|
| static const uint8_t kData[] = {
|
| 0x00, 0x00, 0x00, 0x2c, 'e', 'm', 's', 'g', // outer box
|
| 0x00, 0x00, 0x00, 0x24, 'e', 'l', 's', 't', // nested box
|
| 0x01, 0x00, 0x00, 0x00, // version = 1, flags = 0
|
| - 0xff, 0xff, 0xff, 0xff, // count = max, but only 1 actually included
|
| + 0x00, 0x00, 0x00, 0x0a, // count = 10, but only 1 actually included
|
| 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
| 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
|
|
| @@ -301,36 +344,6 @@ TEST_F(BoxReaderTest, ScanChildrenWithInvalidChild) {
|
| EXPECT_FALSE(reader->ReadChild(&child));
|
| }
|
|
|
| -TEST_F(BoxReaderTest, ReadAllChildrenWithInvalidChild) {
|
| - // This data is not a valid 'emsg' box. It is just used as a top-level box
|
| - // as ReadTopLevelBox() has a restricted set of boxes it allows.
|
| - // The nested 'trun' box is used as it includes a count of the number
|
| - // of samples. The data specifies a large number of samples, but only 1
|
| - // is actually included in the box. Verifying that the large count does not
|
| - // cause an int32_t overflow which would allow parsing of TrackFragmentRun
|
| - // to read past the end of the buffer.
|
| - static const uint8_t kData[] = {
|
| - 0x00, 0x00, 0x00, 0x28, 'e', 'm', 's', 'g', // outer box
|
| - 0x00, 0x00, 0x00, 0x20, 't', 'r', 'u', 'n', // nested box
|
| - 0x00, 0x00, 0x0f, 0x00, // version = 0, flags = samples present
|
| - 0xff, 0xff, 0xff, 0xff, // count = max, but only 1 actually included
|
| - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
| - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
| -
|
| - bool err;
|
| - std::unique_ptr<BoxReader> reader(
|
| - BoxReader::ReadTopLevelBox(kData, sizeof(kData), media_log_, &err));
|
| -
|
| - EXPECT_FALSE(err);
|
| - EXPECT_TRUE(reader);
|
| - EXPECT_EQ(FOURCC_EMSG, reader->type());
|
| -
|
| - // Reading the child should fail since the number of samples specified
|
| - // doesn't match what is in the box.
|
| - std::vector<TrackFragmentRun> children;
|
| - EXPECT_FALSE(reader->ReadAllChildrenAndCheckFourCC(&children));
|
| -}
|
| -
|
| TEST_F(BoxReaderTest, ReadAllChildrenWithChildLargerThanParent) {
|
| static const uint8_t kData[] = {
|
| 0x00, 0x00, 0x00, 0x10, 's', 'k', 'i', 'p', // outer box
|
| @@ -349,5 +362,103 @@ TEST_F(BoxReaderTest, ReadAllChildrenWithChildLargerThanParent) {
|
| EXPECT_FALSE(reader->ReadAllChildren(&tmp));
|
| }
|
|
|
| +TEST_F(BoxReaderTest, TrunSampleCount32bitOverflow) {
|
| + // This 'trun' box specifies an unusually high sample count, though only one
|
| + // sample is included in the bytes below. The values for "sample_count" and
|
| + // "flags" are chosen such that the needed number of bytes will overflow 32
|
| + // bits to yield a very small number (4), potentially passing the
|
| + // internal check for HasBytes(). http://crbug.com/679640
|
| + static const uint8_t kData[] = {
|
| + 0x00, 0x00, 0x00, 0x18, 't', 'r', 'u', 'n', // header
|
| + 0x00, 0x00, // version = 0
|
| + 0x03, 0x00, // flags = 2 fields present (sample duration and sample size)
|
| + 0x80, 0x00, 0x00, 0x02, // sample count = 2147483650
|
| + 0x00, 0x00, 0x00, 0x00, // only one sample present
|
| + 0x00, 0x00, 0x00, 0x00};
|
| +
|
| + // Verify we catch the overflow to avoid OOB reads/writes.
|
| + TestParsing32bitOverflow<TrackFragmentRun>(
|
| + kData, sizeof(kData),
|
| + "Extreme TRUN sample count exceeds implementation limit.");
|
| +}
|
| +
|
| +TEST_F(BoxReaderTest, SaioCount32bitOverflow) {
|
| + // This 'saio' box specifies an unusually high number of offset counts, though
|
| + // only one offset is included in the bytes below. The values for "count" and
|
| + // "version" are chosen such that the needed number of bytes will overflow 32
|
| + // bits to yield a very small number (4), potentially passing the internal
|
| + // check for HasBytes(). http://crbug.com/679641
|
| + static const uint8_t kData[] = {
|
| + 0x00, 0x00, 0x00, 0x14, 's', 'a', 'i', 'o', // header
|
| + 0x00, 0x00, // version = 0 (4 bytes per offset entry)
|
| + 0x00, 0x00, // flags = 0
|
| + 0x40, 0x00, 0x00, 0x01, // offsets count = 1073741825
|
| + 0x00, 0x00, 0x00, 0x00, // single offset entry
|
| + };
|
| +
|
| + // Verify we catch the overflow to avoid OOB reads/writes.
|
| + TestParsing32bitOverflow<SampleAuxiliaryInformationOffset>(
|
| + kData, sizeof(kData), "Extreme SAIO count exceeds implementation limit.");
|
| +}
|
| +
|
| +TEST_F(BoxReaderTest, ElstCount32bitOverflow) {
|
| + // This 'elst' box specifies an unusually high number of edit counts, though
|
| + // only one edit is included in the bytes below. The values for "count" and
|
| + // "version" are chosen such that the needed number of bytes will overflow 32
|
| + // bits to yield a very small number (12), potentially passing the internal
|
| + // check for HasBytes(). http://crbug.com/679645
|
| + static const uint8_t kData[] = {
|
| + 0x00, 0x00, 0x00, 0x1c, 'e', 'l', 's', 't', // header
|
| + 0x00, 0x00, // version = 0 (12 bytes per edit entry)
|
| + 0x00, 0x00, // flags = 0
|
| + 0x80, 0x00, 0x00, 0x01, // edits count = 2147483649
|
| + 0x00, 0x00, 0x00, 0x00, // single edit entry
|
| + 0x00, 0x00, 0x00, 0x00, // ...
|
| + 0x00, 0x00, 0x00, 0x00,
|
| + };
|
| +
|
| + // Verify we catch the overflow to avoid OOB reads/writes.
|
| + TestParsing32bitOverflow<EditList>(
|
| + kData, sizeof(kData), "Extreme ELST count exceeds implementation limit.");
|
| +}
|
| +
|
| +TEST_F(BoxReaderTest, SbgpCount32bitOverflow) {
|
| + // This 'sbgp' box specifies an unusually high count of entries, though only
|
| + // one partial entry is included in the bytes below. The value for "count" is
|
| + // chosen such that we could overflow attempting to allocate the vector for
|
| + // parsed entries. http://crbug.com/679646
|
| + static const uint8_t kData[] = {
|
| + 0x00, 0x00, 0x00, 0x1c, 's', 'b', 'g', 'p', // header
|
| + 0x00, 0x00, 0x00, 0x00, // version = 0, flags = 0
|
| + 's', 'e', 'i', 'g', // required grouping "type"
|
| + 0xff, 0xff, 0xff, 0xff, // count = 4294967295
|
| + 0x00, 0x00, 0x00, 0x00, // partial entry
|
| + 0x00, 0x00, 0x00, 0x00,
|
| + };
|
| +
|
| + // Verify we catch the overflow to avoid OOB reads/writes.
|
| + TestParsing32bitOverflow<SampleToGroup>(
|
| + kData, sizeof(kData), "Extreme SBGP count exceeds implementation limit.");
|
| +}
|
| +
|
| +TEST_F(BoxReaderTest, SgpdCount32bitOverflow) {
|
| + // This 'sgpd' box specifies an unusually high count of entries, though only
|
| + // one partial entry is included in the bytes below. The value for "count" is
|
| + // chosen such that we could overflow attempting to allocate the vector for
|
| + // parsed entries. http://crbug.com/679647
|
| + static const uint8_t kData[] = {
|
| + 0x00, 0x00, 0x00, 0x1c, 's', 'g', 'p', 'd', // header
|
| + 0x00, 0x00, 0x00, 0x00, // version = 0, flags = 0
|
| + 's', 'e', 'i', 'g', // required grouping "type"
|
| + 0xff, 0xff, 0xff, 0xff, // count = 4294967295
|
| + 0x00, 0x00, 0x00, 0x00, // partial entry
|
| + 0x00, 0x00, 0x00, 0x00,
|
| + };
|
| +
|
| + // Verify we catch the overflow to avoid OOB reads/writes.
|
| + TestParsing32bitOverflow<SampleGroupDescription>(
|
| + kData, sizeof(kData), "Extreme SGPD count exceeds implementation limit.");
|
| +}
|
| +
|
| } // namespace mp4
|
| } // namespace media
|
|
|