Merge commit 'eafbc6716cede6d4a652f8bedf82f2901c68d06d'
authorMichael Niedermayer <michaelni@gmx.at>
Wed, 20 May 2015 16:31:55 +0000 (18:31 +0200)
committerMichael Niedermayer <michaelni@gmx.at>
Wed, 20 May 2015 16:41:43 +0000 (18:41 +0200)
* commit 'eafbc6716cede6d4a652f8bedf82f2901c68d06d':
  vmnc: Delay pixel size check

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

diff --combined libavcodec/vmnc.c
@@@ -2,20 -2,20 +2,20 @@@
   * VMware Screen Codec (VMnc) decoder
   * Copyright (c) 2006 Konstantin Shishkov
   *
 - * 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
   */
  
@@@ -291,11 -291,6 +291,11 @@@ static int decode_hextile(VmncContext *
                          fg = vmnc_get_pixel(gb, bpp, c->bigendian);
                      xy = bytestream2_get_byte(gb);
                      wh = bytestream2_get_byte(gb);
 +                    if (   (xy >> 4) + (wh >> 4) + 1 > w - i
 +                        || (xy & 0xF) + (wh & 0xF)+1 > h - j) {
 +                        av_log(c->avctx, AV_LOG_ERROR, "Rectangle outside picture\n");
 +                        return AVERROR_INVALIDDATA;
 +                    }
                      paint_rect(dst2, xy >> 4, xy & 0xF,
                                 (wh>>4)+1, (wh & 0xF)+1, fg, bpp, stride);
                  }
@@@ -312,8 -307,6 +312,8 @@@ static void reset_buffers(VmncContext *
      av_freep(&c->curmask);
      av_freep(&c->screendta);
      c->cur_w = c->cur_h = 0;
 +    c->cur_hx = c->cur_hy = 0;
 +
  }
  
  static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
      uint8_t *outptr;
      int dx, dy, w, h, depth, enc, chunks, res, size_left, ret;
  
 -    if ((ret = ff_reget_buffer(avctx, c->pic)) < 0) {
 -        av_log(avctx, AV_LOG_ERROR, "reget_buffer() failed\n");
 +    if ((ret = ff_reget_buffer(avctx, c->pic)) < 0)
          return ret;
 -    }
  
      bytestream2_init(gb, buf, buf_size);
  
      bytestream2_skip(gb, 2);
      chunks = bytestream2_get_be16(gb);
      while (chunks--) {
 +        if (bytestream2_get_bytes_left(gb) < 12) {
 +            av_log(avctx, AV_LOG_ERROR, "Premature end of data!\n");
 +            return -1;
 +        }
          dx  = bytestream2_get_be16(gb);
          dy  = bytestream2_get_be16(gb);
          w   = bytestream2_get_be16(gb);
          size_left = bytestream2_get_bytes_left(gb);
          switch (enc) {
          case MAGIC_WMVd: // cursor
 +            if (w*(int64_t)h*c->bpp2 > INT_MAX/2 - 2) {
 +                av_log(avctx, AV_LOG_ERROR, "dimensions too large\n");
 +                return AVERROR_INVALIDDATA;
 +            }
              if (size_left < 2 + w * h * c->bpp2 * 2) {
                  av_log(avctx, AV_LOG_ERROR,
                         "Premature end of data! (need %i got %i)\n",
              c->pic->pict_type = AV_PICTURE_TYPE_I;
              depth = bytestream2_get_byte(gb);
              if (depth != c->bpp) {
-                 av_log(avctx, AV_LOG_INFO,
-                        "Depth mismatch. Container %i bpp, "
-                        "Frame data: %i bpp\n",
-                        c->bpp, depth);
+                 av_log(avctx, AV_LOG_WARNING, "Depth mismatch. "
+                        "Container %i bpp / Codec %i bpp\n", c->bpp, depth);
+                 if (depth != 8 && depth != 16 && depth != 32) {
+                     av_log(avctx, AV_LOG_ERROR,
+                            "Unsupported codec bitdepth %i\n", depth);
+                     return AVERROR_INVALIDDATA;
+                 }
+                 /* reset values */
+                 c->bpp  = depth;
+                 c->bpp2 = c->bpp / 8;
              }
              bytestream2_skip(gb, 1);
              c->bigendian = bytestream2_get_byte(gb);
@@@ -537,8 -532,11 +545,11 @@@ static av_cold int decode_init(AVCodecC
      case 16:
          avctx->pix_fmt = AV_PIX_FMT_RGB555;
          break;
+     case 24:
+         /* 24 bits is not technically supported, but some clients might
+          * mistakenly set it -- delay the actual check until decode_frame() */
      case 32:
 -        avctx->pix_fmt = AV_PIX_FMT_RGB32;
 +        avctx->pix_fmt = AV_PIX_FMT_0RGB32;
          break;
      default:
          av_log(avctx, AV_LOG_ERROR, "Unsupported bitdepth %i\n", c->bpp);
@@@ -558,9 -556,9 +569,9 @@@ static av_cold int decode_end(AVCodecCo
  
      av_frame_free(&c->pic);
  
 -    av_free(c->curbits);
 -    av_free(c->curmask);
 -    av_free(c->screendta);
 +    av_freep(&c->curbits);
 +    av_freep(&c->curmask);
 +    av_freep(&c->screendta);
      return 0;
  }