Skip to content

Commit 9753b96

Browse files
tmathmeyermibrunin
authored andcommitted
[Backport] Security bug 1194689
Cherry-pick of patch originally reviewed on https://chromium-review.googlesource.com/c/chromium/src/+/2923118: A few fixes to the D3D11H264Accelerator - Adds a AsD3D11H264Picture method to H264Pictures because sometimes there can be just normal H264Pictures in the DPB and this could cause some invalid variable access as we were statically casting the pointer before. - Adds a bounds check just in case there are more than 16 items in the DPB. Bug: 1194689 Change-Id: Ief2e1d00b451fbc0585dd0b22b5aff7a6918fa11 Commit-Queue: Ted Meyer <tmathmeyer@chromium.org> Reviewed-by: Frank Liberato <liberato@chromium.org> Cr-Commit-Position: refs/heads/master@{#888267} Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
1 parent 7d75c96 commit 9753b96

File tree

4 files changed

+42
-18
lines changed

4 files changed

+42
-18
lines changed

chromium/media/gpu/h264_dpb.cc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,10 @@ VaapiH264Picture* H264Picture::AsVaapiH264Picture() {
5555
return nullptr;
5656
}
5757

58+
D3D11H264Picture* H264Picture::AsD3D11H264Picture() {
59+
return nullptr;
60+
}
61+
5862
H264DPB::H264DPB() : max_num_pics_(0) {}
5963
H264DPB::~H264DPB() = default;
6064

