diff options
Diffstat (limited to 'libavcodec/4xm.c')
-rw-r--r-- | libavcodec/4xm.c | 107 |
1 files changed, 79 insertions, 28 deletions
diff --git a/libavcodec/4xm.c b/libavcodec/4xm.c index 8d7db98653..f886e3e7a5 100644 --- a/libavcodec/4xm.c +++ b/libavcodec/4xm.c @@ -2,20 +2,20 @@ * 4XM codec * Copyright (c) 2003 Michael Niedermayer * - * This file is part of Libav. + * This file is part of FFmpeg. * - * Libav is free software; you can redistribute it and/or + * FFmpeg is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * - * Libav is distributed in the hope that it will be useful, + * FFmpeg is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with Libav; if not, write to the Free Software + * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ @@ -343,6 +343,10 @@ static void decode_p_block(FourXContext *f, uint16_t *dst, uint16_t *src, assert(code >= 0 && code <= 6); if (code == 0) { + if (f->g.buffer_end - f->g.buffer < 1) { + av_log(f->avctx, AV_LOG_ERROR, "bytestream overread\n"); + return; + } src += f->mv[bytestream2_get_byte(&f->g)]; if (start > src || src > end) { av_log(f->avctx, AV_LOG_ERROR, "mv out of pic\n"); @@ -362,15 +366,31 @@ static void decode_p_block(FourXContext *f, uint16_t *dst, uint16_t *src, } else if (code == 3 && f->version < 2) { mcdc(dst, src, log2w, h, stride, 1, 0); } else if (code == 4) { + if (f->g.buffer_end - f->g.buffer < 1) { + av_log(f->avctx, AV_LOG_ERROR, "bytestream overread\n"); + return; + } src += f->mv[bytestream2_get_byte(&f->g)]; if (start > src || src > end) { av_log(f->avctx, AV_LOG_ERROR, "mv out of pic\n"); return; } + if (f->g2.buffer_end - f->g2.buffer < 1){ + av_log(f->avctx, AV_LOG_ERROR, "wordstream overread\n"); + return; + } mcdc(dst, src, log2w, h, stride, 1, bytestream2_get_le16(&f->g2)); } else if (code == 5) { + if (f->g2.buffer_end - f->g2.buffer < 1) { + av_log(f->avctx, AV_LOG_ERROR, "wordstream overread\n"); + return; + } mcdc(dst, src, log2w, h, stride, 0, bytestream2_get_le16(&f->g2)); } else if (code == 6) { + if (f->g2.buffer_end - f->g2.buffer < 2) { + av_log(f->avctx, AV_LOG_ERROR, "wordstream overread\n"); + return; + } if (log2w) { dst[0] = bytestream2_get_le16(&f->g2); dst[1] = bytestream2_get_le16(&f->g2); @@ -394,6 +414,8 @@ static int decode_p_frame(FourXContext *f, const uint8_t *buf, int length) if (f->version > 1) { extra = 20; + if (length < extra) + return -1; bitstream_size = AV_RL32(buf + 8); wordstream_size = AV_RL32(buf + 12); bytestream_size = AV_RL32(buf + 16); @@ -404,13 +426,12 @@ static int decode_p_frame(FourXContext *f, const uint8_t *buf, int length) bytestream_size = FFMAX(length - bitstream_size - wordstream_size, 0); } - if (bitstream_size + bytestream_size + wordstream_size + extra != length - || bitstream_size > (1 << 26) - || bytestream_size > (1 << 26) - || wordstream_size > (1 << 26)) { - av_log(f->avctx, AV_LOG_ERROR, "lengths %d %d %d %d\n", - bitstream_size, bytestream_size, wordstream_size, - bitstream_size + bytestream_size + wordstream_size - length); + if (bitstream_size > length || + bytestream_size > length - bitstream_size || + wordstream_size > length - bytestream_size - bitstream_size || + extra > length - bytestream_size - bitstream_size - wordstream_size) { + av_log(f->avctx, AV_LOG_ERROR, "lengths %d %d %d %d\n", bitstream_size, bytestream_size, wordstream_size, + bitstream_size+ bytestream_size+ wordstream_size - length); return -1; } @@ -451,6 +472,11 @@ static int decode_i_block(FourXContext *f, DCTELEM *block) { int code, i, j, level, val; + if (get_bits_left(&f->gb) < 2){ + av_log(f->avctx, AV_LOG_ERROR, "%d bits left before decode_i_block()\n", get_bits_left(&f->gb)); + return -1; + } + /* DC coef */ val = get_vlc2(&f->pre_gb, f->pre_vlc.table, ACDC_VLC_BITS, 3); if (val >> 4) @@ -550,7 +576,7 @@ static int decode_i_mb(FourXContext *f) } static const uint8_t *read_huffman_tables(FourXContext *f, - const uint8_t * const buf) + const uint8_t * const buf, int buf_size) { int frequency[512]; uint8_t flag[512]; @@ -559,6 +585,7 @@ static const uint8_t *read_huffman_tables(FourXContext *f, int bits_tab[257]; int start, end; const uint8_t *ptr = buf; + const uint8_t *ptr_end = buf + buf_size; int j; memset(frequency, 0, sizeof(frequency)); @@ -569,6 +596,8 @@ static const uint8_t *read_huffman_tables(FourXContext *f, for (;;) { int i; + if (start <= end && ptr_end - ptr < end - start + 1 + 1) + return NULL; for (i = start; i <= end; i++) frequency[i] = *ptr++; start = *ptr++; @@ -651,6 +680,7 @@ static int decode_i2_frame(FourXContext *f, const uint8_t *buf, int length) const int mbs = (FFALIGN(width, 16) >> 4) * (FFALIGN(height, 16) >> 4); uint16_t *dst = (uint16_t*)f->current_picture.data[0]; const int stride = f->current_picture.linesize[0]>>1; + const uint8_t *buf_end = buf + length; GetByteContext g3; if (length < mbs * 8) { @@ -662,6 +692,8 @@ static int decode_i2_frame(FourXContext *f, const uint8_t *buf, int length) for (y = 0; y < height; y += 16) { for (x = 0; x < width; x += 16) { unsigned int color[4], bits; + if (buf_end - buf < 8) + return -1; memset(color, 0, sizeof(color)); // warning following is purely guessed ... color[0] = bytestream2_get_le16u(&g3); @@ -696,16 +728,14 @@ static int decode_i_frame(FourXContext *f, const uint8_t *buf, int length) const int width = f->avctx->width; const int height = f->avctx->height; const unsigned int bitstream_size = AV_RL32(buf); - int token_count av_unused; unsigned int prestream_size; const uint8_t *prestream; - if (length < bitstream_size + 12) { + if (bitstream_size > (1<<26) || length < bitstream_size + 12) { av_log(f->avctx, AV_LOG_ERROR, "packet size too small\n"); return AVERROR_INVALIDDATA; } - token_count = AV_RL32(buf + bitstream_size + 8); prestream_size = 4 * AV_RL32(buf + bitstream_size + 4); prestream = buf + bitstream_size + 12; @@ -717,7 +747,9 @@ static int decode_i_frame(FourXContext *f, const uint8_t *buf, int length) return -1; } - prestream = read_huffman_tables(f, prestream); + prestream = read_huffman_tables(f, prestream, buf + length - prestream); + if (!prestream) + return -1; init_get_bits(&f->gb, buf + 4, 8 * bitstream_size); @@ -760,6 +792,8 @@ static int decode_frame(AVCodecContext *avctx, void *data, AVFrame *p, temp; int i, frame_4cc, frame_size; + if (buf_size < 12) + return AVERROR_INVALIDDATA; frame_4cc = AV_RL32(buf); if (buf_size != AV_RL32(buf + 4) + 8 || buf_size < 20) av_log(f->avctx, AV_LOG_ERROR, "size mismatch %d %d\n", @@ -772,6 +806,11 @@ static int decode_frame(AVCodecContext *avctx, void *data, const int whole_size = AV_RL32(buf + 16); CFrameBuffer *cfrm; + if (data_size < 0 || whole_size < 0) { + av_log(f->avctx, AV_LOG_ERROR, "sizes invalid\n"); + return AVERROR_INVALIDDATA; + } + for (i = 0; i < CFRAME_BUFFER_COUNT; i++) if (f->cfrm[i].id && f->cfrm[i].id < avctx->frame_number) av_log(f->avctx, AV_LOG_ERROR, "lost c frame %d\n", @@ -790,6 +829,9 @@ static int decode_frame(AVCodecContext *avctx, void *data, } cfrm = &f->cfrm[i]; + if (data_size > UINT_MAX - cfrm->size - FF_INPUT_BUFFER_PADDING_SIZE) + return AVERROR_INVALIDDATA; + cfrm->data = av_fast_realloc(cfrm->data, &cfrm->allocated_size, cfrm->size + data_size + FF_INPUT_BUFFER_PADDING_SIZE); // explicit check needed as memcpy below might not catch a NULL @@ -828,26 +870,27 @@ static int decode_frame(AVCodecContext *avctx, void *data, // alternatively we would have to use our own buffer management avctx->flags |= CODEC_FLAG_EMU_EDGE; - if (p->data[0]) - avctx->release_buffer(avctx, p); - - p->reference = 1; - if (avctx->get_buffer(avctx, p) < 0) { - av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n"); + p->reference= 3; + if (avctx->reget_buffer(avctx, p) < 0) { + av_log(avctx, AV_LOG_ERROR, "reget_buffer() failed\n"); return -1; } if (frame_4cc == AV_RL32("ifr2")) { - p->pict_type = AV_PICTURE_TYPE_I; - if (decode_i2_frame(f, buf - 4, frame_size + 4) < 0) + p->pict_type= AV_PICTURE_TYPE_I; + if (decode_i2_frame(f, buf - 4, frame_size + 4) < 0) { + av_log(f->avctx, AV_LOG_ERROR, "decode i2 frame failed\n"); return -1; + } } else if (frame_4cc == AV_RL32("ifrm")) { - p->pict_type = AV_PICTURE_TYPE_I; - if (decode_i_frame(f, buf, frame_size) < 0) + p->pict_type= AV_PICTURE_TYPE_I; + if (decode_i_frame(f, buf, frame_size) < 0) { + av_log(f->avctx, AV_LOG_ERROR, "decode i frame failed\n"); return -1; + } } else if (frame_4cc == AV_RL32("pfrm") || frame_4cc == AV_RL32("pfr2")) { if (!f->last_picture.data[0]) { - f->last_picture.reference = 1; + f->last_picture.reference = 3; if (avctx->get_buffer(avctx, &f->last_picture) < 0) { av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n"); return -1; @@ -855,8 +898,10 @@ static int decode_frame(AVCodecContext *avctx, void *data, } p->pict_type = AV_PICTURE_TYPE_P; - if (decode_p_frame(f, buf, frame_size) < 0) + if (decode_p_frame(f, buf, frame_size) < 0) { + av_log(f->avctx, AV_LOG_ERROR, "decode p frame failed\n"); return -1; + } } else if (frame_4cc == AV_RL32("snd_")) { av_log(avctx, AV_LOG_ERROR, "ignoring snd_ chunk length:%d\n", buf_size); @@ -893,7 +938,13 @@ static av_cold int decode_init(AVCodecContext *avctx) av_log(avctx, AV_LOG_ERROR, "extradata wrong or missing\n"); return 1; } + if((avctx->width % 16) || (avctx->height % 16)) { + av_log(avctx, AV_LOG_ERROR, "unsupported width/height\n"); + return AVERROR_INVALIDDATA; + } + avcodec_get_frame_defaults(&f->current_picture); + avcodec_get_frame_defaults(&f->last_picture); f->version = AV_RL32(avctx->extradata) >> 16; common_init(avctx); init_vlcs(f); |