webm2pes: Avoid OOB reads caused by invalid superframe index.

BUG=webm:1492

Change-Id: Ibd5781731fe8f6fcdf5f1cc6e5807d17b3b92d4d
diff --git a/common/libwebm_util.cc b/common/libwebm_util.cc
index 7520bb7..d158250 100644
--- a/common/libwebm_util.cc
+++ b/common/libwebm_util.cc
@@ -7,8 +7,10 @@
 // be found in the AUTHORS file in the root of the source tree.
 #include "common/libwebm_util.h"
 
+#include <cassert>
 #include <cstdint>
 #include <cstdio>
+#include <limits>
 
 namespace libwebm {
 
@@ -23,9 +25,12 @@
 }
 
 bool ParseVP9SuperFrameIndex(const std::uint8_t* frame,
-                             std::size_t frame_length, Ranges* frame_ranges) {
-  if (frame == nullptr || frame_length == 0 || frame_ranges == nullptr)
+                             std::size_t frame_length, Ranges* frame_ranges,
+                             bool* error) {
+  if (frame == nullptr || frame_length == 0 || frame_ranges == nullptr ||
+      error == nullptr) {
     return false;
+  }
 
   bool parse_ok = false;
   const std::uint8_t marker = frame[frame_length - 1];
@@ -40,7 +45,9 @@
     const std::size_t index_length = 2 + length_field_size * num_frames;
 
     if (frame_length < index_length) {
-      std::fprintf(stderr, "VP9Parse: Invalid superframe index size.\n");
+      std::fprintf(stderr,
+                   "VP9ParseSuperFrameIndex: Invalid superframe index size.\n");
+      *error = true;
       return false;
     }
 
@@ -53,6 +60,7 @@
       const std::uint8_t* byte = frame + length + 1;
 
       std::size_t frame_offset = 0;
+
       for (int i = 0; i < num_frames; ++i) {
         std::uint32_t child_frame_length = 0;
 
@@ -60,18 +68,28 @@
           child_frame_length |= (*byte++) << (j * 8);
         }
 
+        if (length - frame_offset < child_frame_length) {
+          std::fprintf(stderr,
+                       "ParseVP9SuperFrameIndex: Invalid superframe, sub frame "
+                       "larger than entire frame.\n");
+          *error = true;
+          return false;
+        }
+
         frame_ranges->push_back(Range(frame_offset, child_frame_length));
         frame_offset += child_frame_length;
       }
 
       if (static_cast<int>(frame_ranges->size()) != num_frames) {
         std::fprintf(stderr, "VP9Parse: superframe index parse failed.\n");
+        *error = true;
         return false;
       }
 
       parse_ok = true;
     } else {
       std::fprintf(stderr, "VP9Parse: Invalid superframe index.\n");
+      *error = true;
     }
   }
   return parse_ok;
diff --git a/common/libwebm_util.h b/common/libwebm_util.h
index 233c482..71d805f 100644
--- a/common/libwebm_util.h
+++ b/common/libwebm_util.h
@@ -47,9 +47,11 @@
 std::int64_t Khz90TicksToNanoseconds(std::int64_t khz90_ticks);
 
 // Returns true and stores frame offsets and lengths in |frame_ranges| when
-// |frame| has a valid VP9 super frame index.
+// |frame| has a valid VP9 super frame index. Sets |error| to true when parsing
+// fails for any reason.
 bool ParseVP9SuperFrameIndex(const std::uint8_t* frame,
-                             std::size_t frame_length, Ranges* frame_ranges);
+                             std::size_t frame_length, Ranges* frame_ranges,
+                             bool* error);
 
 // Writes |val| to |fileptr| and returns true upon success.
 bool WriteUint8(std::uint8_t val, std::FILE* fileptr);
diff --git a/m2ts/webm2pes.cc b/m2ts/webm2pes.cc
index 7922f6a..f510acf 100644
--- a/m2ts/webm2pes.cc
+++ b/m2ts/webm2pes.cc
@@ -429,8 +429,14 @@
 
   Ranges frame_ranges;
   if (frame.codec() == VideoFrame::kVP9) {
-    const bool has_superframe_index = ParseVP9SuperFrameIndex(
-        frame.buffer().data.get(), frame.buffer().length, &frame_ranges);
+    bool error = false;
+    const bool has_superframe_index =
+        ParseVP9SuperFrameIndex(frame.buffer().data.get(),
+                                frame.buffer().length, &frame_ranges, &error);
+    if (error) {
+      std::fprintf(stderr, "Webm2Pes: Superframe index parse failed.\n");
+      return false;
+    }
     if (has_superframe_index == false) {
       frame_ranges.push_back(Range(0, frame.buffer().length));
     }
@@ -450,6 +456,11 @@
     if (packet_payload_range.length > kMaxPayloadSize) {
       extra_bytes = packet_payload_range.length - kMaxPayloadSize;
     }
+    if (packet_payload_range.length + packet_payload_range.offset >
+        frame.buffer().length) {
+      std::fprintf(stderr, "Webm2Pes: Invalid frame length.\n");
+      return false;
+    }
 
     // First packet of new frame. Always include PTS and BCMV header.
     header.packet_length =