CVE-2013-7009: Improper Restriction of Operations within the Bounds of a Memory Buffer (CWE-119)
value: The rpza_decode_stream function in libavcodec/rpza.c in FFmpeg before 2.1 does not properly maintain a pointer to pixel data, which allows remote attackers to cause a denial of service (out-of-bounds array access) or possibly have unspecified other impact via crafted Apple RPZA data.
CWE description: The product performs operations on a memory buffer, but it reads from or writes to a memory location outside the buffer's intended boundary. This may result in read or write operations on unexpected memory locations that could be linked to other variables, data structures, or internal program data.
Published: 2013-12-09T16:36Z
Repository: https://github.com/FFmpeg/FFmpeg
Language: C
Files changed: libavcodec/rpza.c
Commit date: 2013-08-22 01:26:02 +0200
Commit message: avcodec/rpza: Perform pointer advance and checks before using the pointers

Fixes out of array accesses
Fixes Ticket2850

Signed-off-by: Michael Niedermayer <michaelni@gmx.at>

Diff: diff --git a/libavcodec/rpza.c b/libavcodec/rpza.c
index 2aa0091d326..416f8b67228 100644
--- a/libavcodec/rpza.c
+++ b/libavcodec/rpza.c
@@ -83,11 +83,11 @@ static void rpza_decode_stream(RpzaContext *s)
     unsigned char index, idx;
     unsigned short ta, tb;
     unsigned short *pixels = (unsigned short *)s->frame.data[0];
 
     int row_ptr = 0;
-    int pixel_ptr = 0;
+    int pixel_ptr = -4;
     int block_ptr;
     int pixel_x, pixel_y;
     int total_blocks;
 
     /* First byte is always 0xe1. Warn if it's different */
@@ -139,19 +139,19 @@ static void rpza_decode_stream(RpzaContext *s)
         /* Fill blocks with one color */
         case 0xa0:
             colorA = AV_RB16 (&s->buf[stream_ptr]);
             stream_ptr += 2;
             while (n_blocks--) {
+                ADVANCE_BLOCK()
                 block_ptr = row_ptr + pixel_ptr;
                 for (pixel_y = 0; pixel_y < 4; pixel_y++) {
                     for (pixel_x = 0; pixel_x < 4; pixel_x++){
                         pixels[block_ptr] = colorA;
                         block_ptr++;
                     }
                     block_ptr += row_inc;
                 }
-                ADVANCE_BLOCK();
             }
             break;
 
         /* Fill blocks with 4 colors */
         case 0xc0:
@@ -186,28 +186,29 @@ static void rpza_decode_stream(RpzaContext *s)
             color4[2] |= ((21 * ta + 11 * tb) >> 5);
 
             if (s->size - stream_ptr < n_blocks * 4)
                 return;
             while (n_blocks--) {
+                ADVANCE_BLOCK();
                 block_ptr = row_ptr + pixel_ptr;
                 for (pixel_y = 0; pixel_y < 4; pixel_y++) {
                     index = s->buf[stream_ptr++];
                     for (pixel_x = 0; pixel_x < 4; pixel_x++){
                         idx = (index >> (2 * (3 - pixel_x))) & 0x03;
                         pixels[block_ptr] = color4[idx];
                         block_ptr++;
                     }
                     block_ptr += row_inc;
                 }
-                ADVANCE_BLOCK();
             }
             break;
 
         /* Fill block with 16 colors */
         case 0x00:
             if (s->size - stream_ptr < 16)
                 return;
+            ADVANCE_BLOCK();
             block_ptr = row_ptr + pixel_ptr;
             for (pixel_y = 0; pixel_y < 4; pixel_y++) {
                 for (pixel_x = 0; pixel_x < 4; pixel_x++){
                     /* We already have color of upper left pixel */
                     if ((pixel_y != 0) || (pixel_x !=0)) {
@@ -217,11 +218,10 @@ static void rpza_decode_stream(RpzaContext *s)
                     pixels[block_ptr] = colorA;
                     block_ptr++;
                 }
                 block_ptr += row_inc;
             }
-            ADVANCE_BLOCK();
             break;
 
         /* Unknown opcode */
         default:
             av_log(s->avctx, AV_LOG_ERROR, "Unknown opcode %d in rpza chunk."

Vulnerable code:     int pixel_ptr = 0;
                ADVANCE_BLOCK();
                ADVANCE_BLOCK();
            ADVANCE_BLOCK();
Fixed code:     int pixel_ptr = -4;
                ADVANCE_BLOCK()
                ADVANCE_BLOCK();
            ADVANCE_BLOCK();