rpza: Check the blocks left before processing one
authorLuca Barbato <lu_zero@gentoo.org>
Sun, 1 Nov 2015 03:07:42 +0000 (04:07 +0100)
committerLuca Barbato <lu_zero@gentoo.org>
Mon, 2 Nov 2015 15:26:04 +0000 (16:26 +0100)
Bug-Id: 903
CC: libav-stable@libav.org
Reported-By: Mateusz "j00ru" Jurczyk and Gynvael Coldwind
Signed-off-by: Luca Barbato <lu_zero@gentoo.org>
libavcodec/rpza.c

index f365a06..d1c959d 100644 (file)
@@ -52,23 +52,25 @@ typedef struct RpzaContext {
     GetByteContext gb;
 } RpzaContext;
 
-#define ADVANCE_BLOCK() \
-{ \
-    pixel_ptr += 4; \
-    if (pixel_ptr >= width) \
-    { \
-        pixel_ptr = 0; \
-        row_ptr += stride * 4; \
-    } \
-    total_blocks--; \
-    if (total_blocks < 0) \
-    { \
-        av_log(s->avctx, AV_LOG_ERROR, "warning: block counter just went negative (this should not happen)\n"); \
-        return; \
-    } \
-}
+#define CHECK_BLOCK()                                                         \
+    if (total_blocks < 1) {                                                    \
+        av_log(s->avctx, AV_LOG_ERROR,                                         \
+               "Block counter just went negative (this should not happen)\n"); \
+        return AVERROR_INVALIDDATA;                                            \
+    }                                                                          \
+
+#define ADVANCE_BLOCK()             \
+    {                               \
+        pixel_ptr += 4;             \
+        if (pixel_ptr >= width)     \
+        {                           \
+            pixel_ptr = 0;          \
+            row_ptr  += stride * 4; \
+        }                           \
+        total_blocks--;             \
+    }
 
-static void rpza_decode_stream(RpzaContext *s)
+static int rpza_decode_stream(RpzaContext *s)
 {
     int width = s->avctx->width;
     int stride = s->frame->linesize[0] / 2;
@@ -126,7 +128,8 @@ static void rpza_decode_stream(RpzaContext *s)
         /* Skip blocks */
         case 0x80:
             while (n_blocks--) {
-              ADVANCE_BLOCK();
+                CHECK_BLOCK();
+                ADVANCE_BLOCK();
             }
             break;
 
@@ -134,6 +137,7 @@ static void rpza_decode_stream(RpzaContext *s)
         case 0xa0:
             colorA = bytestream2_get_be16(&s->gb);
             while (n_blocks--) {
+                CHECK_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++){
@@ -177,8 +181,9 @@ static void rpza_decode_stream(RpzaContext *s)
             color4[2] |= ((21 * ta + 11 * tb) >> 5);
 
             if (bytestream2_get_bytes_left(&s->gb) < n_blocks * 4)
-                return;
+                return AVERROR_INVALIDDATA;
             while (n_blocks--) {
+                CHECK_BLOCK();
                 block_ptr = row_ptr + pixel_ptr;
                 for (pixel_y = 0; pixel_y < 4; pixel_y++) {
                     uint8_t index = bytestream2_get_byteu(&s->gb);
@@ -196,7 +201,8 @@ static void rpza_decode_stream(RpzaContext *s)
         /* Fill block with 16 colors */
         case 0x00:
             if (bytestream2_get_bytes_left(&s->gb) < 30)
-                return;
+                return AVERROR_INVALIDDATA;
+            CHECK_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++){
@@ -216,9 +222,11 @@ static void rpza_decode_stream(RpzaContext *s)
             av_log(s->avctx, AV_LOG_ERROR, "Unknown opcode %d in rpza chunk."
                  " Skip remaining %d bytes of chunk data.\n", opcode,
                  bytestream2_get_bytes_left(&s->gb));
-            return;
+            return AVERROR_INVALIDDATA;
         } /* Opcode switch */
     }
+
+    return 0;
 }
 
 static av_cold int rpza_decode_init(AVCodecContext *avctx)
@@ -249,7 +257,9 @@ static int rpza_decode_frame(AVCodecContext *avctx,
         return ret;
     }
 
-    rpza_decode_stream(s);
+    ret = rpza_decode_stream(s);
+    if (ret < 0)
+        return ret;
 
     if ((ret = av_frame_ref(data, s->frame)) < 0)
         return ret;