Merge commit '16158da9607f2f84232d3dd381406b2f2449ec74'
authorMichael Niedermayer <michaelni@gmx.at>
Tue, 25 Nov 2014 11:16:07 +0000 (12:16 +0100)
committerMichael Niedermayer <michaelni@gmx.at>
Tue, 25 Nov 2014 11:19:08 +0000 (12:19 +0100)
* commit '16158da9607f2f84232d3dd381406b2f2449ec74':
  hnm4: Use av_image_check_size

See: e23b18321fb5cffb6e05d0b0ef00de9733f560da
Merged-by: Michael Niedermayer <michaelni@gmx.at>
1  2 
libavcodec/hnm4video.c

diff --combined libavcodec/hnm4video.c
@@@ -3,25 -3,26 +3,26 @@@
   *
   * Copyright (c) 2012 David Kment
   *
 - * 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
   */
  
  #include <string.h>
  
+ #include "libavutil/imgutils.h"
  #include "libavutil/internal.h"
  #include "libavutil/intreadwrite.h"
  #include "libavutil/mem.h"
@@@ -36,8 -37,8 +37,8 @@@
  
  typedef struct Hnm4VideoContext {
      uint8_t version;
 -    uint16_t width;
 -    uint16_t height;
 +    int width;
 +    int height;
      uint8_t *current;
      uint8_t *previous;
      uint8_t *buffer1;
@@@ -78,7 -79,7 +79,7 @@@ static void unpack_intraframe(AVCodecCo
          if (getbit(&gb, &bitbuf, &bits)) {
              if (writeoffset >= hnm->width * hnm->height) {
                  av_log(avctx, AV_LOG_ERROR,
 -                       "Attempting to write out of bounds");
 +                       "Attempting to write out of bounds\n");
                  break;
              }
              hnm->current[writeoffset++] = bytestream2_get_byte(&gb);
              count  += 2;
              offset += writeoffset;
              if (offset < 0 || offset + count >= hnm->width * hnm->height) {
 -                av_log(avctx, AV_LOG_ERROR, "Attempting to read out of bounds");
 +                av_log(avctx, AV_LOG_ERROR, "Attempting to read out of bounds\n");
                  break;
              } else if (writeoffset + count >= hnm->width * hnm->height) {
                  av_log(avctx, AV_LOG_ERROR,
 -                       "Attempting to write out of bounds");
 +                       "Attempting to write out of bounds\n");
                  break;
              }
              while (count--) {
@@@ -146,8 -147,7 +147,8 @@@ static void decode_interframe_v4(AVCode
  {
      Hnm4VideoContext *hnm = avctx->priv_data;
      GetByteContext gb;
 -    uint32_t writeoffset = 0, count, left, offset;
 +    uint32_t writeoffset = 0;
 +    int count, left, offset;
      uint8_t tag, previous, backline, backward, swap;
  
      bytestream2_init(&gb, src, size);
          if (count == 0) {
              tag = bytestream2_get_byte(&gb) & 0xE0;
              tag = tag >> 5;
 +
              if (tag == 0) {
 +                if (writeoffset + 2 > hnm->width * hnm->height) {
 +                    av_log(avctx, AV_LOG_ERROR, "writeoffset out of bounds\n");
 +                    break;
 +                }
                  hnm->current[writeoffset++] = bytestream2_get_byte(&gb);
                  hnm->current[writeoffset++] = bytestream2_get_byte(&gb);
              } else if (tag == 1) {
                  writeoffset += count;
              } else if (tag == 3) {
                  count = bytestream2_get_byte(&gb) * 2;
 +                if (writeoffset + count > hnm->width * hnm->height) {
 +                    av_log(avctx, AV_LOG_ERROR, "writeoffset out of bounds\n");
 +                    break;
 +                }
                  while (count > 0) {
                      hnm->current[writeoffset++] = bytestream2_peek_byte(&gb);
                      count--;
              } else {
                  break;
              }
 +            if (writeoffset > hnm->width * hnm->height) {
 +                av_log(avctx, AV_LOG_ERROR, "writeoffset out of bounds\n");
 +                break;
 +            }
          } else {
              previous = bytestream2_peek_byte(&gb) & 0x20;
              backline = bytestream2_peek_byte(&gb) & 0x40;
  
              left = count;
  
 -            if (!backward && offset + count >= hnm->width * hnm->height) {
 -                av_log(avctx, AV_LOG_ERROR, "Attempting to read out of bounds");
 +            if (!backward && offset + 2*count > hnm->width * hnm->height) {
 +                av_log(avctx, AV_LOG_ERROR, "Attempting to read out of bounds\n");
                  break;
 -            } else if (backward && offset >= hnm->width * hnm->height) {
 -                av_log(avctx, AV_LOG_ERROR, "Attempting to read out of bounds");
 +            } else if (backward && offset + 1 >= hnm->width * hnm->height) {
 +                av_log(avctx, AV_LOG_ERROR, "Attempting to read out of bounds\n");
                  break;
 -            } else if (writeoffset + count >= hnm->width * hnm->height) {
 +            } else if (writeoffset + 2*count > hnm->width * hnm->height) {
                  av_log(avctx, AV_LOG_ERROR,
 -                       "Attempting to write out of bounds");
 +                       "Attempting to write out of bounds\n");
                  break;
              }
 +            if(backward) {
 +                if (offset < (!!backline)*(2 * hnm->width - 1) + 2*(left-1)) {
 +                    av_log(avctx, AV_LOG_ERROR, "Attempting to read out of bounds\n");
 +                    break;
 +                }
 +            } else {
 +                if (offset < (!!backline)*(2 * hnm->width - 1)) {
 +                    av_log(avctx, AV_LOG_ERROR, "Attempting to read out of bounds\n");
 +                    break;
 +                }
 +            }
  
              if (previous) {
                  while (left > 0) {
@@@ -287,10 -263,6 +288,10 @@@ static void decode_interframe_v4a(AVCod
              if (tag == 0) {
                  writeoffset += bytestream2_get_byte(&gb);
              } else if (tag == 1) {
 +                if (writeoffset + hnm->width >= hnm->width * hnm->height) {
 +                    av_log(avctx, AV_LOG_ERROR, "writeoffset out of bounds\n");
 +                    break;
 +                }
                  hnm->current[writeoffset]              = bytestream2_get_byte(&gb);
                  hnm->current[writeoffset + hnm->width] = bytestream2_get_byte(&gb);
                  writeoffset++;
              } else if (tag == 3) {
                  break;
              }
 +            if (writeoffset > hnm->width * hnm->height) {
 +                av_log(avctx, AV_LOG_ERROR, "writeoffset out of bounds\n");
 +                break;
 +            }
          } else {
              delta    = bytestream2_peek_byte(&gb) & 0x80;
              previous = bytestream2_peek_byte(&gb) & 0x40;
              offset  = writeoffset;
              offset += bytestream2_get_le16(&gb);
  
 -            if (delta)
 +            if (delta) {
 +                if (offset < 0x10000) {
 +                    av_log(avctx, AV_LOG_ERROR, "Attempting to read out of bounds\n");
 +                    break;
 +                }
                  offset -= 0x10000;
 +            }
  
              if (offset + hnm->width + count >= hnm->width * hnm->height) {
 -                av_log(avctx, AV_LOG_ERROR, "Attempting to read out of bounds");
 +                av_log(avctx, AV_LOG_ERROR, "Attempting to read out of bounds\n");
                  break;
              } else if (writeoffset + hnm->width + count >= hnm->width * hnm->height) {
 -                av_log(avctx, AV_LOG_ERROR, "Attempting to write out of bounds");
 +                av_log(avctx, AV_LOG_ERROR, "Attempting to write out of bounds\n");
                  break;
              }
  
@@@ -397,23 -360,17 +398,23 @@@ static int hnm_decode_frame(AVCodecCont
      int ret;
      uint16_t chunk_id;
  
 -    if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) {
 -        av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
 -        return ret;
 +    if (avpkt->size < 8) {
 +        av_log(avctx, AV_LOG_ERROR, "packet too small\n");
 +        return AVERROR_INVALIDDATA;
      }
  
      chunk_id = AV_RL16(avpkt->data + 4);
  
      if (chunk_id == HNM4_CHUNK_ID_PL) {
          hnm_update_palette(avctx, avpkt->data, avpkt->size);
 -        frame->palette_has_changed = 1;
      } else if (chunk_id == HNM4_CHUNK_ID_IZ) {
 +        if (avpkt->size < 12) {
 +            av_log(avctx, AV_LOG_ERROR, "packet too small\n");
 +            return AVERROR_INVALIDDATA;
 +        }
 +        if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
 +            return ret;
 +
          unpack_intraframe(avctx, avpkt->data + 12, avpkt->size - 12);
          memcpy(hnm->previous, hnm->current, hnm->width * hnm->height);
          if (hnm->version == 0x4a)
          memcpy(frame->data[1], hnm->palette, 256 * 4);
          *got_frame = 1;
      } else if (chunk_id == HNM4_CHUNK_ID_IU) {
 +        if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
 +            return ret;
 +
          if (hnm->version == 0x4a) {
              decode_interframe_v4a(avctx, avpkt->data + 8, avpkt->size - 8);
              memcpy(hnm->processed, hnm->current, hnm->width * hnm->height);
  static av_cold int hnm_decode_init(AVCodecContext *avctx)
  {
      Hnm4VideoContext *hnm = avctx->priv_data;
+     int ret;
  
      if (avctx->extradata_size < 1) {
          av_log(avctx, AV_LOG_ERROR,
          return AVERROR_INVALIDDATA;
      }
  
+     ret = av_image_check_size(avctx->width, avctx->height, 0, avctx);
+     if (ret < 0)
+         return ret;
      hnm->version   = avctx->extradata[0];
      avctx->pix_fmt = AV_PIX_FMT_PAL8;
      hnm->width     = avctx->width;
      hnm->buffer2   = av_mallocz(avctx->width * avctx->height);
      hnm->processed = av_mallocz(avctx->width * avctx->height);
  
 -    if (!hnm->buffer1 || !hnm->buffer2 || !hnm->processed) {
 +    if (   !hnm->buffer1 || !hnm->buffer2 || !hnm->processed
 +        || avctx->width * avctx->height == 0
 +        || avctx->height % 2) {
          av_log(avctx, AV_LOG_ERROR, "av_mallocz() failed\n");
          av_freep(&hnm->buffer1);
          av_freep(&hnm->buffer2);