From 60f50374f1955442dc987abc4a6c61c2109620c2 Mon Sep 17 00:00:00 2001 From: Luca Barbato Date: Sun, 1 Nov 2015 04:07:42 +0100 Subject: rpza: Check the blocks left before processing one Bug-Id: 903 CC: libav-stable@libav.org Reported-By: Mateusz "j00ru" Jurczyk and Gynvael Coldwind Signed-off-by: Luca Barbato --- libavcodec/rpza.c | 52 +++++++++++++++++++++++++++++++--------------------- 1 file changed, 31 insertions(+), 21 deletions(-) (limited to 'libavcodec/rpza.c') diff --git a/libavcodec/rpza.c b/libavcodec/rpza.c index f365a06..d1c959d 100644 --- a/libavcodec/rpza.c +++ b/libavcodec/rpza.c @@ -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; -- cgit v1.1