diff options
Diffstat (limited to 'libavcodec/4xm.c')
-rw-r--r-- | libavcodec/4xm.c | 168 |
1 files changed, 110 insertions, 58 deletions
diff --git a/libavcodec/4xm.c b/libavcodec/4xm.c index 09336b0737..a73f8d59fc 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 */ @@ -24,6 +24,7 @@ * 4XM codec. */ +#include "libavutil/avassert.h" #include "libavutil/frame.h" #include "libavutil/intreadwrite.h" #include "avcodec.h" @@ -32,6 +33,7 @@ #include "get_bits.h" #include "internal.h" + #define BLOCK_TYPE_VLC_BITS 5 #define ACDC_VLC_BITS 9 @@ -129,7 +131,7 @@ typedef struct CFrameBuffer { typedef struct FourXContext { AVCodecContext *avctx; DSPContext dsp; - AVFrame *last_picture; + AVFrame *current_picture, *last_picture; GetBitContext pre_gb; ///< ac/dc prefix GetBitContext gb; GetByteContext g; @@ -283,7 +285,7 @@ static void init_mv(FourXContext *f, int linesize) } #endif -static inline void mcdc(uint16_t *dst, uint16_t *src, int log2w, +static inline void mcdc(uint16_t *dst, const uint16_t *src, int log2w, int h, int stride, int scale, unsigned dc) { int i; @@ -327,7 +329,7 @@ static inline void mcdc(uint16_t *dst, uint16_t *src, int log2w, } break; default: - break; + av_assert0(0); } } @@ -345,8 +347,7 @@ static int decode_p_block(FourXContext *f, uint16_t *dst, uint16_t *src, int scale = 1; unsigned dc = 0; - if (code < 0 || code > 6 || log2w < 0) - return AVERROR_INVALIDDATA; + av_assert0(code >= 0 && code <= 6 && log2w >= 0); if (code == 1) { log2h--; @@ -363,24 +364,42 @@ static int decode_p_block(FourXContext *f, uint16_t *dst, uint16_t *src, src + (1 << log2w), log2w, log2h, stride); } else if (code == 6) { + if (bytestream2_get_bytes_left(&f->g2) < 4) { + av_log(f->avctx, AV_LOG_ERROR, "wordstream overread\n"); + return AVERROR_INVALIDDATA; + } if (log2w) { - dst[0] = bytestream2_get_le16(&f->g2); - dst[1] = bytestream2_get_le16(&f->g2); + dst[0] = bytestream2_get_le16u(&f->g2); + dst[1] = bytestream2_get_le16u(&f->g2); } else { - dst[0] = bytestream2_get_le16(&f->g2); - dst[stride] = bytestream2_get_le16(&f->g2); + dst[0] = bytestream2_get_le16u(&f->g2); + dst[stride] = bytestream2_get_le16u(&f->g2); } return 0; } + if ((code&3)==0 && bytestream2_get_bytes_left(&f->g) < 1) { + av_log(f->avctx, AV_LOG_ERROR, "bytestream overread\n"); + return AVERROR_INVALIDDATA; + } + if (code == 0) { src += f->mv[bytestream2_get_byte(&f->g)]; } else if (code == 3 && f->version >= 2) { return 0; } else if (code == 4) { src += f->mv[bytestream2_get_byte(&f->g)]; + if (bytestream2_get_bytes_left(&f->g2) < 2){ + av_log(f->avctx, AV_LOG_ERROR, "wordstream overread\n"); + return AVERROR_INVALIDDATA; + } dc = bytestream2_get_le16(&f->g2); } else if (code == 5) { + if (bytestream2_get_bytes_left(&f->g2) < 2){ + av_log(f->avctx, AV_LOG_ERROR, "wordstream overread\n"); + return AVERROR_INVALIDDATA; + } + av_assert0(start <= src && src <= end); scale = 0; dc = bytestream2_get_le16(&f->g2); } @@ -411,19 +430,18 @@ static int decode_p_frame(FourXContext *f, AVFrame *frame, if (!f->last_picture->data[0]) { if ((ret = ff_get_buffer(f->avctx, f->last_picture, AV_GET_BUFFER_FLAG_REF)) < 0) { - av_log(f->avctx, AV_LOG_ERROR, "get_buffer() failed\n"); return ret; } - memset(f->last_picture->data[0], 0, - f->avctx->height * FFABS(f->last_picture->linesize[0])); + for (y=0; y<f->avctx->height; y++) + memset(f->last_picture->data[0] + y*f->last_picture->linesize[0], 0, 2*f->avctx->width); } src = (uint16_t *)f->last_picture->data[0]; if (f->version > 1) { - if (length < 20) - return AVERROR_INVALIDDATA; extra = 20; + if (length < extra) + return AVERROR_INVALIDDATA; bitstream_size = AV_RL32(buf + 8); wordstream_size = AV_RL32(buf + 12); bytestream_size = AV_RL32(buf + 16); @@ -434,13 +452,12 @@ static int decode_p_frame(FourXContext *f, AVFrame *frame, 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 || bitstream_size >= INT_MAX/8 || + 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 AVERROR_INVALIDDATA; } @@ -482,10 +499,17 @@ static int decode_i_block(FourXContext *f, int16_t *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) + if (val >> 4) { av_log(f->avctx, AV_LOG_ERROR, "error dc run != 0\n"); + return AVERROR_INVALIDDATA; + } if (val) val = get_xbits(&f->gb, val); @@ -503,7 +527,12 @@ static int decode_i_block(FourXContext *f, int16_t *block) if (code == 0xf0) { i += 16; } else { - level = get_xbits(&f->gb, code & 0xf); + if (code & 0xf) { + level = get_xbits(&f->gb, code & 0xf); + } else { + av_log(f->avctx, AV_LOG_ERROR, "0 coeff\n"); + return AVERROR_INVALIDDATA; + } i += code >> 4; if (i >= 64) { av_log(f->avctx, AV_LOG_ERROR, "run %d oveflow\n", i); @@ -583,7 +612,7 @@ static int decode_i_mb(FourXContext *f) static const uint8_t *read_huffman_tables(FourXContext *f, const uint8_t * const buf, - int len) + int buf_size) { int frequency[512] = { 0 }; uint8_t flag[512]; @@ -592,6 +621,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(up, -1, sizeof(up)); @@ -601,10 +631,10 @@ static const uint8_t *read_huffman_tables(FourXContext *f, for (;;) { int i; - len -= end - start + 1; - - if (end < start || len < 0) + if (ptr_end - ptr < FFMAX(end - start + 1, 0) + 1) { + av_log(f->avctx, AV_LOG_ERROR, "invalid data in read_huffman_tables\n"); return NULL; + } for (i = start; i <= end; i++) frequency[i] = *ptr++; @@ -612,9 +642,6 @@ static const uint8_t *read_huffman_tables(FourXContext *f, if (start == 0) break; - if (--len < 0) - return NULL; - end = *ptr++; } frequency[256] = 1; @@ -622,6 +649,11 @@ static const uint8_t *read_huffman_tables(FourXContext *f, while ((ptr - buf) & 3) ptr++; // 4byte align + if (ptr > ptr_end) { + av_log(f->avctx, AV_LOG_ERROR, "ptr overflow in read_huffman_tables\n"); + return NULL; + } + for (j = 257; j < 512; j++) { int min_freq[2] = { 256 * 256, 256 * 256 }; int smallest[2] = { 0, 0 }; @@ -691,6 +723,7 @@ static int decode_i2_frame(FourXContext *f, AVFrame *frame, const uint8_t *buf, const int mbs = (FFALIGN(width, 16) >> 4) * (FFALIGN(height, 16) >> 4); uint16_t *dst = (uint16_t*)frame->data[0]; const int stride = frame->linesize[0]>>1; + const uint8_t *buf_end = buf + length; GetByteContext g3; if (length < mbs * 8) { @@ -702,6 +735,8 @@ static int decode_i2_frame(FourXContext *f, AVFrame *frame, const uint8_t *buf, for (y = 0; y < height; y += 16) { for (x = 0; x < width; x += 16) { unsigned int color[4] = { 0 }, bits; + if (buf_end - buf < 8) + return -1; // warning following is purely guessed ... color[0] = bytestream2_get_le16u(&g3); color[1] = bytestream2_get_le16u(&g3); @@ -735,7 +770,6 @@ static int decode_i_frame(FourXContext *f, AVFrame *frame, const uint8_t *buf, i 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; @@ -747,7 +781,6 @@ static int decode_i_frame(FourXContext *f, AVFrame *frame, const uint8_t *buf, i 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; @@ -764,6 +797,8 @@ static int decode_i_frame(FourXContext *f, AVFrame *frame, const uint8_t *buf, i return AVERROR_INVALIDDATA; } + av_assert0(prestream <= buf + length); + init_get_bits(&f->gb, buf + 4, 8 * bitstream_size); prestream_size = length + buf - prestream; @@ -807,11 +842,7 @@ static int decode_frame(AVCodecContext *avctx, void *data, if (buf_size < 20) return AVERROR_INVALIDDATA; - if (avctx->width % 16 || avctx->height % 16) { - av_log(avctx, AV_LOG_ERROR, - "Dimensions non-multiple of 16 are invalid.\n"); - return AVERROR_INVALIDDATA; - } + av_assert0(avctx->width % 16 == 0 && avctx->height % 16 == 0); if (buf_size < AV_RL32(buf + 4) + 8) { av_log(f->avctx, AV_LOG_ERROR, "size mismatch %d %d\n", @@ -827,12 +858,19 @@ static int decode_frame(AVCodecContext *avctx, void *data, const int data_size = buf_size - 20; CFrameBuffer *cfrm; - if (data_size < 0) + if (f->version <= 1) { + av_log(f->avctx, AV_LOG_ERROR, "cfrm in version %d\n", f->version); return AVERROR_INVALIDDATA; + } id = AV_RL32(buf + 12); whole_size = AV_RL32(buf + 16); + 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", @@ -851,11 +889,14 @@ 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 if (!cfrm->data) { - av_log(f->avctx, AV_LOG_ERROR, "realloc failure"); + av_log(f->avctx, AV_LOG_ERROR, "realloc failure\n"); return AVERROR(ENOMEM); } @@ -882,26 +923,32 @@ static int decode_frame(AVCodecContext *avctx, void *data, frame_size = buf_size - 12; } + FFSWAP(AVFrame*, f->current_picture, f->last_picture); + // alternatively we would have to use our own buffer management avctx->flags |= CODEC_FLAG_EMU_EDGE; - if ((ret = ff_get_buffer(avctx, picture, AV_GET_BUFFER_FLAG_REF)) < 0) { - av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n"); + if ((ret = ff_reget_buffer(avctx, f->current_picture)) < 0) return ret; - } if (frame_4cc == AV_RL32("ifr2")) { - picture->pict_type = AV_PICTURE_TYPE_I; - if ((ret = decode_i2_frame(f, picture, buf - 4, frame_size + 4)) < 0) + f->current_picture->pict_type = AV_PICTURE_TYPE_I; + if ((ret = decode_i2_frame(f, f->current_picture, buf - 4, frame_size + 4)) < 0) { + av_log(f->avctx, AV_LOG_ERROR, "decode i2 frame failed\n"); return ret; + } } else if (frame_4cc == AV_RL32("ifrm")) { - picture->pict_type = AV_PICTURE_TYPE_I; - if ((ret = decode_i_frame(f, picture, buf, frame_size)) < 0) + f->current_picture->pict_type = AV_PICTURE_TYPE_I; + if ((ret = decode_i_frame(f, f->current_picture, buf, frame_size)) < 0) { + av_log(f->avctx, AV_LOG_ERROR, "decode i frame failed\n"); return ret; + } } else if (frame_4cc == AV_RL32("pfrm") || frame_4cc == AV_RL32("pfr2")) { - picture->pict_type = AV_PICTURE_TYPE_P; - if ((ret = decode_p_frame(f, picture, buf, frame_size)) < 0) + f->current_picture->pict_type = AV_PICTURE_TYPE_P; + if ((ret = decode_p_frame(f, f->current_picture, buf, frame_size)) < 0) { + av_log(f->avctx, AV_LOG_ERROR, "decode p frame failed\n"); return ret; + } } else if (frame_4cc == AV_RL32("snd_")) { av_log(avctx, AV_LOG_ERROR, "ignoring snd_ chunk length:%d\n", buf_size); @@ -910,10 +957,9 @@ static int decode_frame(AVCodecContext *avctx, void *data, buf_size); } - picture->key_frame = picture->pict_type == AV_PICTURE_TYPE_I; + f->current_picture->key_frame = f->current_picture->pict_type == AV_PICTURE_TYPE_I; - av_frame_unref(f->last_picture); - if ((ret = av_frame_ref(f->last_picture, picture)) < 0) + if ((ret = av_frame_ref(picture, f->current_picture)) < 0) return ret; *got_frame = 1; @@ -928,7 +974,11 @@ static av_cold int decode_init(AVCodecContext *avctx) if (avctx->extradata_size != 4 || !avctx->extradata) { av_log(avctx, AV_LOG_ERROR, "extradata wrong or missing\n"); - return 1; + return AVERROR_INVALIDDATA; + } + if((avctx->width % 16) || (avctx->height % 16)) { + av_log(avctx, AV_LOG_ERROR, "unsupported width/height\n"); + return AVERROR_INVALIDDATA; } f->version = AV_RL32(avctx->extradata) >> 16; @@ -941,8 +991,9 @@ static av_cold int decode_init(AVCodecContext *avctx) else avctx->pix_fmt = AV_PIX_FMT_BGR555; - f->last_picture = av_frame_alloc(); - if (!f->last_picture) + f->current_picture = av_frame_alloc(); + f->last_picture = av_frame_alloc(); + if (!f->current_picture || !f->last_picture) return AVERROR(ENOMEM); return 0; @@ -961,6 +1012,7 @@ static av_cold int decode_end(AVCodecContext *avctx) f->cfrm[i].allocated_size = 0; } ff_free_vlc(&f->pre_vlc); + av_frame_free(&f->current_picture); av_frame_free(&f->last_picture); return 0; |