[FFmpeg-devel] avformat/utils: fix crashes in has_decode_delay_been_guessed

Submitted by Timo Rothenpieler on Dec. 2, 2016, 12:51 p.m.

Details

Message ID 20161202125124.10712-1-timo@rothenpieler.org
State New
Headers show

Commit Message

Timo Rothenpieler Dec. 2, 2016, 12:51 p.m.
These paths can be taken when the actual underlying codec is not h264,
but the user forces, for example via ffmpeg command line, a specific
input decoder that happens to be a h264 decoder.

In that case, the codecpar codec_id is set to h264, but the internal
avctx is the one of, for example, an mpeg2 decoder, thus crashing in
this function.

Checking for the codec actually being h264 is not strictly neccesary to
fix the crash, but a precaution to catch potential other unexpected
codepaths.

Fixes #5985
---
 libavformat/utils.c | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

Comments

wm4 Dec. 2, 2016, 1:03 p.m.
On Fri,  2 Dec 2016 13:51:24 +0100
Timo Rothenpieler <timo@rothenpieler.org> wrote:

> These paths can be taken when the actual underlying codec is not h264,
> but the user forces, for example via ffmpeg command line, a specific
> input decoder that happens to be a h264 decoder.
> 
> In that case, the codecpar codec_id is set to h264, but the internal
> avctx is the one of, for example, an mpeg2 decoder, thus crashing in
> this function.
> 
> Checking for the codec actually being h264 is not strictly neccesary to
> fix the crash, but a precaution to catch potential other unexpected
> codepaths.
> 
> Fixes #5985
> ---
>  libavformat/utils.c | 7 +++++--
>  1 file changed, 5 insertions(+), 2 deletions(-)
> 
> diff --git a/libavformat/utils.c b/libavformat/utils.c
> index 345bbfe5fe..8e23c0c6ec 100644
> --- a/libavformat/utils.c
> +++ b/libavformat/utils.c
> @@ -966,11 +966,14 @@ static int is_intra_only(enum AVCodecID id)
>  
>  static int has_decode_delay_been_guessed(AVStream *st)
>  {
> -    if (st->codecpar->codec_id != AV_CODEC_ID_H264) return 1;
> +    if (st->codecpar->codec_id != AV_CODEC_ID_H264 ||
> +       st->internal->avctx->codec_id != AV_CODEC_ID_H264)
> +        return 1;
>      if (!st->info) // if we have left find_stream_info then nb_decoded_frames won't increase anymore for stream copy
>          return 1;
>  #if CONFIG_H264_DECODER
> -    if (st->internal->avctx->has_b_frames &&
> +    if (st->internal->avctx->codec && !strcmp(st->internal->avctx->codec->name, "h264") &&
> +       st->internal->avctx->has_b_frames &&
>         avpriv_h264_has_num_reorder_frames(st->internal->avctx) == st->internal->avctx->has_b_frames)
>          return 1;
>  #endif

That looks ok, but: can someone explain to me why Libav does apparently
not need this shitshow?
Michael Niedermayer Dec. 2, 2016, 2:46 p.m.
On Fri, Dec 02, 2016 at 01:51:24PM +0100, Timo Rothenpieler wrote:
> These paths can be taken when the actual underlying codec is not h264,
> but the user forces, for example via ffmpeg command line, a specific
> input decoder that happens to be a h264 decoder.
> 

> In that case, the codecpar codec_id is set to h264, but the internal
> avctx is the one of, for example, an mpeg2 decoder, thus crashing in
> this function.

Is it just me or is this completely inconsistent?
the codec id told to the user is h264 while we internally use a
mpeg2 decoder to analyze it ?

If its h264 (as forced by the user) we should use a h264 decoder
to internally analyze it

[...]
Timo Rothenpieler Dec. 2, 2016, 4:05 p.m.
> Is it just me or is this completely inconsistent?
> the codec id told to the user is h264 while we internally use a
> mpeg2 decoder to analyze it ?
> 
> If its h264 (as forced by the user) we should use a h264 decoder
> to internally analyze it
> 

Yes, something is very wrong here.
I also wasn't able to reproduce this with any self made sample. Only the
one from Ticket 5985 makes it crash for me. In two separate ways even.
In one case, the avctx->codec is NULL, because there are unknown codecs
in that sample, and in other cases the codecs mismatch.

I don't have time to take an in depth look at what is going on there, so
for now I decided to harden it against crashes, which is probably a good
idea in any case.

If this patch gets merged, it should also be backported to at least 3.2
Michael Niedermayer Dec. 2, 2016, 11:55 p.m.
On Fri, Dec 02, 2016 at 05:05:29PM +0100, Timo Rothenpieler wrote:
> > Is it just me or is this completely inconsistent?
> > the codec id told to the user is h264 while we internally use a
> > mpeg2 decoder to analyze it ?
> > 
> > If its h264 (as forced by the user) we should use a h264 decoder
> > to internally analyze it
> > 
> 
> Yes, something is very wrong here.
> I also wasn't able to reproduce this with any self made sample. Only the
> one from Ticket 5985 makes it crash for me. In two separate ways even.
> In one case, the avctx->codec is NULL, because there are unknown codecs
> in that sample, and in other cases the codecs mismatch.
> 
> I don't have time to take an in depth look at what is going on there, so
> for now I decided to harden it against crashes, which is probably a good
> idea in any case.

I dont think its a good idea to leave the inconsistency


[...]
Timo Rothenpieler Dec. 3, 2016, 5 p.m.
ping

If nobody has a better idea how to resolve the crash, I'm going to push
this today.
Michael Niedermayer Dec. 3, 2016, 7:44 p.m.
On Sat, Dec 03, 2016 at 06:00:12PM +0100, Timo Rothenpieler wrote:
> ping
> 
> If nobody has a better idea how to resolve the crash, I'm going to push
> this today.

i dont think this patch really fixes it

with this patch and the same sample:
make -j12 && ./ffmpeg -vcodec h264_cuvid -i full20.ts

...

Assertion avctx->codec_id == s->parser->codec_ids[0] || avctx->codec_id == s->parser->codec_ids[1] || avctx->codec_id == s->parser->codec_ids[2] || avctx->codec_id == s->parser->codec_ids[3] || avctx->codec_id == s->parser->codec_ids[4] failed at libavcodec/parser.c:151
Aborted

[...]

Patch hide | download patch | download mbox

diff --git a/libavformat/utils.c b/libavformat/utils.c
index 345bbfe5fe..8e23c0c6ec 100644
--- a/libavformat/utils.c
+++ b/libavformat/utils.c
@@ -966,11 +966,14 @@  static int is_intra_only(enum AVCodecID id)
 
 static int has_decode_delay_been_guessed(AVStream *st)
 {
-    if (st->codecpar->codec_id != AV_CODEC_ID_H264) return 1;
+    if (st->codecpar->codec_id != AV_CODEC_ID_H264 ||
+       st->internal->avctx->codec_id != AV_CODEC_ID_H264)
+        return 1;
     if (!st->info) // if we have left find_stream_info then nb_decoded_frames won't increase anymore for stream copy
         return 1;
 #if CONFIG_H264_DECODER
-    if (st->internal->avctx->has_b_frames &&
+    if (st->internal->avctx->codec && !strcmp(st->internal->avctx->codec->name, "h264") &&
+       st->internal->avctx->has_b_frames &&
        avpriv_h264_has_num_reorder_frames(st->internal->avctx) == st->internal->avctx->has_b_frames)
         return 1;
 #endif