diff --git a/media/base/video_frame.cc b/media/base/video_frame.cc index b736fafba09c7..e7d969db7e9e1 100644 --- a/media/base/video_frame.cc +++ b/media/base/video_frame.cc @@ -588,7 +588,26 @@ scoped_refptr VideoFrame::WrapExternalYuvData( *layout, storage, visible_rect, natural_size, timestamp); std::array, 3> data = {y_data, u_data, v_data}; + std::array strides = {y_stride, u_stride, v_stride}; for (size_t plane = 0; plane < NumPlanes(format); ++plane) { + // The caller may pass spans that are smaller than the area implied by + // |coded_size| and |stride|; downstream consumers walk planes by raw + // pointer + stride*row arithmetic without consulting the span size, so an + // under-sized span here turns into an OOB read later. Reject such frames. + const size_t rows = Rows(plane, format, coded_size.height()); + base::CheckedNumeric required = 0; + if (rows > 0) { + required = strides[plane]; + required *= (rows - 1); + required += RowBytes(plane, format, coded_size.width()); + } + if (!required.IsValid() || data[plane].size() < required.ValueOrDie()) { + DLOG(ERROR) << __func__ << " plane " << plane + << " span too small: have " << data[plane].size() + << ", need " + << static_cast(required.ValueOrDefault(SIZE_MAX)); + return nullptr; + } frame->data_[plane] = data[plane]; } return frame;