From e6d527ff729e42d80e4756cab779ff4ad693631b Mon Sep 17 00:00:00 2001 From: Reinhard Tartler Date: Thu, 5 Jan 2012 21:40:18 +0100 Subject: [PATCH 1/5] vorbisdec: Fix decoding bug with channel handling Fixes Bug: #191 Chromium Bug: #101458 CVE-2011-3895 Signed-off-by: Reinhard Tartler --- libavcodec/vorbisdec.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/libavcodec/vorbisdec.c b/libavcodec/vorbisdec.c index e0c38c2360..dd30c0fe7a 100644 --- a/libavcodec/vorbisdec.c +++ b/libavcodec/vorbisdec.c @@ -675,7 +675,7 @@ static int vorbis_parse_setup_hdr_residues(vorbis_context *vc) res_setup->partition_size = get_bits(gb, 24) + 1; /* Validations to prevent a buffer overflow later. */ if (res_setup->begin>res_setup->end || - res_setup->end > vc->avccontext->channels * vc->blocksize[1] / 2 || + res_setup->end > (res_setup->type == 2 ? vc->avccontext->channels : 1) * vc->blocksize[1] / 2 || (res_setup->end-res_setup->begin) / res_setup->partition_size > V_MAX_PARTITIONS) { av_log(vc->avccontext, AV_LOG_ERROR, "partition out of bounds: type, begin, end, size, blocksize: %"PRIu16", %"PRIu32", %"PRIu32", %u, %"PRIu32"\n", @@ -1478,6 +1478,7 @@ static int vorbis_parse_audio_packet(vorbis_context *vc) uint8_t res_chan[255]; unsigned res_num = 0; int retlen = 0; + int ch_left = vc->audio_channels; if (get_bits1(gb)) { av_log(vc->avccontext, AV_LOG_ERROR, "Not a Vorbis I audio packet.\n"); @@ -1552,9 +1553,14 @@ static int vorbis_parse_audio_packet(vorbis_context *vc) } } residue = &vc->residues[mapping->submap_residue[i]]; + if (ch_left < ch) { + av_log(vc->avccontext, AV_LOG_ERROR, "Too many channels in vorbis_floor_decode.\n"); + return -1; + } vorbis_residue_decode(vc, residue, ch, do_not_decode, ch_res_ptr, blocksize/2); ch_res_ptr += ch * blocksize / 2; + ch_left -= ch; } // Inverse coupling From afb2aa537954db537d54358997b68f46561fd5a7 Mon Sep 17 00:00:00 2001 From: Chris Evans Date: Thu, 5 Jan 2012 21:25:41 +0100 Subject: [PATCH 2/5] vorbis: An additional defense in the Vorbis codec. Fixes Bug: #190 Chromium Bug: #100543 Related to CVE-2011-3893 Signed-off-by: Reinhard Tartler --- libavcodec/vorbisdec.c | 37 +++++++++++++++++++++++++++---------- 1 file changed, 27 insertions(+), 10 deletions(-) diff --git a/libavcodec/vorbisdec.c b/libavcodec/vorbisdec.c index dd30c0fe7a..bb69fed254 100644 --- a/libavcodec/vorbisdec.c +++ b/libavcodec/vorbisdec.c @@ -1281,6 +1281,7 @@ static av_always_inline int vorbis_residue_decode_internal(vorbis_context *vc, uint8_t *do_not_decode, float *vec, unsigned vlen, + unsigned ch_left, int vr_type) { GetBitContext *gb = &vc->gb; @@ -1288,6 +1289,7 @@ static av_always_inline int vorbis_residue_decode_internal(vorbis_context *vc, unsigned ptns_to_read = vr->ptns_to_read; uint8_t *classifs = vr->classifs; unsigned pass, ch_used, i, j, k, l; + unsigned max_output = (ch - 1) * vlen; if (vr_type == 2) { for (j = 1; j < ch; ++j) @@ -1295,8 +1297,15 @@ static av_always_inline int vorbis_residue_decode_internal(vorbis_context *vc, if (do_not_decode[0]) return 0; ch_used = 1; + max_output += vr->end / ch; } else { ch_used = ch; + max_output += vr->end; + } + + if (max_output > ch_left * vlen) { + av_log(vc->avccontext, AV_LOG_ERROR, "Insufficient output buffer\n"); + return -1; } av_dlog(NULL, " residue type 0/1/2 decode begin, ch: %d cpc %d \n", ch, c_p_c); @@ -1423,14 +1432,15 @@ static av_always_inline int vorbis_residue_decode_internal(vorbis_context *vc, static inline int vorbis_residue_decode(vorbis_context *vc, vorbis_residue *vr, unsigned ch, uint8_t *do_not_decode, - float *vec, unsigned vlen) + float *vec, unsigned vlen, + unsigned ch_left) { if (vr->type == 2) - return vorbis_residue_decode_internal(vc, vr, ch, do_not_decode, vec, vlen, 2); + return vorbis_residue_decode_internal(vc, vr, ch, do_not_decode, vec, vlen, ch_left, 2); else if (vr->type == 1) - return vorbis_residue_decode_internal(vc, vr, ch, do_not_decode, vec, vlen, 1); + return vorbis_residue_decode_internal(vc, vr, ch, do_not_decode, vec, vlen, ch_left, 1); else if (vr->type == 0) - return vorbis_residue_decode_internal(vc, vr, ch, do_not_decode, vec, vlen, 0); + return vorbis_residue_decode_internal(vc, vr, ch, do_not_decode, vec, vlen, ch_left, 0); else { av_log(vc->avccontext, AV_LOG_ERROR, " Invalid residue type while residue decode?! \n"); return AVERROR_INVALIDDATA; @@ -1478,7 +1488,8 @@ static int vorbis_parse_audio_packet(vorbis_context *vc) uint8_t res_chan[255]; unsigned res_num = 0; int retlen = 0; - int ch_left = vc->audio_channels; + unsigned ch_left = vc->audio_channels; + unsigned vlen; if (get_bits1(gb)) { av_log(vc->avccontext, AV_LOG_ERROR, "Not a Vorbis I audio packet.\n"); @@ -1498,11 +1509,12 @@ static int vorbis_parse_audio_packet(vorbis_context *vc) blockflag = vc->modes[mode_number].blockflag; blocksize = vc->blocksize[blockflag]; + vlen = blocksize / 2; if (blockflag) skip_bits(gb, 2); // previous_window, next_window - memset(ch_res_ptr, 0, sizeof(float) * vc->audio_channels * blocksize / 2); //FIXME can this be removed ? - memset(ch_floor_ptr, 0, sizeof(float) * vc->audio_channels * blocksize / 2); //FIXME can this be removed ? + memset(ch_res_ptr, 0, sizeof(float) * vc->audio_channels * vlen); //FIXME can this be removed ? + memset(ch_floor_ptr, 0, sizeof(float) * vc->audio_channels * vlen); //FIXME can this be removed ? // Decode floor @@ -1522,7 +1534,7 @@ static int vorbis_parse_audio_packet(vorbis_context *vc) return AVERROR_INVALIDDATA; } no_residue[i] = ret; - ch_floor_ptr += blocksize / 2; + ch_floor_ptr += vlen; } // Nonzero vector propagate @@ -1539,6 +1551,7 @@ static int vorbis_parse_audio_packet(vorbis_context *vc) for (i = 0; i < mapping->submaps; ++i) { vorbis_residue *residue; unsigned ch = 0; + int ret; for (j = 0; j < vc->audio_channels; ++j) { if ((mapping->submaps == 1) || (i == mapping->mux[j])) { @@ -1557,9 +1570,13 @@ static int vorbis_parse_audio_packet(vorbis_context *vc) av_log(vc->avccontext, AV_LOG_ERROR, "Too many channels in vorbis_floor_decode.\n"); return -1; } - vorbis_residue_decode(vc, residue, ch, do_not_decode, ch_res_ptr, blocksize/2); + if (ch) { + ret = vorbis_residue_decode(vc, residue, ch, do_not_decode, ch_res_ptr, vlen, ch_left); + if (ret < 0) + return ret; + } - ch_res_ptr += ch * blocksize / 2; + ch_res_ptr += ch * vlen; ch_left -= ch; } From 12e984aed76d52e959bb7cbee72c149444ff58ce Mon Sep 17 00:00:00 2001 From: Aneesh Dogra Date: Mon, 9 Jan 2012 00:49:46 +0530 Subject: [PATCH 3/5] utvideo: frame multithreading. >> time ./avconv -i file.avi -f null - Before : real 0m7.784s After : real 0m3.662s Tested on a Intel Core i3 Processor (2 cores, 4 threads). Signed-off-by: Ronald S. Bultje --- libavcodec/utvideo.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/libavcodec/utvideo.c b/libavcodec/utvideo.c index d105d29148..89854c277c 100644 --- a/libavcodec/utvideo.c +++ b/libavcodec/utvideo.c @@ -31,6 +31,7 @@ #include "bytestream.h" #include "get_bits.h" #include "dsputil.h" +#include "thread.h" enum { PRED_NONE = 0, @@ -366,15 +367,17 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *data_size, AVPac int ret; if (c->pic.data[0]) - avctx->release_buffer(avctx, &c->pic); + ff_thread_release_buffer(avctx, &c->pic); c->pic.reference = 1; c->pic.buffer_hints = FF_BUFFER_HINTS_VALID; - if ((ret = avctx->get_buffer(avctx, &c->pic)) < 0) { + if ((ret = ff_thread_get_buffer(avctx, &c->pic)) < 0) { av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n"); return ret; } + ff_thread_finish_setup(avctx); + /* parse plane structure to retrieve frame flags and validate slice offsets */ ptr = buf; for (i = 0; i < c->planes; i++) { @@ -557,7 +560,7 @@ static av_cold int decode_end(AVCodecContext *avctx) UtvideoContext * const c = avctx->priv_data; if (c->pic.data[0]) - avctx->release_buffer(avctx, &c->pic); + ff_thread_release_buffer(avctx, &c->pic); av_freep(&c->slice_bits); @@ -572,7 +575,7 @@ AVCodec ff_utvideo_decoder = { .init = decode_init, .close = decode_end, .decode = decode_frame, - .capabilities = CODEC_CAP_DR1, + .capabilities = CODEC_CAP_DR1 | CODEC_CAP_FRAME_THREADS, .long_name = NULL_IF_CONFIG_SMALL("Ut Video"), }; From 529a25d6e5c3ff889257a57042872d84dc2312d5 Mon Sep 17 00:00:00 2001 From: Laurentiu Ion Date: Sun, 8 Jan 2012 23:05:37 +0200 Subject: [PATCH 4/5] dpcm: Fix invalid writes Fixes bug: #152 Signed-off-by: Ronald S. Bultje --- libavcodec/dpcm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libavcodec/dpcm.c b/libavcodec/dpcm.c index 935f67caca..1b0f6b005b 100644 --- a/libavcodec/dpcm.c +++ b/libavcodec/dpcm.c @@ -288,7 +288,7 @@ static int dpcm_decode_frame(AVCodecContext *avctx, void *data, } case CODEC_ID_SOL_DPCM: if (avctx->codec_tag != 3) { - uint8_t *output_samples_u8 = data; + uint8_t *output_samples_u8 = s->frame.data[0]; while (buf < buf_end) { uint8_t n = *buf++; From ccc27e2139336b66cdec3bb73a2cc7e60ef7e599 Mon Sep 17 00:00:00 2001 From: Aneesh Dogra Date: Mon, 9 Jan 2012 01:27:58 +0530 Subject: [PATCH 5/5] bfi: Use bytestream2 functions to prevent buffer overreads. Signed-off-by: Ronald S. Bultje --- libavcodec/bfi.c | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/libavcodec/bfi.c b/libavcodec/bfi.c index cfe7bdc738..542ba5421c 100644 --- a/libavcodec/bfi.c +++ b/libavcodec/bfi.c @@ -47,7 +47,7 @@ static av_cold int bfi_decode_init(AVCodecContext *avctx) static int bfi_decode_frame(AVCodecContext *avctx, void *data, int *data_size, AVPacket *avpkt) { - const uint8_t *buf = avpkt->data, *buf_end = avpkt->data + avpkt->size; + GetByteContext g; int buf_size = avpkt->size; BFIContext *bfi = avctx->priv_data; uint8_t *dst = bfi->dst; @@ -66,6 +66,8 @@ static int bfi_decode_frame(AVCodecContext *avctx, void *data, return -1; } + bytestream2_init(&g, avpkt->data, buf_size); + /* Set frame parameters and palette, if necessary */ if (!avctx->frame_number) { bfi->frame.pict_type = AV_PICTURE_TYPE_I; @@ -91,15 +93,15 @@ static int bfi_decode_frame(AVCodecContext *avctx, void *data, bfi->frame.key_frame = 0; } - buf += 4; // Unpacked size, not required. + bytestream2_skip(&g, 4); // Unpacked size, not required. while (dst != frame_end) { static const uint8_t lentab[4] = { 0, 2, 0, 1 }; - unsigned int byte = *buf++, av_uninit(offset); + unsigned int byte = bytestream2_get_byte(&g), av_uninit(offset); unsigned int code = byte >> 6; unsigned int length = byte & ~0xC0; - if (buf >= buf_end) { + if (!bytestream2_get_bytes_left(&g)) { av_log(avctx, AV_LOG_ERROR, "Input resolution larger than actual frame.\n"); return -1; @@ -108,16 +110,16 @@ static int bfi_decode_frame(AVCodecContext *avctx, void *data, /* Get length and offset(if required) */ if (length == 0) { if (code == 1) { - length = bytestream_get_byte(&buf); - offset = bytestream_get_le16(&buf); + length = bytestream2_get_byte(&g); + offset = bytestream2_get_le16(&g); } else { - length = bytestream_get_le16(&buf); + length = bytestream2_get_le16(&g); if (code == 2 && length == 0) break; } } else { if (code == 1) - offset = bytestream_get_byte(&buf); + offset = bytestream2_get_byte(&g); } /* Do boundary check */ @@ -127,11 +129,11 @@ static int bfi_decode_frame(AVCodecContext *avctx, void *data, switch (code) { case 0: //Normal Chain - if (length >= buf_end - buf) { + if (length >= bytestream2_get_bytes_left(&g)) { av_log(avctx, AV_LOG_ERROR, "Frame larger than buffer.\n"); return -1; } - bytestream_get_buffer(&buf, dst, length); + bytestream2_get_buffer(&g, dst, length); dst += length; break; @@ -149,8 +151,8 @@ static int bfi_decode_frame(AVCodecContext *avctx, void *data, break; case 3: //Fill Chain - colour1 = bytestream_get_byte(&buf); - colour2 = bytestream_get_byte(&buf); + colour1 = bytestream2_get_byte(&g); + colour2 = bytestream2_get_byte(&g); while (length--) { *dst++ = colour1; *dst++ = colour2;