Hi,

according to the WebP Lossless Bitstream Specification [1] "each transform is allowed to be used only once". Attached patch adds checks for this to avoid crashes decoding broken files.

Best regards,
Andreas

1: https://developers.google.com/speed/webp/docs/webp_lossless_bitstream_specification#3_transformations
>From d80baa7f786ca326891e145a000fbecdde55da80 Mon Sep 17 00:00:00 2001
From: Andreas Cadhalpun <andreas.cadhal...@googlemail.com>
Date: Thu, 5 Mar 2015 22:48:28 +0100
Subject: [PATCH] webp: ensure that each transform is only used once

According to the WebP Lossless Bitstream Specification
"each transform is allowed to be used only once".

If a transform is more than once this can lead to memory
corruption.

Signed-off-by: Andreas Cadhalpun <andreas.cadhal...@googlemail.com>
---
 libavcodec/webp.c | 39 +++++++++++++++++++++++++++++++++++----
 1 file changed, 35 insertions(+), 4 deletions(-)

diff --git a/libavcodec/webp.c b/libavcodec/webp.c
index 9549c0e..2cd976f 100644
--- a/libavcodec/webp.c
+++ b/libavcodec/webp.c
@@ -1104,7 +1104,7 @@ static int vp8_lossless_decode_frame(AVCodecContext *avctx, AVFrame *p,
                                      unsigned int data_size, int is_alpha_chunk)
 {
     WebPContext *s = avctx->priv_data;
-    int w, h, ret, i;
+    int w, h, ret, i, used;
 
     if (!is_alpha_chunk) {
         s->lossless = 1;
@@ -1154,18 +1154,49 @@ static int vp8_lossless_decode_frame(AVCodecContext *avctx, AVFrame *p,
     /* parse transformations */
     s->nb_transforms = 0;
     s->reduced_width = 0;
+    used = 0;
     while (get_bits1(&s->gb)) {
         enum TransformType transform = get_bits(&s->gb, 2);
         s->transforms[s->nb_transforms++] = transform;
         switch (transform) {
         case PREDICTOR_TRANSFORM:
-            ret = parse_transform_predictor(s);
+            if (used & 1) {
+                av_log(avctx, AV_LOG_ERROR,
+                       "Predictor transform used more than once\n");
+                ret = AVERROR_INVALIDDATA;
+            } else {
+                used |= 1;
+                ret = parse_transform_predictor(s);
+            }
             break;
         case COLOR_TRANSFORM:
-            ret = parse_transform_color(s);
+            if (used & 2) {
+                av_log(avctx, AV_LOG_ERROR,
+                       "Color transform used more than once\n");
+                ret = AVERROR_INVALIDDATA;
+            } else {
+                used |= 2;
+                ret = parse_transform_color(s);
+            }
+            break;
+        case SUBTRACT_GREEN:
+            if (used & 4) {
+                av_log(avctx, AV_LOG_ERROR,
+                       "Subtract green used more than once\n");
+                ret = AVERROR_INVALIDDATA;
+            } else {
+                used |= 4;
+            }
             break;
         case COLOR_INDEXING_TRANSFORM:
-            ret = parse_transform_color_indexing(s);
+            if (used & 8) {
+                av_log(avctx, AV_LOG_ERROR,
+                       "Color indexing transform used more than once\n");
+                ret = AVERROR_INVALIDDATA;
+            } else {
+                used |= 8;
+                ret = parse_transform_color_indexing(s);
+            }
             break;
         }
         if (ret < 0)
-- 
2.1.4

_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel

Reply via email to