diff options
author | Ronald S. Bultje <rsbultje@gmail.com> | 2012-03-11 07:28:54 -0700 |
---|---|---|
committer | Reinhard Tartler <siretart@tauware.de> | 2012-03-14 20:47:19 +0100 |
commit | 26521d87ba22fe1bb49f1f0796c7227017064e7f (patch) | |
tree | e8056949002364d4ac308e16a0234ff7f8ac48c6 | |
parent | e1a4143793afc98d623fa4c56835b837b74bac1d (diff) | |
download | ffmpeg-26521d87ba22fe1bb49f1f0796c7227017064e7f.tar.gz |
dsicinvideo: validate buffer offset before copying pixels.
Found-by: Mateusz "j00ru" Jurczyk and Gynvael Coldwind
CC: libav-stable@libav.org
(cherry picked from commit c95fefa0420be9cc0f09a95041acf11114aaacd0)
Signed-off-by: Reinhard Tartler <siretart@tauware.de>
-rw-r--r-- | libavcodec/dsicinav.c | 40 |
1 files changed, 25 insertions, 15 deletions
diff --git a/libavcodec/dsicinav.c b/libavcodec/dsicinav.c index 37d39f5405..a379531613 100644 --- a/libavcodec/dsicinav.c +++ b/libavcodec/dsicinav.c @@ -146,11 +146,11 @@ static int cin_decode_huffman(const unsigned char *src, int src_size, unsigned c return dst_cur - dst; } -static void cin_decode_lzss(const unsigned char *src, int src_size, unsigned char *dst, int dst_size) +static int cin_decode_lzss(const unsigned char *src, int src_size, unsigned char *dst, int dst_size) { uint16_t cmd; int i, sz, offset, code; - unsigned char *dst_end = dst + dst_size; + unsigned char *dst_end = dst + dst_size, *dst_start = dst; const unsigned char *src_end = src + src_size; while (src < src_end && dst < dst_end) { @@ -161,6 +161,8 @@ static void cin_decode_lzss(const unsigned char *src, int src_size, unsigned cha } else { cmd = AV_RL16(src); src += 2; offset = cmd >> 4; + if ((int) (dst - dst_start) < offset + 1) + return AVERROR_INVALIDDATA; sz = (cmd & 0xF) + 2; /* don't use memcpy/memmove here as the decoding routine (ab)uses */ /* buffer overlappings to repeat bytes in the destination */ @@ -172,6 +174,8 @@ static void cin_decode_lzss(const unsigned char *src, int src_size, unsigned cha } } } + + return 0; } static void cin_decode_rle(const unsigned char *src, int src_size, unsigned char *dst, int dst_size) @@ -201,13 +205,7 @@ static int cinvideo_decode_frame(AVCodecContext *avctx, const uint8_t *buf = avpkt->data; int buf_size = avpkt->size; CinVideoContext *cin = avctx->priv_data; - int i, y, palette_type, palette_colors_count, bitmap_frame_type, bitmap_frame_size; - - cin->frame.buffer_hints = FF_BUFFER_HINTS_VALID | FF_BUFFER_HINTS_PRESERVE | FF_BUFFER_HINTS_REUSABLE; - if (avctx->reget_buffer(avctx, &cin->frame)) { - av_log(cin->avctx, AV_LOG_ERROR, "delphinecinvideo: reget_buffer() failed to allocate a frame\n"); - return -1; - } + int i, y, palette_type, palette_colors_count, bitmap_frame_type, bitmap_frame_size, res = 0; palette_type = buf[0]; palette_colors_count = AV_RL16(buf+1); @@ -233,8 +231,6 @@ static int cinvideo_decode_frame(AVCodecContext *avctx, bitmap_frame_size -= 4; } } - memcpy(cin->frame.data[1], cin->palette, sizeof(cin->palette)); - cin->frame.palette_has_changed = 1; /* note: the decoding routines below assumes that surface.width = surface.pitch */ switch (bitmap_frame_type) { @@ -267,17 +263,31 @@ static int cinvideo_decode_frame(AVCodecContext *avctx, cin->bitmap_table[CIN_CUR_BMP], cin->bitmap_size); break; case 38: - cin_decode_lzss(buf, bitmap_frame_size, - cin->bitmap_table[CIN_CUR_BMP], cin->bitmap_size); + res = cin_decode_lzss(buf, bitmap_frame_size, + cin->bitmap_table[CIN_CUR_BMP], + cin->bitmap_size); + if (res < 0) + return res; break; case 39: - cin_decode_lzss(buf, bitmap_frame_size, - cin->bitmap_table[CIN_CUR_BMP], cin->bitmap_size); + res = cin_decode_lzss(buf, bitmap_frame_size, + cin->bitmap_table[CIN_CUR_BMP], + cin->bitmap_size); + if (res < 0) + return res; cin_apply_delta_data(cin->bitmap_table[CIN_PRE_BMP], cin->bitmap_table[CIN_CUR_BMP], cin->bitmap_size); break; } + cin->frame.buffer_hints = FF_BUFFER_HINTS_VALID | FF_BUFFER_HINTS_PRESERVE | FF_BUFFER_HINTS_REUSABLE; + if (avctx->reget_buffer(avctx, &cin->frame)) { + av_log(cin->avctx, AV_LOG_ERROR, "delphinecinvideo: reget_buffer() failed to allocate a frame\n"); + return -1; + } + + memcpy(cin->frame.data[1], cin->palette, sizeof(cin->palette)); + cin->frame.palette_has_changed = 1; for (y = 0; y < cin->avctx->height; ++y) memcpy(cin->frame.data[0] + (cin->avctx->height - 1 - y) * cin->frame.linesize[0], cin->bitmap_table[CIN_CUR_BMP] + y * cin->avctx->width, |