diff options
author | Anton Khirnov <anton@khirnov.net> | 2013-11-28 10:54:35 +0100 |
---|---|---|
committer | Anton Khirnov <anton@khirnov.net> | 2014-01-06 08:23:17 +0100 |
commit | 9a026c72982faf20e1c8dfbe48f0b312cdea69c8 (patch) | |
tree | ec465d98733766e96602ad11b8f4f4b1fe04772e /libavcodec | |
parent | 4736d003fac30af4afd8390182f12f480ad78801 (diff) | |
download | ffmpeg-9a026c72982faf20e1c8dfbe48f0b312cdea69c8.tar.gz |
h264: rebuild the default ref list if the reference count changes
Fixes possible access to freed memory.
Found-by: Mateusz "j00ru" Jurczyk and Gynvael Coldwind
CC:libav-stable@libav.org
Diffstat (limited to 'libavcodec')
-rw-r--r-- | libavcodec/h264.c | 34 |
1 files changed, 23 insertions, 11 deletions
diff --git a/libavcodec/h264.c b/libavcodec/h264.c index 3aa3af0a64..e3dfbfb193 100644 --- a/libavcodec/h264.c +++ b/libavcodec/h264.c @@ -3275,11 +3275,12 @@ static int h264_slice_header_init(H264Context *h, int reinit) int ff_set_ref_count(H264Context *h) { + int ref_count[2], list_count; int num_ref_idx_active_override_flag, max_refs; // set defaults, might be overridden a few lines later - h->ref_count[0] = h->pps.ref_count[0]; - h->ref_count[1] = h->pps.ref_count[1]; + ref_count[0] = h->pps.ref_count[0]; + ref_count[1] = h->pps.ref_count[1]; if (h->slice_type_nos != AV_PICTURE_TYPE_I) { if (h->slice_type_nos == AV_PICTURE_TYPE_B) @@ -3287,33 +3288,42 @@ int ff_set_ref_count(H264Context *h) num_ref_idx_active_override_flag = get_bits1(&h->gb); if (num_ref_idx_active_override_flag) { - h->ref_count[0] = get_ue_golomb(&h->gb) + 1; - if (h->ref_count[0] < 1) + ref_count[0] = get_ue_golomb(&h->gb) + 1; + if (ref_count[0] < 1) return AVERROR_INVALIDDATA; if (h->slice_type_nos == AV_PICTURE_TYPE_B) { - h->ref_count[1] = get_ue_golomb(&h->gb) + 1; - if (h->ref_count[1] < 1) + ref_count[1] = get_ue_golomb(&h->gb) + 1; + if (ref_count[1] < 1) return AVERROR_INVALIDDATA; } } if (h->slice_type_nos == AV_PICTURE_TYPE_B) - h->list_count = 2; + list_count = 2; else - h->list_count = 1; + list_count = 1; } else { - h->list_count = 0; - h->ref_count[0] = h->ref_count[1] = 0; + list_count = 0; + ref_count[0] = ref_count[1] = 0; } max_refs = h->picture_structure == PICT_FRAME ? 16 : 32; - if (h->ref_count[0] > max_refs || h->ref_count[1] > max_refs) { + if (ref_count[0] > max_refs || ref_count[1] > max_refs) { av_log(h->avctx, AV_LOG_ERROR, "reference overflow\n"); h->ref_count[0] = h->ref_count[1] = 0; return AVERROR_INVALIDDATA; } + if (list_count != h->list_count || + ref_count[0] != h->ref_count[0] || + ref_count[1] != h->ref_count[1]) { + h->ref_count[0] = ref_count[0]; + h->ref_count[1] = ref_count[1]; + h->list_count = list_count; + return 1; + } + return 0; } @@ -3741,6 +3751,8 @@ static int decode_slice_header(H264Context *h, H264Context *h0) ret = ff_set_ref_count(h); if (ret < 0) return ret; + else if (ret == 1) + default_ref_list_done = 0; if (!default_ref_list_done) ff_h264_fill_default_ref_list(h); |