Check for out of bound reads in vmd_decode() of vmd video decoder.
authorLaurent Aimar <fenrir@videolan.org>
Sat, 24 Sep 2011 22:08:49 +0000 (00:08 +0200)
committerMichael Niedermayer <michaelni@gmx.at>
Sat, 1 Oct 2011 18:25:10 +0000 (20:25 +0200)
Signed-off-by: Michael Niedermayer <michaelni@gmx.at>
(cherry picked from commit e07377e7366d038d6f28792c46745463a0542650)

libavcodec/vmdav.c

index 0a91d73..eb2d208 100644 (file)
@@ -203,6 +203,7 @@ static void vmd_decode(VmdVideoContext *s)
     const unsigned char *p_end = s->buf + s->size;
 
     const unsigned char *pb;
+    const unsigned char *pb_end;
     unsigned char meth;
     unsigned char *dp;   /* pointer to current frame */
     unsigned char *pp;   /* pointer to previous frame */
@@ -248,6 +249,8 @@ static void vmd_decode(VmdVideoContext *s)
 
     /* check if there is a new palette */
     if (s->buf[15] & 0x02) {
+        if (p_end - p < 2 + 3 * PALETTE_COUNT)
+            return;
         p += 2;
         palette32 = (unsigned int *)s->palette;
         for (i = 0; i < PALETTE_COUNT; i++) {
@@ -256,16 +259,17 @@ static void vmd_decode(VmdVideoContext *s)
             b = *p++ * 4;
             palette32[i] = (r << 16) | (g << 8) | (b);
         }
-        s->size -= (256 * 3 + 2);
     }
-    if (s->size >= 0) {
+    if (p < p_end) {
         /* originally UnpackFrame in VAG's code */
         pb = p;
+        pb_end = p_end;
         meth = *pb++;
         if (meth & 0x80) {
             lz_unpack(pb, p_end - pb, s->unpack_buffer, s->unpack_buffer_size);
             meth &= 0x7F;
             pb = s->unpack_buffer;
+            pb_end = s->unpack_buffer + s->unpack_buffer_size;
         }
 
         dp = &s->frame.data[0][frame_y * s->frame.linesize[0] + frame_x];
@@ -275,10 +279,12 @@ static void vmd_decode(VmdVideoContext *s)
             for (i = 0; i < frame_height; i++) {
                 ofs = 0;
                 do {
+                    if (pb_end - pb < 1)
+                        return;
                     len = *pb++;
                     if (len & 0x80) {
                         len = (len & 0x7F) + 1;
-                        if (ofs + len > frame_width)
+                        if (ofs + len > frame_width || pb_end - pb < len)
                             return;
                         memcpy(&dp[ofs], pb, len);
                         pb += len;
@@ -303,6 +309,8 @@ static void vmd_decode(VmdVideoContext *s)
 
         case 2:
             for (i = 0; i < frame_height; i++) {
+                if (pb_end -pb < frame_width)
+                    return;
                 memcpy(dp, pb, frame_width);
                 pb += frame_width;
                 dp += s->frame.linesize[0];
@@ -314,13 +322,20 @@ static void vmd_decode(VmdVideoContext *s)
             for (i = 0; i < frame_height; i++) {
                 ofs = 0;
                 do {
+                    if (pb_end - pb < 1)
+                        return;
                     len = *pb++;
                     if (len & 0x80) {
                         len = (len & 0x7F) + 1;
+                        if (pb_end - pb < 1)
+                            return;
                         if (*pb++ == 0xFF)
                             len = rle_unpack(pb, &dp[ofs], len, frame_width - ofs);
-                        else
+                        else {
+                        if (pb_end - pb < len)
+                            return;
                             memcpy(&dp[ofs], pb, len);
+                        }
                         pb += len;
                         ofs += len;
                     } else {