chromium/media/gpu/h264_dpb.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ namespace media {
2323

2424
class V4L2H264Picture;
2525
class VaapiH264Picture;
26+
class D3D11H264Picture;
2627

2728
// A picture (a frame or a field) in the H.264 spec sense.
2829
// See spec at http://www.itu.int/rec/T-REC-H.264
@@ -40,6 +41,7 @@ class MEDIA_GPU_EXPORT H264Picture : public CodecPicture {
4041

4142
virtual V4L2H264Picture* AsV4L2H264Picture();
4243
virtual VaapiH264Picture* AsVaapiH264Picture();
44+
virtual D3D11H264Picture* AsD3D11H264Picture();
4345

4446
// Values calculated per H.264 specification or taken from slice header.
4547
// See spec for more details on each (some names have been converted from

chromium/media/gpu/windows/d3d11_h264_accelerator.cc

Lines changed: 30 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@ class D3D11H264Picture : public H264Picture {
5555
D3D11PictureBuffer* picture;
5656
size_t picture_index_;
5757

58+
D3D11H264Picture* AsD3D11H264Picture() override { return this; }
59+
5860
protected:
5961
~D3D11H264Picture() override;
6062
};
@@ -105,10 +107,12 @@ DecoderStatus D3D11H264Accelerator::SubmitFrameMetadata(
105107

106108
HRESULT hr;
107109
for (;;) {
110+
D3D11H264Picture* d3d11_pic = pic->AsD3D11H264Picture();
111+
if (!d3d11_pic)
112+
return DecoderStatus::kFail;
108113
hr = video_context_->DecoderBeginFrame(
109-
video_decoder_.Get(),
110-
static_cast<D3D11H264Picture*>(pic.get())->picture->output_view().Get(),
111-
0, nullptr);
114+
video_decoder_.Get(), d3d11_pic->picture->output_view().Get(), 0,
115+
nullptr);
112116

113117
if (hr == E_PENDING || hr == D3DERR_WASSTILLDRAWING) {
114118
// Hardware is busy. We should make the call again.
@@ -124,7 +128,7 @@ DecoderStatus D3D11H264Accelerator::SubmitFrameMetadata(
124128
}
125129

126130
sps_ = *sps;
127-
for (size_t i = 0; i < 16; i++) {
131+
for (size_t i = 0; i < media::kRefFrameMaxCount; i++) {
128132
ref_frame_list_[i].bPicEntry = 0xFF;
129133
field_order_cnt_list_[i][0] = 0;
130134
field_order_cnt_list_[i][1] = 0;
@@ -137,8 +141,19 @@ DecoderStatus D3D11H264Accelerator::SubmitFrameMetadata(
137141

138142
int i = 0;
139143
for (auto it = dpb.begin(); it != dpb.end(); i++, it++) {
140-
D3D11H264Picture* our_ref_pic = static_cast<D3D11H264Picture*>(it->get());
141-
if (!our_ref_pic->ref)
144+
// The DPB is supposed to have a maximum of 16 pictures in it, but there's
145+
// nothing actually stopping it from having more. If we run into this case,
146+
// something is clearly wrong, and we should just fail decoding rather than
147+
// try to sort out which pictures really shouldn't be included.
148+
if (i >= media::kRefFrameMaxCount)
149+
return DecoderStatus::kFail;
150+
151+
D3D11H264Picture* our_ref_pic = it->get()->AsD3D11H264Picture();
152+
// How does a non-d3d11 picture get here you might ask? The decoder
153+
// inserts blank H264Picture objects that we can't use as part of filling
154+
// gaps in frame numbers. If we see one, it's not a reference picture
155+
// anyway, so skip it.
156+
if (!our_ref_pic || !our_ref_pic->ref)
142157
continue;
143158
ref_frame_list_[i].Index7Bits = our_ref_pic->picture_index_;
144159
ref_frame_list_[i].AssociatedFlag = our_ref_pic->long_term;
@@ -285,9 +300,8 @@ void D3D11H264Accelerator::PicParamsFromSliceHeader(
285300
}
286301

287302
void D3D11H264Accelerator::PicParamsFromPic(DXVA_PicParams_H264* pic_param,
288-
scoped_refptr<H264Picture> pic) {
289-
pic_param->CurrPic.Index7Bits =
290-
static_cast<D3D11H264Picture*>(pic.get())->picture_index_;
303+
D3D11H264Picture* pic) {
304+
pic_param->CurrPic.Index7Bits = pic->picture_index_;
291305
pic_param->RefPicFlag = pic->ref;
292306
pic_param->frame_num = pic->frame_num;
293307

@@ -320,7 +334,11 @@ DecoderStatus D3D11H264Accelerator::SubmitSlice(
320334
if (!PicParamsFromPPS(&pic_param, pps))
321335
return DecoderStatus::kFail;
322336
PicParamsFromSliceHeader(&pic_param, slice_hdr);
323-
PicParamsFromPic(&pic_param, std::move(pic));
337+
338+
D3D11H264Picture* d3d11_pic = pic->AsD3D11H264Picture();
339+
if (!d3d11_pic)
340+
return DecoderStatus::kFail;
341+
PicParamsFromPic(&pic_param, d3d11_pic);
324342

325343
memcpy(pic_param.RefFrameList, ref_frame_list_,
326344
sizeof pic_param.RefFrameList);
@@ -583,9 +601,8 @@ void D3D11H264Accelerator::Reset() {
583601
}
584602

585603
bool D3D11H264Accelerator::OutputPicture(scoped_refptr<H264Picture> pic) {
586-
D3D11H264Picture* our_pic = static_cast<D3D11H264Picture*>(pic.get());
587-
588-
return client_->OutputResult(our_pic, our_pic->picture);
604+
D3D11H264Picture* our_pic = pic->AsD3D11H264Picture();
605+
return our_pic && client_->OutputResult(our_pic, our_pic->picture);
589606
}
590607

591608
void D3D11H264Accelerator::RecordFailure(const std::string& reason,

chromium/media/gpu/windows/d3d11_h264_accelerator.h

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@
2828

2929
namespace media {
3030

31+
constexpr int kRefFrameMaxCount = 16;
32+
3133
class D3D11H264Accelerator;
3234
class MediaLog;
3335

@@ -75,8 +77,7 @@ class D3D11H264Accelerator : public H264Decoder::H264Accelerator {
7577
void PicParamsFromSliceHeader(DXVA_PicParams_H264* pic_param,
7678
const H264SliceHeader* pps);
7779

78-
void PicParamsFromPic(DXVA_PicParams_H264* pic_param,
79-
scoped_refptr<H264Picture> pic);
80+
void PicParamsFromPic(DXVA_PicParams_H264* pic_param, D3D11H264Picture* pic);
8081

8182
void SetVideoDecoder(ComD3D11VideoDecoder video_decoder);
8283

@@ -98,10 +99,10 @@ class D3D11H264Accelerator : public H264Decoder::H264Accelerator {
9899

99100
// This information set at the beginning of a frame and saved for processing
100101
// all the slices.
101-
DXVA_PicEntry_H264 ref_frame_list_[16];
102+
DXVA_PicEntry_H264 ref_frame_list_[kRefFrameMaxCount];
102103
H264SPS sps_;
103-
INT field_order_cnt_list_[16][2];
104-
USHORT frame_num_list_[16];
104+
INT field_order_cnt_list_[kRefFrameMaxCount][2];
105+
USHORT frame_num_list_[kRefFrameMaxCount];
105106
UINT used_for_reference_flags_;
106107
USHORT non_existing_frame_flags_;
107108

0 commit comments

Comments
 (0)