d3d12decoder: Fix potential use after free

A DPB buffer held by codec picture object may not be writable
at the moment, then gst_buffer_make_writable() will unref passed buffer.

Specifically, the use after free or double free can happen if:
* Crop meta of buffer copy is required because of non-zero
  top-left crop position
* zero-copy is possible with crop meta
* A picture was duplicated, interlaced h264 stream for example

Interlaced h264 stream with non-zero top-left crop position
is not very common but it's possible configuration in theory.

Thus gst_buffer_make_writable() should be called with
GstVideoCodecFrame.output_buffer directly.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/6706>
This commit is contained in:
Seungha Yang 2024-04-21 22:38:50 +09:00 committed by GStreamer Marge Bot
parent b9e51facdd
commit 700c00eda3

View file

@ -1360,6 +1360,7 @@ gst_d3d12_decoder_process_output (GstD3D12Decoder * self,
ID3D12Resource *resource; ID3D12Resource *resource;
UINT subresource[2]; UINT subresource[2];
HRESULT hr; HRESULT hr;
bool attach_crop_meta = false;
auto priv = self->priv; auto priv = self->priv;
@ -1405,21 +1406,8 @@ gst_d3d12_decoder_process_output (GstD3D12Decoder * self,
GST_MINI_OBJECT_FLAG_SET (dmem, GST_D3D12_MEMORY_TRANSFER_NEED_DOWNLOAD); GST_MINI_OBJECT_FLAG_SET (dmem, GST_D3D12_MEMORY_TRANSFER_NEED_DOWNLOAD);
GST_MINI_OBJECT_FLAG_UNSET (dmem, GST_D3D12_MEMORY_TRANSFER_NEED_UPLOAD); GST_MINI_OBJECT_FLAG_UNSET (dmem, GST_D3D12_MEMORY_TRANSFER_NEED_UPLOAD);
if (priv->session->need_crop) { if (priv->session->need_crop)
GstVideoCropMeta *crop_meta; attach_crop_meta = true;
buffer = gst_buffer_make_writable (buffer);
crop_meta = gst_buffer_get_video_crop_meta (buffer);
if (!crop_meta)
crop_meta = gst_buffer_add_video_crop_meta (buffer);
crop_meta->x = priv->session->crop_x;
crop_meta->y = priv->session->crop_y;
crop_meta->width = priv->session->info.width;
crop_meta->height = priv->session->info.height;
GST_TRACE_OBJECT (self, "Attatching crop meta");
}
frame->output_buffer = gst_buffer_ref (buffer); frame->output_buffer = gst_buffer_ref (buffer);
} else { } else {
@ -1550,6 +1538,18 @@ gst_d3d12_decoder_process_output (GstD3D12Decoder * self,
GST_BUFFER_FLAG_SET (frame->output_buffer, buffer_flags); GST_BUFFER_FLAG_SET (frame->output_buffer, buffer_flags);
gst_codec_picture_unref (picture); gst_codec_picture_unref (picture);
if (attach_crop_meta) {
frame->output_buffer = gst_buffer_make_writable (frame->output_buffer);
auto crop_meta = gst_buffer_add_video_crop_meta (frame->output_buffer);
crop_meta->x = priv->session->crop_x;
crop_meta->y = priv->session->crop_y;
crop_meta->width = priv->session->info.width;
crop_meta->height = priv->session->info.height;
GST_TRACE_OBJECT (self, "Attatching crop meta");
}
return gst_video_decoder_finish_frame (videodec, frame); return gst_video_decoder_finish_frame (videodec, frame);
error: error: