OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "media/formats/mp4/box_reader.h" | 5 #include "media/formats/mp4/box_reader.h" |
6 | 6 |
7 #include <stdint.h> | 7 #include <stdint.h> |
8 #include <string.h> | 8 #include <string.h> |
9 | 9 |
10 #include <memory> | 10 #include <memory> |
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
96 bool err; | 96 bool err; |
97 std::unique_ptr<BoxReader> reader( | 97 std::unique_ptr<BoxReader> reader( |
98 BoxReader::ReadTopLevelBox(&buf[0], buf.size(), media_log_, &err)); | 98 BoxReader::ReadTopLevelBox(&buf[0], buf.size(), media_log_, &err)); |
99 | 99 |
100 EXPECT_FALSE(err); | 100 EXPECT_FALSE(err); |
101 EXPECT_TRUE(reader); | 101 EXPECT_TRUE(reader); |
102 EXPECT_EQ(fourCC, reader->type()); | 102 EXPECT_EQ(fourCC, reader->type()); |
103 EXPECT_EQ(reader->box_size(), data_size); | 103 EXPECT_EQ(reader->box_size(), data_size); |
104 } | 104 } |
105 | 105 |
| 106 template <typename ChildType> |
| 107 void TestParsing32bitOverflow(const uint8_t* buffer, |
| 108 size_t size, |
| 109 const std::string& overflow_error) { |
| 110 // Wrap whatever we're passed in a dummy EMSG so we can satisfy requirements |
| 111 // for ReadTopLevelBox and to kick off parsing. |
| 112 std::vector<uint8_t> buffer_wrapper = { |
| 113 0x00, 0x00, 0x00, 0x00, // dummy size |
| 114 'e', 'm', 's', 'g', // fourcc |
| 115 }; |
| 116 buffer_wrapper.insert(buffer_wrapper.end(), buffer, buffer + size); |
| 117 |
| 118 // Basic check of the nested buffer size. If box_size > buffer size the test |
| 119 // will exit early (waiting for more bytes to be appended). |
| 120 ASSERT_TRUE(base::IsValueInRangeForNumericType<uint8_t>(size)); |
| 121 ASSERT_LE(buffer[3], size); |
| 122 |
| 123 // Update the size (keep it simple). |
| 124 ASSERT_TRUE( |
| 125 base::IsValueInRangeForNumericType<uint8_t>(buffer_wrapper.size())); |
| 126 buffer_wrapper[3] = buffer_wrapper.size(); |
| 127 |
| 128 bool err; |
| 129 std::unique_ptr<BoxReader> reader(BoxReader::ReadTopLevelBox( |
| 130 &buffer_wrapper[0], buffer_wrapper.size(), media_log_, &err)); |
| 131 EXPECT_FALSE(err); |
| 132 EXPECT_TRUE(reader); |
| 133 EXPECT_EQ(FOURCC_EMSG, reader->type()); |
| 134 |
| 135 // Overflow is only triggered/caught on 32-bit systems. 64-bit systems will |
| 136 // instead fail parsing because tests are written such that |buffer| never |
| 137 // contains enough bytes for parsing to succeed. |
| 138 #if defined(ARCH_CPU_32_BITS) |
| 139 const int kOverflowLogCount = 1; |
| 140 #else |
| 141 const int kOverflowLogCount = 0; |
| 142 #endif |
| 143 |
| 144 if (!overflow_error.empty()) |
| 145 EXPECT_MEDIA_LOG(HasSubstr(overflow_error)).Times(kOverflowLogCount); |
| 146 |
| 147 std::vector<ChildType> children; |
| 148 EXPECT_FALSE(reader->ReadAllChildrenAndCheckFourCC(&children)); |
| 149 } |
| 150 |
106 scoped_refptr<StrictMock<MockMediaLog>> media_log_; | 151 scoped_refptr<StrictMock<MockMediaLog>> media_log_; |
107 }; | 152 }; |
108 | 153 |
109 TEST_F(BoxReaderTest, ExpectedOperationTest) { | 154 TEST_F(BoxReaderTest, ExpectedOperationTest) { |
110 std::vector<uint8_t> buf = GetBuf(); | 155 std::vector<uint8_t> buf = GetBuf(); |
111 bool err; | 156 bool err; |
112 std::unique_ptr<BoxReader> reader( | 157 std::unique_ptr<BoxReader> reader( |
113 BoxReader::ReadTopLevelBox(&buf[0], buf.size(), media_log_, &err)); | 158 BoxReader::ReadTopLevelBox(&buf[0], buf.size(), media_log_, &err)); |
114 EXPECT_FALSE(err); | 159 EXPECT_FALSE(err); |
115 EXPECT_TRUE(reader.get()); | 160 EXPECT_TRUE(reader.get()); |
(...skipping 153 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
269 EXPECT_FALSE(reader->ScanChildren()); | 314 EXPECT_FALSE(reader->ScanChildren()); |
270 } | 315 } |
271 | 316 |
272 TEST_F(BoxReaderTest, ScanChildrenWithInvalidChild) { | 317 TEST_F(BoxReaderTest, ScanChildrenWithInvalidChild) { |
273 // This data is not a valid 'emsg' box. It is just used as a top-level box | 318 // This data is not a valid 'emsg' box. It is just used as a top-level box |
274 // as ReadTopLevelBox() has a restricted set of boxes it allows. | 319 // as ReadTopLevelBox() has a restricted set of boxes it allows. |
275 // The nested 'elst' box is used as it includes a count of EditListEntry's. | 320 // The nested 'elst' box is used as it includes a count of EditListEntry's. |
276 // The sample specifies a large number of EditListEntry's, but only 1 is | 321 // The sample specifies a large number of EditListEntry's, but only 1 is |
277 // actually included in the box. This test verifies that the code checks | 322 // actually included in the box. This test verifies that the code checks |
278 // properly that the buffer contains the specified number of EditListEntry's | 323 // properly that the buffer contains the specified number of EditListEntry's |
279 // (does not cause an int32_t overflow when checking that the bytes are | |
280 // available, and does not read past the end of the buffer). | |
281 static const uint8_t kData[] = { | 324 static const uint8_t kData[] = { |
282 0x00, 0x00, 0x00, 0x2c, 'e', 'm', 's', 'g', // outer box | 325 0x00, 0x00, 0x00, 0x2c, 'e', 'm', 's', 'g', // outer box |
283 0x00, 0x00, 0x00, 0x24, 'e', 'l', 's', 't', // nested box | 326 0x00, 0x00, 0x00, 0x24, 'e', 'l', 's', 't', // nested box |
284 0x01, 0x00, 0x00, 0x00, // version = 1, flags = 0 | 327 0x01, 0x00, 0x00, 0x00, // version = 1, flags = 0 |
285 0xff, 0xff, 0xff, 0xff, // count = max, but only 1 actually included | 328 0x00, 0x00, 0x00, 0x0a, // count = 10, but only 1 actually included |
286 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 329 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
287 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; | 330 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; |
288 | 331 |
289 bool err; | 332 bool err; |
290 std::unique_ptr<BoxReader> reader( | 333 std::unique_ptr<BoxReader> reader( |
291 BoxReader::ReadTopLevelBox(kData, sizeof(kData), media_log_, &err)); | 334 BoxReader::ReadTopLevelBox(kData, sizeof(kData), media_log_, &err)); |
292 | 335 |
293 EXPECT_FALSE(err); | 336 EXPECT_FALSE(err); |
294 EXPECT_TRUE(reader); | 337 EXPECT_TRUE(reader); |
295 EXPECT_EQ(FOURCC_EMSG, reader->type()); | 338 EXPECT_EQ(FOURCC_EMSG, reader->type()); |
296 EXPECT_TRUE(reader->ScanChildren()); | 339 EXPECT_TRUE(reader->ScanChildren()); |
297 | 340 |
298 // 'elst' specifies lots of EditListEntry's but only includes 1. Thus | 341 // 'elst' specifies lots of EditListEntry's but only includes 1. Thus |
299 // parsing it should fail. | 342 // parsing it should fail. |
300 EditList child; | 343 EditList child; |
301 EXPECT_FALSE(reader->ReadChild(&child)); | 344 EXPECT_FALSE(reader->ReadChild(&child)); |
302 } | 345 } |
303 | 346 |
304 TEST_F(BoxReaderTest, ReadAllChildrenWithInvalidChild) { | |
305 // This data is not a valid 'emsg' box. It is just used as a top-level box | |
306 // as ReadTopLevelBox() has a restricted set of boxes it allows. | |
307 // The nested 'trun' box is used as it includes a count of the number | |
308 // of samples. The data specifies a large number of samples, but only 1 | |
309 // is actually included in the box. Verifying that the large count does not | |
310 // cause an int32_t overflow which would allow parsing of TrackFragmentRun | |
311 // to read past the end of the buffer. | |
312 static const uint8_t kData[] = { | |
313 0x00, 0x00, 0x00, 0x28, 'e', 'm', 's', 'g', // outer box | |
314 0x00, 0x00, 0x00, 0x20, 't', 'r', 'u', 'n', // nested box | |
315 0x00, 0x00, 0x0f, 0x00, // version = 0, flags = samples present | |
316 0xff, 0xff, 0xff, 0xff, // count = max, but only 1 actually included | |
317 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
318 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; | |
319 | |
320 bool err; | |
321 std::unique_ptr<BoxReader> reader( | |
322 BoxReader::ReadTopLevelBox(kData, sizeof(kData), media_log_, &err)); | |
323 | |
324 EXPECT_FALSE(err); | |
325 EXPECT_TRUE(reader); | |
326 EXPECT_EQ(FOURCC_EMSG, reader->type()); | |
327 | |
328 // Reading the child should fail since the number of samples specified | |
329 // doesn't match what is in the box. | |
330 std::vector<TrackFragmentRun> children; | |
331 EXPECT_FALSE(reader->ReadAllChildrenAndCheckFourCC(&children)); | |
332 } | |
333 | |
334 TEST_F(BoxReaderTest, ReadAllChildrenWithChildLargerThanParent) { | 347 TEST_F(BoxReaderTest, ReadAllChildrenWithChildLargerThanParent) { |
335 static const uint8_t kData[] = { | 348 static const uint8_t kData[] = { |
336 0x00, 0x00, 0x00, 0x10, 's', 'k', 'i', 'p', // outer box | 349 0x00, 0x00, 0x00, 0x10, 's', 'k', 'i', 'p', // outer box |
337 0x00, 0x00, 0x00, 0x10, 'p', 's', 's', 'h', // nested box | 350 0x00, 0x00, 0x00, 0x10, 'p', 's', 's', 'h', // nested box |
338 }; | 351 }; |
339 | 352 |
340 bool err; | 353 bool err; |
341 std::unique_ptr<BoxReader> reader( | 354 std::unique_ptr<BoxReader> reader( |
342 BoxReader::ReadTopLevelBox(kData, sizeof(kData), media_log_, &err)); | 355 BoxReader::ReadTopLevelBox(kData, sizeof(kData), media_log_, &err)); |
343 | 356 |
344 EXPECT_FALSE(err); | 357 EXPECT_FALSE(err); |
345 EXPECT_TRUE(reader); | 358 EXPECT_TRUE(reader); |
346 EXPECT_EQ(FOURCC_SKIP, reader->type()); | 359 EXPECT_EQ(FOURCC_SKIP, reader->type()); |
347 | 360 |
348 std::vector<PsshBox> tmp; | 361 std::vector<PsshBox> tmp; |
349 EXPECT_FALSE(reader->ReadAllChildren(&tmp)); | 362 EXPECT_FALSE(reader->ReadAllChildren(&tmp)); |
350 } | 363 } |
351 | 364 |
| 365 TEST_F(BoxReaderTest, TrunSampleCount32bitOverflow) { |
| 366 // This 'trun' box specifies an unusually high sample count, though only one |
| 367 // sample is included in the bytes below. The values for "sample_count" and |
| 368 // "flags" are chosen such that the needed number of bytes will overflow 32 |
| 369 // bits to yield a very small number (4), potentially passing the |
| 370 // internal check for HasBytes(). http://crbug.com/679640 |
| 371 static const uint8_t kData[] = { |
| 372 0x00, 0x00, 0x00, 0x18, 't', 'r', 'u', 'n', // header |
| 373 0x00, 0x00, // version = 0 |
| 374 0x03, 0x00, // flags = 2 fields present (sample duration and sample size) |
| 375 0x80, 0x00, 0x00, 0x02, // sample count = 2147483650 |
| 376 0x00, 0x00, 0x00, 0x00, // only one sample present |
| 377 0x00, 0x00, 0x00, 0x00}; |
| 378 |
| 379 // Verify we catch the overflow to avoid OOB reads/writes. |
| 380 TestParsing32bitOverflow<TrackFragmentRun>( |
| 381 kData, sizeof(kData), |
| 382 "Extreme TRUN sample count exceeds implementation limit."); |
| 383 } |
| 384 |
| 385 TEST_F(BoxReaderTest, SaioCount32bitOverflow) { |
| 386 // This 'saio' box specifies an unusually high number of offset counts, though |
| 387 // only one offset is included in the bytes below. The values for "count" and |
| 388 // "version" are chosen such that the needed number of bytes will overflow 32 |
| 389 // bits to yield a very small number (4), potentially passing the internal |
| 390 // check for HasBytes(). http://crbug.com/679641 |
| 391 static const uint8_t kData[] = { |
| 392 0x00, 0x00, 0x00, 0x14, 's', 'a', 'i', 'o', // header |
| 393 0x00, 0x00, // version = 0 (4 bytes per offset entry) |
| 394 0x00, 0x00, // flags = 0 |
| 395 0x40, 0x00, 0x00, 0x01, // offsets count = 1073741825 |
| 396 0x00, 0x00, 0x00, 0x00, // single offset entry |
| 397 }; |
| 398 |
| 399 // Verify we catch the overflow to avoid OOB reads/writes. |
| 400 TestParsing32bitOverflow<SampleAuxiliaryInformationOffset>( |
| 401 kData, sizeof(kData), "Extreme SAIO count exceeds implementation limit."); |
| 402 } |
| 403 |
| 404 TEST_F(BoxReaderTest, ElstCount32bitOverflow) { |
| 405 // This 'elst' box specifies an unusually high number of edit counts, though |
| 406 // only one edit is included in the bytes below. The values for "count" and |
| 407 // "version" are chosen such that the needed number of bytes will overflow 32 |
| 408 // bits to yield a very small number (12), potentially passing the internal |
| 409 // check for HasBytes(). http://crbug.com/679645 |
| 410 static const uint8_t kData[] = { |
| 411 0x00, 0x00, 0x00, 0x1c, 'e', 'l', 's', 't', // header |
| 412 0x00, 0x00, // version = 0 (12 bytes per edit entry) |
| 413 0x00, 0x00, // flags = 0 |
| 414 0x80, 0x00, 0x00, 0x01, // edits count = 2147483649 |
| 415 0x00, 0x00, 0x00, 0x00, // single edit entry |
| 416 0x00, 0x00, 0x00, 0x00, // ... |
| 417 0x00, 0x00, 0x00, 0x00, |
| 418 }; |
| 419 |
| 420 // Verify we catch the overflow to avoid OOB reads/writes. |
| 421 TestParsing32bitOverflow<EditList>( |
| 422 kData, sizeof(kData), "Extreme ELST count exceeds implementation limit."); |
| 423 } |
| 424 |
| 425 TEST_F(BoxReaderTest, SbgpCount32bitOverflow) { |
| 426 // This 'sbgp' box specifies an unusually high count of entries, though only |
| 427 // one partial entry is included in the bytes below. The value for "count" is |
| 428 // chosen such that we could overflow attempting to allocate the vector for |
| 429 // parsed entries. http://crbug.com/679646 |
| 430 static const uint8_t kData[] = { |
| 431 0x00, 0x00, 0x00, 0x1c, 's', 'b', 'g', 'p', // header |
| 432 0x00, 0x00, 0x00, 0x00, // version = 0, flags = 0 |
| 433 's', 'e', 'i', 'g', // required grouping "type" |
| 434 0xff, 0xff, 0xff, 0xff, // count = 4294967295 |
| 435 0x00, 0x00, 0x00, 0x00, // partial entry |
| 436 0x00, 0x00, 0x00, 0x00, |
| 437 }; |
| 438 |
| 439 // Verify we catch the overflow to avoid OOB reads/writes. |
| 440 TestParsing32bitOverflow<SampleToGroup>( |
| 441 kData, sizeof(kData), "Extreme SBGP count exceeds implementation limit."); |
| 442 } |
| 443 |
| 444 TEST_F(BoxReaderTest, SgpdCount32bitOverflow) { |
| 445 // This 'sgpd' box specifies an unusually high count of entries, though only |
| 446 // one partial entry is included in the bytes below. The value for "count" is |
| 447 // chosen such that we could overflow attempting to allocate the vector for |
| 448 // parsed entries. http://crbug.com/679647 |
| 449 static const uint8_t kData[] = { |
| 450 0x00, 0x00, 0x00, 0x1c, 's', 'g', 'p', 'd', // header |
| 451 0x00, 0x00, 0x00, 0x00, // version = 0, flags = 0 |
| 452 's', 'e', 'i', 'g', // required grouping "type" |
| 453 0xff, 0xff, 0xff, 0xff, // count = 4294967295 |
| 454 0x00, 0x00, 0x00, 0x00, // partial entry |
| 455 0x00, 0x00, 0x00, 0x00, |
| 456 }; |
| 457 |
| 458 // Verify we catch the overflow to avoid OOB reads/writes. |
| 459 TestParsing32bitOverflow<SampleGroupDescription>( |
| 460 kData, sizeof(kData), "Extreme SGPD count exceeds implementation limit."); |
| 461 } |
| 462 |
352 } // namespace mp4 | 463 } // namespace mp4 |
353 } // namespace media | 464 } // namespace media |
OLD | NEW |