From 8e88e04b07352f2ca449278b44a2d8ec7631bdcf Mon Sep 17 00:00:00 2001 From: Tom Finegan Date: Wed, 31 Jan 2018 14:24:38 -0800 Subject: [PATCH] webm2pes: Avoid OOB reads caused by invalid superframe index. BUG=webm:1492 Change-Id: Ibd5781731fe8f6fcdf5f1cc6e5807d17b3b92d4d --- common/libwebm_util.cc | 24 +++++++++++++++++++++--- common/libwebm_util.h | 6 ++++-- m2ts/webm2pes.cc | 15 +++++++++++++-- 3 files changed, 38 insertions(+), 7 deletions(-) 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 #include #include +#include namespace libwebm { @@ -23,9 +25,12 @@ std::int64_t Khz90TicksToNanoseconds(std::int64_t ticks) { } 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 @@ bool ParseVP9SuperFrameIndex(const std::uint8_t* frame, 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 @@ bool ParseVP9SuperFrameIndex(const std::uint8_t* frame, 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 @@ bool ParseVP9SuperFrameIndex(const std::uint8_t* frame, 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(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 NanosecondsTo90KhzTicks(std::int64_t nanoseconds); 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 @@ bool Webm2Pes::WritePesPacket(const VideoFrame& frame, 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 @@ bool Webm2Pes::WritePesPacket(const VideoFrame& frame, 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 =