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

libavcodec/vmdav.c

index eb2d208..90cbab8 100644 (file)
@@ -153,32 +153,39 @@ static void lz_unpack(const unsigned char *src, int src_len,
     }
 }
 
-static int rle_unpack(const unsigned char *src, unsigned char *dest,
-    int src_len, int dest_len)
+static int rle_unpack(const unsigned char *src, int src_len, int src_count,
+                      unsigned char *dest, int dest_len)
 {
     const unsigned char *ps;
+    const unsigned char *ps_end;
     unsigned char *pd;
     int i, l;
     unsigned char *dest_end = dest + dest_len;
 
     ps = src;
+    ps_end = src + src_len;
     pd = dest;
-    if (src_len & 1)
+    if (src_count & 1) {
+        if (ps_end - ps < 1)
+            return 0;
         *pd++ = *ps++;
+    }
 
-    src_len >>= 1;
+    src_count >>= 1;
     i = 0;
     do {
+        if (ps_end - ps < 1)
+            break;
         l = *ps++;
         if (l & 0x80) {
             l = (l & 0x7F) * 2;
-            if (pd + l > dest_end)
+            if (pd + l > dest_end || ps_end - ps < l)
                 return ps - src;
             memcpy(pd, ps, l);
             ps += l;
             pd += l;
         } else {
-            if (pd + i > dest_end)
+            if (pd + i > dest_end || ps_end - ps < 2)
                 return ps - src;
             for (i = 0; i < l; i++) {
                 *pd++ = ps[0];
@@ -187,7 +194,7 @@ static int rle_unpack(const unsigned char *src, unsigned char *dest,
             ps += 2;
         }
         i += l;
-    } while (i < src_len);
+    } while (i < src_count);
 
     return ps - src;
 }
@@ -330,7 +337,7 @@ static void vmd_decode(VmdVideoContext *s)
                         if (pb_end - pb < 1)
                             return;
                         if (*pb++ == 0xFF)
-                            len = rle_unpack(pb, &dp[ofs], len, frame_width - ofs);
+                            len = rle_unpack(pb, pb_end - pb, len, &dp[ofs], frame_width - ofs);
                         else {
                         if (pb_end - pb < len)
                             return;