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

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

Issue 2654913002: [TO 56] Fix 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
« no previous file with comments | « media/formats/mp4/box_definitions.cc ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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
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
OLDNEW
« no previous file with comments | « media/formats/mp4/box_definitions.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698