diff options
| author | Ronald S. Bultje <[email protected]> | 2012-03-11 07:28:54 -0700 | 
|---|---|---|
| committer | Reinhard Tartler <[email protected]> | 2012-03-14 20:47:19 +0100 | 
| commit | 26521d87ba22fe1bb49f1f0796c7227017064e7f (patch) | |
| tree | e8056949002364d4ac308e16a0234ff7f8ac48c6 | |
| parent | e1a4143793afc98d623fa4c56835b837b74bac1d (diff) | |
dsicinvideo: validate buffer offset before copying pixels.
Found-by: Mateusz "j00ru" Jurczyk and Gynvael Coldwind
CC: [email protected]
(cherry picked from commit c95fefa0420be9cc0f09a95041acf11114aaacd0)
Signed-off-by: Reinhard Tartler <[email protected]>
| -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, | 
