CVE-2013-7020: Improper Restriction of Operations within the Bounds of a Memory Buffer (CWE-119)
value: The read_header function in libavcodec/ffv1dec.c in FFmpeg before 2.1 does not properly enforce certain bit-count and colorspace constraints, which allows remote attackers to cause a denial of service (out-of-bounds array access) or possibly have unspecified other impact via crafted FFV1 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/ffv1dec.c
Commit date: 2013-08-30 13:53:58 +0200
Commit message: ffv1dec: Check bits_per_raw_sample and colorspace for equality in ver 0/1 headers

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

Diff: diff --git a/libavcodec/ffv1dec.c b/libavcodec/ffv1dec.c
index 3081207a049..38e0849d87d 100644
--- a/libavcodec/ffv1dec.c
+++ b/libavcodec/ffv1dec.c
@@ -578,11 +578,11 @@ static int read_header(FFV1Context *f)
     RangeCoder *const c = &f->slice_context[0]->c;
 
     memset(state, 128, sizeof(state));
 
     if (f->version < 2) {
-        int chroma_planes, chroma_h_shift, chroma_v_shift, transparency;
+        int chroma_planes, chroma_h_shift, chroma_v_shift, transparency, colorspace, bits_per_raw_sample;
         unsigned v= get_symbol(c, state, 0);
         if (v >= 2) {
             av_log(f->avctx, AV_LOG_ERROR, "invalid version %d in ver01 header\n", v);
             return AVERROR_INVALIDDATA;
         }
@@ -591,30 +591,31 @@ static int read_header(FFV1Context *f)
         if (f->ac > 1) {
             for (i = 1; i < 256; i++)
                 f->state_transition[i] = get_symbol(c, state, 1) + c->one_state[i];
         }
 
-        f->colorspace = get_symbol(c, state, 0); //YUV cs type
-
-        if (f->version > 0)
-            f->avctx->bits_per_raw_sample = get_symbol(c, state, 0);
-
+        colorspace     = get_symbol(c, state, 0); //YUV cs type
+        bits_per_raw_sample = f->version > 0 ? get_symbol(c, state, 0) : f->avctx->bits_per_raw_sample;
         chroma_planes  = get_rac(c, state);
         chroma_h_shift = get_symbol(c, state, 0);
         chroma_v_shift = get_symbol(c, state, 0);
         transparency   = get_rac(c, state);
 
         if (f->plane_count) {
-            if (   chroma_planes != f->chroma_planes
+            if (   colorspace    != f->colorspace
+                || bits_per_raw_sample != f->avctx->bits_per_raw_sample
+                || chroma_planes != f->chroma_planes
                 || chroma_h_shift!= f->chroma_h_shift
                 || chroma_v_shift!= f->chroma_v_shift
                 || transparency  != f->transparency) {
                 av_log(f->avctx, AV_LOG_ERROR, "Invalid change of global parameters\n");
                 return AVERROR_INVALIDDATA;
             }
         }
 
+        f->colorspace     = colorspace;
+        f->avctx->bits_per_raw_sample = bits_per_raw_sample;
         f->chroma_planes  = chroma_planes;
         f->chroma_h_shift = chroma_h_shift;
         f->chroma_v_shift = chroma_v_shift;
         f->transparency   = transparency;
 

Vulnerable code:         int chroma_planes, chroma_h_shift, chroma_v_shift, transparency;
        f->colorspace = get_symbol(c, state, 0); //YUV cs type

        if (f->version > 0)
            f->avctx->bits_per_raw_sample = get_symbol(c, state, 0);

            if (   chroma_planes != f->chroma_planes
Fixed code:         int chroma_planes, chroma_h_shift, chroma_v_shift, transparency, colorspace, bits_per_raw_sample;
        colorspace     = get_symbol(c, state, 0); //YUV cs type
        bits_per_raw_sample = f->version > 0 ? get_symbol(c, state, 0) : f->avctx->bits_per_raw_sample;
            if (   colorspace    != f->colorspace
                || bits_per_raw_sample != f->avctx->bits_per_raw_sample
                || chroma_planes != f->chroma_planes
        f->colorspace     = colorspace;
        f->avctx->bits_per_raw_sample = bits_per_raw_sample;