[FFmpeg-devel] [PATCH 2/3] lavf/webm_chunk: Fix NULL dereference
Andreas Rheinhardt
andreas.rheinhardt at gmail.com
Mon Jun 17 11:04:00 EEST 2019
Andreas Rheinhardt:
> Andreas Rheinhardt:
>> Andreas Rheinhardt:
>>> The earlier version of the webm_chunk muxer had several bugs:
>>>
>>> 1. If the first packet of an audio stream didn't have a PTS of zero,
>>> then no chunk will be started before a packet is delivered to the
>>> underlying Matroska/WebM muxer, i.e. the AVFormatContext used to write
>>> these packets had a NULL as AVIOContext for output. This is behind the
>>> crash in ticket #5752.
>>>
>>> 2. If an error happens during writing a packet, the underlyimg
>>> Matroska/WebM muxer context is freed. This leads to a use-after-free
>>> coupled with a double-free in webm_chunk_write_trailer (which supposes
>>> that the underlying AVFormatContext is still valid).
>>>
>>> 3. Even when no error occurs at all, webm_chunk_write_trailer is still
>>> buggy: After the underlying Matroska/WebM muxer has written its trailer,
>>> ending the chunk implicitly flushes it again which is illegal at this
>>> point.
>>>
>>> These bugs have been fixed.
>>>
>>> Fixes #5752.
>>>
>>> Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt at gmail.com>
>>> ---
>>> libavformat/webm_chunk.c | 44 +++++++++++++++++++++-------------------
>>> 1 file changed, 23 insertions(+), 21 deletions(-)
>>>
>>> diff --git a/libavformat/webm_chunk.c b/libavformat/webm_chunk.c
>>> index 2c99753b5b..391fee721a 100644
>>> --- a/libavformat/webm_chunk.c
>>> +++ b/libavformat/webm_chunk.c
>>> @@ -168,7 +168,7 @@ static int chunk_start(AVFormatContext *s)
>>> return 0;
>>> }
>>>
>>> -static int chunk_end(AVFormatContext *s)
>>> +static int chunk_end(AVFormatContext *s, int flush)
>>> {
>>> WebMChunkContext *wc = s->priv_data;
>>> AVFormatContext *oc = wc->avf;
>>> @@ -179,11 +179,14 @@ static int chunk_end(AVFormatContext *s)
>>> char filename[MAX_FILENAME_SIZE];
>>> AVDictionary *options = NULL;
>>>
>>> - if (wc->chunk_start_index == wc->chunk_index)
>>> + if (!oc->pb)
>>> return 0;
>>> - // Flush the cluster in WebM muxer.
>>> - oc->oformat->write_packet(oc, NULL);
>>> +
>>> + if (flush)
>>> + // Flush the cluster in WebM muxer.
>>> + oc->oformat->write_packet(oc, NULL);
>>> buffer_size = avio_close_dyn_buf(oc->pb, &buffer);
>>> + oc->pb = NULL;
>>> ret = get_chunk_filename(s, 0, filename);
>>> if (ret < 0)
>>> goto fail;
>>> @@ -194,7 +197,6 @@ static int chunk_end(AVFormatContext *s)
>>> goto fail;
>>> avio_write(pb, buffer, buffer_size);
>>> ff_format_io_close(s, &pb);
>>> - oc->pb = NULL;
>>> fail:
>>> av_dict_free(&options);
>>> av_free(buffer);
>>> @@ -216,27 +218,19 @@ static int webm_chunk_write_packet(AVFormatContext *s, AVPacket *pkt)
>>> }
>>>
>>> // For video, a new chunk is started only on key frames. For audio, a new
>>> - // chunk is started based on chunk_duration.
>>> - if ((st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO &&
>>> + // chunk is started based on chunk_duration. Also, a new chunk is started
>>> + // unconditionally if there is no currently open chunk.
>>> + if (!oc->pb || (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO &&
>>> (pkt->flags & AV_PKT_FLAG_KEY)) ||
>>> (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO &&
>>> - (pkt->pts == 0 || wc->duration_written >= wc->chunk_duration))) {
>>> + wc->duration_written >= wc->chunk_duration)) {
>>> wc->duration_written = 0;
>>> - if ((ret = chunk_end(s)) < 0 || (ret = chunk_start(s)) < 0) {
>>> - goto fail;
>>> + if ((ret = chunk_end(s, 1)) < 0 || (ret = chunk_start(s)) < 0) {
>>> + return ret;
>>> }
>>> }
>>>
>>> ret = oc->oformat->write_packet(oc, pkt);
>>> - if (ret < 0)
>>> - goto fail;
>>> -
>>> -fail:
>>> - if (ret < 0) {
>>> - oc->streams = NULL;
>>> - oc->nb_streams = 0;
>>> - avformat_free_context(oc);
>>> - }
>>>
>>> return ret;
>>> }
>>> @@ -245,12 +239,20 @@ static int webm_chunk_write_trailer(AVFormatContext *s)
>>> {
>>> WebMChunkContext *wc = s->priv_data;
>>> AVFormatContext *oc = wc->avf;
>>> + int ret;
>>> +
>>> + if (!oc->pb) {
>>> + ret = chunk_start(s);
>>> + if (ret < 0)
>>> + goto fail;
>>> + }
>>> oc->oformat->write_trailer(oc);
>>> - chunk_end(s);
>>> + ret = chunk_end(s, 0);
>>> +fail:
>>> oc->streams = NULL;
>>> oc->nb_streams = 0;
>>> avformat_free_context(oc);
>>> - return 0;
>>> + return ret;
>>> }
>>>
>>> #define OFFSET(x) offsetof(WebMChunkContext, x)
>>>
>>>
>> Ping for the last two patches of this patchset (i.e. this one and
>> https://ffmpeg.org/pipermail/ffmpeg-devel/2019-April/242902.html)
>>
>> - Andreas
>>
> And another ping for these two patches.
>
> - Andreas
>
Ping #3.
- Andreas
More information about the ffmpeg-devel
mailing list