Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(191)

Side by Side Diff: media/formats/mp4/box_reader_unittest.cc

Issue 2643123002: MSE: Fix moar mp4 parsing security bugs. (Closed)
Patch Set: Created 3 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
chcunningham 2017/01/19 22:49:59 This actually was causing a 32 bit overflow (now t
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());
(...skipping 17 matching lines...) Expand all
313 356
314 EXPECT_FALSE(err); 357 EXPECT_FALSE(err);
315 EXPECT_TRUE(reader); 358 EXPECT_TRUE(reader);
316 EXPECT_EQ(FOURCC_SKIP, reader->type()); 359 EXPECT_EQ(FOURCC_SKIP, reader->type());
317 360
318 std::vector<PsshBox> tmp; 361 std::vector<PsshBox> tmp;
319 EXPECT_FALSE(reader->ReadAllChildren(&tmp)); 362 EXPECT_FALSE(reader->ReadAllChildren(&tmp));
320 } 363 }
321 364
322 TEST_F(BoxReaderTest, TrunSampleCount32bitOverflow) { 365 TEST_F(BoxReaderTest, TrunSampleCount32bitOverflow) {
323 // This data is not a valid 'emsg' box. It is just used as a top-level box 366 // This 'trun' box specifies an unusually high sample count, though only one
324 // as ReadTopLevelBox() has a restricted set of boxes it allows. 367 // sample is included in the bytes below. The values for "sample_count" and
325 // The nested 'trun' box specifies an unusually high number of samples, though 368 // "flags" are chosen such that the needed number of bytes will overflow 32
326 // only one sample is actually included in the box. The values for "sample 369 // bits to yield a very small number (4), potentially passing the
327 // count" and "flags" are chosen such that their 32-bit product will overflow 370 // internal check for HasBytes(). http://crbug.com/679640
328 // to a very small number (4), leading to incorrect assumptions about bytes
329 // available and ultimately OOB reads. http://crbug.com/679640
330 static const uint8_t kData[] = { 371 static const uint8_t kData[] = {
331 0x00, 0x00, 0x00, 0x28, 372 0x00, 0x00, 0x00, 0x18, 't', 'r', 'u', 'n', // header
332 'e', 'm', 's', 'g', // outer box 373 0x00, 0x00, // version = 0
333 0x00, 0x00, 0x00, 0x20,
334 't', 'r', 'u', 'n', // nested box
335 0x00, 0x00, // version = 0
336 0x03, 0x00, // flags = 2 fields present (sample duration and sample size) 374 0x03, 0x00, // flags = 2 fields present (sample duration and sample size)
337 0x80, 0x00, 0x00, 0x02, // sample count = 2147483650 375 0x80, 0x00, 0x00, 0x02, // sample count = 2147483650
338 0x00, 0x00, 0x00, 0x00,
339 0x00, 0x00, 0x00, 0x00, // only one sample present 376 0x00, 0x00, 0x00, 0x00, // only one sample present
340 0x00, 0x00, 0x00, 0x00,
341 0x00, 0x00, 0x00, 0x00}; 377 0x00, 0x00, 0x00, 0x00};
342 378
343 bool err; 379 // Verify we catch the overflow to avoid OOB reads/writes.
344 std::unique_ptr<BoxReader> reader( 380 TestParsing32bitOverflow<TrackFragmentRun>(
345 BoxReader::ReadTopLevelBox(kData, sizeof(kData), media_log_, &err)); 381 kData, sizeof(kData),
346 382 "Extreme TRUN sample count exceeds implementation limit.");
347 EXPECT_FALSE(err);
348 EXPECT_TRUE(reader);
349 EXPECT_EQ(FOURCC_EMSG, reader->type());
350
351 // Overflow is only triggered/caught on 32-bit systems. 64-bit systems will
352 // instead fail parsing because kData does not have enough bytes to describe
353 // the large number of samples.
354 #if defined(ARCH_CPU_32_BITS)
355 const int kOverflowLogCount = 1;
356 #else
357 const int kOverflowLogCount = 0;
358 #endif
359
360 EXPECT_MEDIA_LOG(
361 HasSubstr("Extreme TRUN sample count exceeds system address space"))
362 .Times(kOverflowLogCount);
363
364 // Reading the child should fail since the number of samples specified
365 // doesn't match what is in the box.
366 std::vector<TrackFragmentRun> children;
367 EXPECT_FALSE(reader->ReadAllChildrenAndCheckFourCC(&children));
368 } 383 }
369 384
370 TEST_F(BoxReaderTest, SaioCount32bitOverflow) { 385 TEST_F(BoxReaderTest, SaioCount32bitOverflow) {
371 // This data is not a valid 'emsg' box. It is just used as a top-level box 386 // This 'saio' box specifies an unusually high number of offset counts, though
372 // as ReadTopLevelBox() has a restricted set of boxes it allows. 387 // only one offset is included in the bytes below. The values for "count" and
373 // The nested 'saio' box specifies an unusually high number of offset counts, 388 // "version" are chosen such that the needed number of bytes will overflow 32
374 // though only one offset is actually included in the box. The values for 389 // bits to yield a very small number (4), potentially passing the internal
375 // "count" and "version" are chosen such that the needed number of bytes will 390 // check for HasBytes(). http://crbug.com/679641
376 // overflow to a very small number (4), leading to incorrect assumptions about
377 // bytes available and ultimately OOB reads. http://crbug.com/679641
378 static const uint8_t kData[] = { 391 static const uint8_t kData[] = {
379 0x00, 0x00, 0x00, 0x1c, 'e', 'm', 's', 'g', // outer box 392 0x00, 0x00, 0x00, 0x14, 's', 'a', 'i', 'o', // header
380 0x00, 0x00, 0x00, 0x14, 's', 'a', 'i', 'o', // nested box
381 0x00, 0x00, // version = 0 (4 bytes per offset entry) 393 0x00, 0x00, // version = 0 (4 bytes per offset entry)
382 0x00, 0x00, // flags = 0 394 0x00, 0x00, // flags = 0
383 0x40, 0x00, 0x00, 0x01, // offsets count = 1073741825 395 0x40, 0x00, 0x00, 0x01, // offsets count = 1073741825
384 0x00, 0x00, 0x00, 0x00, // single offset entry 396 0x00, 0x00, 0x00, 0x00, // single offset entry
385 }; 397 };
386 398
387 bool err; 399 // Verify we catch the overflow to avoid OOB reads/writes.
388 std::unique_ptr<BoxReader> reader( 400 TestParsing32bitOverflow<SampleAuxiliaryInformationOffset>(
389 BoxReader::ReadTopLevelBox(kData, sizeof(kData), media_log_, &err)); 401 kData, sizeof(kData), "Extreme SAIO count exceeds implementation limit.");
402 }
390 403
391 EXPECT_FALSE(err); 404 TEST_F(BoxReaderTest, ElstCount32bitOverflow) {
392 EXPECT_TRUE(reader); 405 // This 'elst' box specifies an unusually high number of edit counts, though
393 EXPECT_EQ(FOURCC_EMSG, reader->type()); 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 };
394 419
395 // Overflow is only triggered/caught on 32-bit systems. 64-bit systems will 420 // Verify we catch the overflow to avoid OOB reads/writes.
396 // instead fail parsing because kData does not have enough bytes to describe 421 TestParsing32bitOverflow<EditList>(
397 // the large number of samples. 422 kData, sizeof(kData), "Extreme ELST count exceeds implementation limit.");
398 #if defined(ARCH_CPU_32_BITS) 423 }
399 const int kOverflowLogCount = 1;
400 #else
401 const int kOverflowLogCount = 0;
402 #endif
403 424
404 EXPECT_MEDIA_LOG( 425 TEST_F(BoxReaderTest, SbgpCount32bitOverflow) {
405 HasSubstr("Extreme SAIO count exceeds implementation limit.")) 426 // This 'sbgp' box specifies an unusually high count of entries, though only
406 .Times(kOverflowLogCount); 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 };
407 438
408 std::vector<SampleAuxiliaryInformationOffset> children; 439 // Verify we catch the overflow to avoid OOB reads/writes.
409 EXPECT_FALSE(reader->ReadAllChildrenAndCheckFourCC(&children)); 440 TestParsing32bitOverflow<SampleToGroup>(
441 kData, sizeof(kData), "Extreme SBGP count exceeds implementation limit.");
442 }
443
444 TEST_F(BoxReaderTest, SgpdCount32bitOverflow) {
445 LOG(ERROR) << __func__ << "size:" << sizeof(SampleDependsOn);
DaleCurtis 2017/01/19 22:59:30 Drop?
chcunningham 2017/01/19 23:55:31 Done.
446
447 // This 'sgpd' box specifies an unusually high count of entries, though only
448 // one partial entry is included in the bytes below. The value for "count" is
449 // chosen such that we could overflow attempting to allocate the vector for
450 // parsed entries. http://crbug.com/679647
451 static const uint8_t kData[] = {
452 0x00, 0x00, 0x00, 0x1c, 's', 'g', 'p', 'd', // header
453 0x00, 0x00, 0x00, 0x00, // version = 0, flags = 0
454 's', 'e', 'i', 'g', // required grouping "type"
455 0xff, 0xff, 0xff, 0xff, // count = 4294967295
456 0x00, 0x00, 0x00, 0x00, // partial entry
457 0x00, 0x00, 0x00, 0x00,
458 };
459
460 // Verify we catch the overflow to avoid OOB reads/writes.
461 TestParsing32bitOverflow<SampleGroupDescription>(
462 kData, sizeof(kData), "Extreme SGPD count exceeds implementation limit.");
410 } 463 }
411 464
412 } // namespace mp4 465 } // namespace mp4
413 } // namespace media 466 } // namespace media
OLDNEW
« media/formats/mp4/box_definitions.cc ('K') | « media/formats/mp4/box_definitions.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698