diff options
author | Michael Niedermayer <michaelni@gmx.at> | 2015-04-07 00:40:21 +0200 |
---|---|---|
committer | Michael Niedermayer <michaelni@gmx.at> | 2015-04-07 00:40:21 +0200 |
commit | 43b434210e597d484aef57c4139c3126d22b7e2b (patch) | |
tree | d7b975b0a4803f00932f9dfbe4b2be356cef6295 | |
parent | 4ec5762e253c4d44618079a1b1afc37433bd99e7 (diff) | |
download | ffmpeg-43b434210e597d484aef57c4139c3126d22b7e2b.tar.gz |
avcodec/h264: Fix race between slices where one overwrites data from the next
Fixes non deterministic crash in ticket4408/fuzz2.264
Likely fixes other samples as well
Signed-off-by: Michael Niedermayer <michaelni@gmx.at>
-rw-r--r-- | libavcodec/h264.h | 1 | ||||
-rw-r--r-- | libavcodec/h264_slice.c | 41 |
2 files changed, 38 insertions, 4 deletions
diff --git a/libavcodec/h264.h b/libavcodec/h264.h index e651d8a4c2..dc68b69a95 100644 --- a/libavcodec/h264.h +++ b/libavcodec/h264.h @@ -411,6 +411,7 @@ typedef struct H264SliceContext { int mb_xy; int resync_mb_x; int resync_mb_y; + int mb_index_end; int mb_skip_run; int is_complex; diff --git a/libavcodec/h264_slice.c b/libavcodec/h264_slice.c index ac3c50ce51..1b67f213ca 100644 --- a/libavcodec/h264_slice.c +++ b/libavcodec/h264_slice.c @@ -2349,8 +2349,17 @@ static int decode_slice(struct AVCodecContext *avctx, void *arg) for (;;) { // START_TIMER - int ret = ff_h264_decode_mb_cabac(h, sl); - int eos; + int ret, eos; + + if (sl->mb_x + sl->mb_y * h->mb_width >= sl->mb_index_end) { + av_log(h->avctx, AV_LOG_ERROR, "Slice overlaps next at %d\n", + sl->mb_index_end); + er_add_slice(sl, sl->resync_mb_x, sl->resync_mb_y, sl->mb_x, + sl->mb_y, ER_MB_ERROR); + return AVERROR_INVALIDDATA; + } + + ret = ff_h264_decode_mb_cabac(h, sl); // STOP_TIMER("decode_mb_cabac") if (ret >= 0) @@ -2412,7 +2421,17 @@ static int decode_slice(struct AVCodecContext *avctx, void *arg) } } else { for (;;) { - int ret = ff_h264_decode_mb_cavlc(h, sl); + int ret; + + if (sl->mb_x + sl->mb_y * h->mb_width >= sl->mb_index_end) { + av_log(h->avctx, AV_LOG_ERROR, "Slice overlaps next at %d\n", + sl->mb_index_end); + er_add_slice(sl, sl->resync_mb_x, sl->resync_mb_y, sl->mb_x, + sl->mb_y, ER_MB_ERROR); + return AVERROR_INVALIDDATA; + } + + ret = ff_h264_decode_mb_cavlc(h, sl); if (ret >= 0) ff_h264_hl_decode_mb(h, sl); @@ -2500,6 +2519,8 @@ int ff_h264_execute_decode_slices(H264Context *h, unsigned context_count) av_assert0(context_count && h->slice_ctx[context_count - 1].mb_y < h->mb_height); + h->slice_ctx[0].mb_index_end = INT_MAX; + if (h->avctx->hwaccel || h->avctx->codec->capabilities & CODEC_CAP_HWACCEL_VDPAU) return 0; @@ -2508,12 +2529,24 @@ int ff_h264_execute_decode_slices(H264Context *h, unsigned context_count) h->mb_y = h->slice_ctx[0].mb_y; return ret; } else { + int j, mb_index; av_assert0(context_count > 0); - for (i = 1; i < context_count; i++) { + for (i = 0; i < context_count; i++) { + int mb_index_end = h->mb_width * h->mb_height; sl = &h->slice_ctx[i]; + mb_index = sl->resync_mb_x + sl->resync_mb_y * h->mb_width; if (CONFIG_ERROR_RESILIENCE) { sl->er.error_count = 0; } + for (j = 0; j < context_count; j++) { + H264SliceContext *sl2 = &h->slice_ctx[j]; + int mb_index2 = sl2->resync_mb_x + sl2->resync_mb_y * h->mb_width; + + if (i==j || mb_index > mb_index2) + continue; + mb_index_end = FFMIN(mb_index_end, mb_index2); + } + sl->mb_index_end = mb_index_end; } avctx->execute(avctx, decode_slice, h->slice_ctx, |