Index: media/formats/mp4/box_definitions.cc |
diff --git a/media/formats/mp4/box_definitions.cc b/media/formats/mp4/box_definitions.cc |
index 73138d300362ffb0254c0f3f6c12b642430f1392..fd00f9c1b550854df75c4d14a9bd6313eb8465ba 100644 |
--- a/media/formats/mp4/box_definitions.cc |
+++ b/media/formats/mp4/box_definitions.cc |
@@ -9,6 +9,7 @@ |
#include "base/command_line.h" |
#include "base/logging.h" |
+#include "base/numerics/safe_math.h" |
#include "base/strings/string_number_conversions.h" |
#include "media/base/media_switches.h" |
#include "media/base/video_types.h" |
@@ -117,8 +118,17 @@ bool SampleAuxiliaryInformationOffset::Parse(BoxReader* reader) { |
RCHECK(reader->SkipBytes(8)); |
uint32_t count; |
- RCHECK(reader->Read4(&count) && |
- reader->HasBytes(count * (reader->version() == 1 ? 8 : 4))); |
+ RCHECK(reader->Read4(&count)); |
+ int bytes_per_offset = reader->version() == 1 ? 8 : 4; |
+ |
+ base::CheckedNumeric<size_t> bytes_needed = |
+ base::CheckedNumeric<size_t>(bytes_per_offset); |
+ bytes_needed *= count; |
+ RCHECK_MEDIA_LOGGED(bytes_needed.IsValid(), reader->media_log(), |
+ "Extreme SAIO count exceeds implementation limit."); |
+ RCHECK(reader->HasBytes(bytes_needed.ValueOrDie())); |
+ |
+ RCHECK(count <= offsets.max_size()); |
offsets.resize(count); |
for (uint32_t i = 0; i < count; i++) { |
@@ -175,6 +185,7 @@ bool SampleEncryptionEntry::Parse(BufferReader* reader, |
uint16_t subsample_count; |
RCHECK(reader->Read2(&subsample_count)); |
RCHECK(subsample_count > 0); |
+ RCHECK(subsample_count <= subsamples.max_size()); |
subsamples.resize(subsample_count); |
for (SubsampleEntry& subsample : subsamples) { |
uint16_t clear_bytes; |
@@ -428,11 +439,16 @@ bool EditList::Parse(BoxReader* reader) { |
uint32_t count; |
RCHECK(reader->ReadFullBoxHeader() && reader->Read4(&count)); |
- if (reader->version() == 1) { |
- RCHECK(reader->HasBytes(count * 20)); |
- } else { |
- RCHECK(reader->HasBytes(count * 12)); |
- } |
+ const size_t bytes_per_edit = reader->version() == 1 ? 20 : 12; |
+ |
+ base::CheckedNumeric<size_t> bytes_needed = |
+ base::CheckedNumeric<size_t>(bytes_per_edit); |
+ bytes_needed *= count; |
+ RCHECK_MEDIA_LOGGED(bytes_needed.IsValid(), reader->media_log(), |
+ "Extreme ELST count exceeds implementation limit."); |
+ RCHECK(reader->HasBytes(bytes_needed.ValueOrDie())); |
+ |
+ RCHECK(count <= edits.max_size()); |
edits.resize(count); |
for (std::vector<EditListEntry>::iterator edit = edits.begin(); |
@@ -1081,16 +1097,32 @@ bool TrackFragmentRun::Parse(BoxReader* reader) { |
int fields = sample_duration_present + sample_size_present + |
sample_flags_present + sample_composition_time_offsets_present; |
- RCHECK(reader->HasBytes(fields * sample_count)); |
- |
- if (sample_duration_present) |
+ const size_t bytes_per_field = 4; |
+ |
+ base::CheckedNumeric<size_t> bytes_needed(fields); |
+ bytes_needed *= bytes_per_field; |
+ bytes_needed *= sample_count; |
+ RCHECK_MEDIA_LOGGED( |
+ bytes_needed.IsValid(), reader->media_log(), |
+ "Extreme TRUN sample count exceeds implementation limit."); |
+ RCHECK(reader->HasBytes(bytes_needed.ValueOrDie())); |
+ |
+ if (sample_duration_present) { |
+ RCHECK(sample_count <= sample_durations.max_size()); |
sample_durations.resize(sample_count); |
- if (sample_size_present) |
+ } |
+ if (sample_size_present) { |
+ RCHECK(sample_count <= sample_sizes.max_size()); |
sample_sizes.resize(sample_count); |
- if (sample_flags_present) |
+ } |
+ if (sample_flags_present) { |
+ RCHECK(sample_count <= sample_flags.max_size()); |
sample_flags.resize(sample_count); |
- if (sample_composition_time_offsets_present) |
+ } |
+ if (sample_composition_time_offsets_present) { |
+ RCHECK(sample_count <= sample_composition_time_offsets.max_size()); |
sample_composition_time_offsets.resize(sample_count); |
+ } |
for (uint32_t i = 0; i < sample_count; ++i) { |
if (sample_duration_present) |
@@ -1133,6 +1165,16 @@ bool SampleToGroup::Parse(BoxReader* reader) { |
uint32_t count; |
RCHECK(reader->Read4(&count)); |
+ |
+ const size_t bytes_per_entry = 8; |
+ base::CheckedNumeric<size_t> bytes_needed = |
+ base::CheckedNumeric<size_t>(bytes_per_entry); |
+ bytes_needed *= count; |
+ RCHECK_MEDIA_LOGGED(bytes_needed.IsValid(), reader->media_log(), |
+ "Extreme SBGP count exceeds implementation limit."); |
+ RCHECK(reader->HasBytes(bytes_needed.ValueOrDie())); |
+ |
+ RCHECK(count <= entries.max_size()); |
entries.resize(count); |
for (uint32_t i = 0; i < count; ++i) { |
RCHECK(reader->Read4(&entries[i].sample_count) && |
@@ -1175,6 +1217,19 @@ bool SampleGroupDescription::Parse(BoxReader* reader) { |
uint32_t count; |
RCHECK(reader->Read4(&count)); |
+ |
+ // Check that we have at least two bytes for each entry before allocating a |
+ // potentially huge entries vector. In reality each entry will require a |
+ // variable number of bytes in excess of 2. |
+ const int bytes_per_entry = 2; |
+ base::CheckedNumeric<size_t> bytes_needed = |
+ base::CheckedNumeric<size_t>(bytes_per_entry); |
+ bytes_needed *= count; |
+ RCHECK_MEDIA_LOGGED(bytes_needed.IsValid(), reader->media_log(), |
+ "Extreme SGPD count exceeds implementation limit."); |
+ RCHECK(reader->HasBytes(bytes_needed.ValueOrDie())); |
+ |
+ RCHECK(count <= entries.max_size()); |
entries.resize(count); |
for (uint32_t i = 0; i < count; ++i) { |
if (version == 1) { |
@@ -1258,9 +1313,10 @@ bool IndependentAndDisposableSamples::Parse(BoxReader* reader) { |
RCHECK(reader->version() == 0); |
RCHECK(reader->flags() == 0); |
- int sample_count = reader->box_size() - reader->pos(); |
+ size_t sample_count = reader->box_size() - reader->pos(); |
+ RCHECK(sample_count <= sample_depends_on_.max_size()); |
sample_depends_on_.resize(sample_count); |
- for (int i = 0; i < sample_count; ++i) { |
+ for (size_t i = 0; i < sample_count; ++i) { |
uint8_t sample_info; |
RCHECK(reader->Read1(&sample_info)); |