File gstreamer-flxdec-array-overruns.patch of Package gstreamer-0_10-plugins-good.3941

From 7c7a9f8df1b545eec1ef4461b742c3696d4d0e9e Mon Sep 17 00:00:00 2001
From: Matthew Waters <matthew@centricular.com>
Date: Wed, 23 Nov 2016 07:09:06 +1100
Subject: [PATCH] flxdec: rewrite logic based on GstByteReader/Writer

Solves overreading/writing the given arrays and will error out if the
streams asks to do that.

Also does more error checking that the stream is valid and won't
overrun any allocated arrays.  Also mitigate integer overflow errors
calculating allocation sizes.

https://bugzilla.gnome.org/show_bug.cgi?id=774859

Backported by Mike Gorse <mgorse@suse.com>
---
diff -urp gst-plugins-good-0.10.31.orig/gst/flx/flx_color.c gst-plugins-good-0.10.31/gst/flx/flx_color.c
--- gst-plugins-good-0.10.31.orig/gst/flx/flx_color.c	2011-12-11 12:48:11.000000000 -0600
+++ gst-plugins-good-0.10.31/gst/flx/flx_color.c	2016-12-20 11:12:02.143915398 -0600
@@ -101,7 +101,6 @@ flx_set_palette_vector (FlxColorSpaceCon
   } else {
     memcpy (&flxpal->palvec[start * 3], newpal, grab * 3);
   }
-
 }
 
 void
diff -urp gst-plugins-good-0.10.31.orig/gst/flx/flx_fmt.h gst-plugins-good-0.10.31/gst/flx/flx_fmt.h
--- gst-plugins-good-0.10.31.orig/gst/flx/flx_fmt.h	2011-12-11 12:48:11.000000000 -0600
+++ gst-plugins-good-0.10.31/gst/flx/flx_fmt.h	2016-12-20 11:12:02.143915398 -0600
@@ -123,78 +123,6 @@ typedef struct _FlxFrameType
 } FlxFrameType;
 #define FlxFrameTypeSize 10
 
-#if G_BYTE_ORDER == G_BIG_ENDIAN 
-#define LE_TO_BE_16(i16) ((guint16) (((i16) << 8) | ((i16) >> 8)))
-#define LE_TO_BE_32(i32) \
-    (((guint32) (LE_TO_BE_16((guint16) (i32))) << 16) | (LE_TO_BE_16((i32) >> 16)))
-
-#define FLX_FRAME_TYPE_FIX_ENDIANNESS(frm_type_p) \
-    do { \
-     (frm_type_p)->chunks = LE_TO_BE_16((frm_type_p)->chunks); \
-     (frm_type_p)->delay = LE_TO_BE_16((frm_type_p)->delay); \
-    } while(0)
-
-#define FLX_HUFFMAN_TABLE_FIX_ENDIANNESS(hffmn_table_p) \
-    do { \
-     (hffmn_table_p)->codelength = \
-	LE_TO_BE_16((hffmn_table_p)->codelength); \
-     (hffmn_table_p)->numcodes = LE_TO_BE_16((hffmn_table_p)->numcodes); \
-    } while(0)
-
-#define FLX_SEGMENT_TABLE_FIX_ENDIANNESS(sgmnt_table_p) \
-     ((sgmnt_table_p)->segments = LE_TO_BE_16((sgmnt_table_p)->segments))
-
-#define FLX_PREFIX_CHUNK_FIX_ENDIANNESS(prfx_chnk_p) \
-    do { \
-     (prfx_chnk_p)->chunks = LE_TO_BE_16((prfx_chnk_p)->chunks); \
-    } while(0)
-
-#define FLX_FRAME_CHUNK_FIX_ENDIANNESS(frm_chnk_p) \
-    do { \
-     (frm_chnk_p)->size = LE_TO_BE_32((frm_chnk_p)->size); \
-     (frm_chnk_p)->id = LE_TO_BE_16((frm_chnk_p)->id); \
-    } while(0)
-
-#define FLX_HDR_FIX_ENDIANNESS(hdr_p) \
-    do { \
-     (hdr_p)->size = LE_TO_BE_32((hdr_p)->size); \
-     (hdr_p)->type = LE_TO_BE_16((hdr_p)->type); \
-     (hdr_p)->frames = LE_TO_BE_16((hdr_p)->frames); \
-     (hdr_p)->width = LE_TO_BE_16((hdr_p)->width); \
-     (hdr_p)->height = LE_TO_BE_16((hdr_p)->height); \
-     (hdr_p)->depth = LE_TO_BE_16((hdr_p)->depth); \
-     (hdr_p)->flags = LE_TO_BE_16((hdr_p)->flags); \
-     (hdr_p)->speed = LE_TO_BE_32((hdr_p)->speed); \
-     (hdr_p)->reserved1 = LE_TO_BE_16((hdr_p)->reserved1); \
-     (hdr_p)->created = LE_TO_BE_32((hdr_p)->created); \
-     (hdr_p)->creator = LE_TO_BE_32((hdr_p)->creator); \
-     (hdr_p)->updated = LE_TO_BE_32((hdr_p)->updated); \
-     (hdr_p)->updater = LE_TO_BE_32((hdr_p)->updater); \
-     (hdr_p)->aspect_dx = LE_TO_BE_16((hdr_p)->aspect_dx); \
-     (hdr_p)->aspect_dy = LE_TO_BE_16((hdr_p)->aspect_dy); \
-     (hdr_p)->ext_flags = LE_TO_BE_16((hdr_p)->ext_flags); \
-     (hdr_p)->keyframes = LE_TO_BE_16((hdr_p)->keyframes); \
-     (hdr_p)->totalframes = LE_TO_BE_16((hdr_p)->totalframes); \
-     (hdr_p)->req_memory = LE_TO_BE_32((hdr_p)->req_memory); \
-     (hdr_p)->max_regions = LE_TO_BE_16((hdr_p)->max_regions); \
-     (hdr_p)->transp_num = LE_TO_BE_16((hdr_p)->transp_num); \
-     (hdr_p)->oframe1 = LE_TO_BE_32((hdr_p)->oframe1); \
-     (hdr_p)->oframe2 = LE_TO_BE_32((hdr_p)->oframe2); \
-    } while(0)
-#else
-
-#define LE_TO_BE_16(i16) ((i16))
-#define LE_TO_BE_32(i32) ((i32))
-
-#define FLX_FRAME_TYPE_FIX_ENDIANNESS(frm_type_p)
-#define FLX_HUFFMAN_TABLE_FIX_ENDIANNESS(hffmn_table_p)
-#define FLX_SEGMENT_TABLE_FIX_ENDIANNESS(sgmnt_table_p)
-#define FLX_PREFIX_CHUNK_FIX_ENDIANNESS(prfx_chnk_p)
-#define FLX_FRAME_CHUNK_FIX_ENDIANNESS(frm_chnk_p)
-#define FLX_HDR_FIX_ENDIANNESS(hdr_p)
-
-#endif /* G_BYTE_ORDER == G_BIG_ENDIAN */
-
 G_END_DECLS
 
 #endif /* __GST_FLX_FMT_H__ */
diff -urp gst-plugins-good-0.10.31.orig/gst/flx/gstflxdec.c gst-plugins-good-0.10.31/gst/flx/gstflxdec.c
--- gst-plugins-good-0.10.31.orig/gst/flx/gstflxdec.c	2016-12-19 14:59:54.261698948 -0600
+++ gst-plugins-good-0.10.31/gst/flx/gstflxdec.c	2017-01-03 14:38:42.763906143 -0600
@@ -1,5 +1,6 @@
 /* GStreamer
  * Copyright (C) <1999> Erik Walthinsen <omega@temple-baptist.com>
+ * Copyright (C) <2016> Matthew Waters <matthew@centricular.com>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public
@@ -24,6 +25,7 @@
 /*
  * http://www.coolutils.com/Formats/FLI
  * http://woodshole.er.usgs.gov/operations/modeling/flc.html
+ * http://www.compuphase.com/flic.htm
  */
 
 #ifdef HAVE_CONFIG_H
@@ -69,10 +71,14 @@ static gboolean gst_flxdec_src_query_han
 static gboolean gst_flxdec_src_event_handler (GstPad * pad, GstEvent * event);
 static gboolean gst_flxdec_sink_event_handler (GstPad * pad, GstEvent * event);
 
-static void flx_decode_color (GstFlxDec *, guchar *, guchar *, gint);
-static gboolean flx_decode_brun (GstFlxDec *, guchar *, guchar *);
-static gboolean flx_decode_delta_fli (GstFlxDec *, guchar *, guchar *);
-static gboolean flx_decode_delta_flc (GstFlxDec *, guchar *, guchar *);
+static gboolean flx_decode_color (GstFlxDec * flxdec, GstByteReader * reader,
+    GstByteWriter * writer, gint scale);
+static gboolean flx_decode_brun (GstFlxDec * flxdec,
+    GstByteReader * reader, GstByteWriter * writer);
+static gboolean flx_decode_delta_fli (GstFlxDec * flxdec,
+    GstByteReader * reader, GstByteWriter * writer);
+static gboolean flx_decode_delta_flc (GstFlxDec * flxdec,
+    GstByteReader * reader, GstByteWriter * writer);
 
 #define rndalign(off) ((off) + ((off) & 1))
 
@@ -226,102 +232,123 @@ gst_flxdec_sink_event_handler (GstPad *
 }
 
 static gboolean
-flx_decode_chunks (GstFlxDec * flxdec, gulong count, guchar * data,
-    guchar * dest)
+flx_decode_chunks (GstFlxDec * flxdec, gulong n_chunks, GstByteReader * reader,
+    GstByteWriter * writer)
 {
-  FlxFrameChunk *hdr;
   gboolean ret = TRUE;
 
-  g_return_val_if_fail (data != NULL, FALSE);
-
-  while (count--) {
-    hdr = (FlxFrameChunk *) data;
-    FLX_FRAME_CHUNK_FIX_ENDIANNESS (hdr);
-    data += FlxFrameChunkSize;
-
-    switch (hdr->id) {
+  while (n_chunks--) {
+    guint32 size;
+    guint16 type;
+    guint next_pos;
+
+    if (!gst_byte_reader_get_uint32_le (reader, &size))
+      goto parse_error;
+    if (!gst_byte_reader_get_uint16_le (reader, &type))
+      goto parse_error;
+    GST_LOG_OBJECT (flxdec, "chunk has type 0x%02x size %d", type, size);
+
+    next_pos = gst_byte_reader_get_pos (reader) + rndalign (size) - FlxFrameChunkSize;
+
+    if (next_pos > gst_byte_reader_get_size (reader)) {
+      GST_ERROR_OBJECT (flxdec, "incorrect size in the chunk header");
+      goto error;
+    }
+    switch (type) {
       case FLX_COLOR64:
-        flx_decode_color (flxdec, data, dest, 2);
-        data += rndalign (hdr->size) - FlxFrameChunkSize;
+        ret = flx_decode_color (flxdec, reader, writer, 2);
         break;
 
       case FLX_COLOR256:
-        flx_decode_color (flxdec, data, dest, 0);
-        data += rndalign (hdr->size) - FlxFrameChunkSize;
+        ret = flx_decode_color (flxdec, reader, writer, 0);
         break;
 
       case FLX_BRUN:
-        ret = flx_decode_brun (flxdec, data, dest);
-        data += rndalign (hdr->size) - FlxFrameChunkSize;
+        ret = flx_decode_brun (flxdec, reader, writer);
         break;
 
       case FLX_LC:
-        ret = flx_decode_delta_fli (flxdec, data, dest);
-        data += rndalign (hdr->size) - FlxFrameChunkSize;
+        ret = flx_decode_delta_fli (flxdec, reader, writer);
         break;
 
       case FLX_SS2:
-        ret = flx_decode_delta_flc (flxdec, data, dest);
-        data += rndalign (hdr->size) - FlxFrameChunkSize;
+        ret = flx_decode_delta_flc (flxdec, reader, writer);
         break;
 
       case FLX_BLACK:
-        memset (dest, 0, flxdec->size);
+        ret = gst_byte_writer_fill (writer, 0, flxdec->size);
         break;
 
       case FLX_MINI:
-        data += rndalign (hdr->size) - FlxFrameChunkSize;
         break;
 
       default:
-        GST_WARNING ("Unimplented chunk type: 0x%02x size: %d - skipping",
-            hdr->id, hdr->size);
-        data += rndalign (hdr->size) - FlxFrameChunkSize;
+        GST_WARNING ("Unimplemented chunk type: 0x%02x size: %d - skipping",
+            type, size);
         break;
     }
 
+    gst_byte_reader_set_pos (reader, next_pos);
+
     if (!ret)
       break;
   }
 
   return ret;
+
+parse_error:
+  GST_ERROR_OBJECT (flxdec, "Failed to decode chunk");
+error:
+  return FALSE;
 }
 
 
-static void
-flx_decode_color (GstFlxDec * flxdec, guchar * data, guchar * dest, gint scale)
+static gboolean
+flx_decode_color (GstFlxDec * flxdec, GstByteReader * reader,
+    GstByteWriter * writer, gint scale)
 {
-  guint packs, count, indx;
-
-  g_return_if_fail (flxdec != NULL);
-
-  packs = (data[0] + (data[1] << 8));
+  guint8 count, indx;
+  guint16 packs;
 
-  data += 2;
+  if (!gst_byte_reader_get_uint16_le (reader, &packs))
+    goto error;
   indx = 0;
 
-  GST_LOG ("GstFlxDec: cmap packs: %d", packs);
+  GST_LOG ("GstFlxDec: cmap packs: %d", (guint) packs);
   while (packs--) {
+    const guint8 *data;
+    guint16 actual_count;
+
     /* color map index + skip count */
-    indx += *data++;
+    if (!gst_byte_reader_get_uint8 (reader, &indx))
+      goto error;
 
     /* number of rgb triplets */
-    count = *data++ & 0xff;
-    if (count == 0)
-      count = 256;
+    if (!gst_byte_reader_get_uint8 (reader, &count))
+      goto error;
+
+    actual_count = count == 0 ? 256 : count;
 
-    GST_LOG ("GstFlxDec: cmap count: %d (indx: %d)", count, indx);
-    flx_set_palette_vector (flxdec->converter, indx, count, data, scale);
+    if (!gst_byte_reader_get_data (reader, count * 3, &data))
+      goto error;
 
-    data += (count * 3);
+    GST_LOG_OBJECT (flxdec, "cmap count: %d (indx: %d)", actual_count, indx);
+    flx_set_palette_vector (flxdec->converter, indx, actual_count,
+        (guchar *) data, scale);
   }
+
+  return TRUE;
+
+error:
+  GST_ERROR_OBJECT (flxdec, "Error decoding color palette");
+  return FALSE;
 }
 
 static gboolean
-flx_decode_brun (GstFlxDec * flxdec, guchar * data, guchar * dest)
+flx_decode_brun (GstFlxDec * flxdec, GstByteReader * reader,
+    GstByteWriter * writer)
 {
-  gulong count, lines, row;
-  guchar x;
+  gulong lines, row;
 
   g_return_val_if_fail (flxdec != NULL, FALSE);
 
@@ -332,83 +359,125 @@ flx_decode_brun (GstFlxDec * flxdec, guc
      * contain more then 255 RLE packets. we use the frame 
      * width instead. 
      */
-    data++;
+    if (!gst_byte_reader_skip (reader, 1))
+      goto error;
 
     row = flxdec->hdr.width;
     while (row) {
-      count = *data++;
+      gint8 count;
+
+      if (!gst_byte_reader_get_int8 (reader, &count))
+        goto error;
+
+      if (count <= 0) {
+        const guint8 *data;
 
-      if (count > 0x7f) {
         /* literal run */
-        count = 0x100 - count;
-        if ((glong) row - (glong) count < 0) {
-          GST_ERROR_OBJECT (flxdec, "Invalid BRUN packet detected.");
+        count = ABS (count);
+
+        GST_LOG_OBJECT (flxdec, "have literal run of size %d", count);
+
+        if (count > row) {
+          GST_ERROR_OBJECT (flxdec, "Invalid BRUN line detected. "
+              "bytes to write exceeds the end of the row");
           return FALSE;
         }
         row -= count;
 
-        while (count--)
-          *dest++ = *data++;
-
+        if (!gst_byte_reader_get_data (reader, count, &data))
+          goto error;
+        if (!gst_byte_writer_put_data (writer, data, count))
+          goto error;
       } else {
-        if ((glong) row - (glong) count < 0) {
-          GST_ERROR_OBJECT (flxdec, "Invalid BRUN packet detected.");
+        guint8 x;
+
+        GST_LOG_OBJECT (flxdec, "have replicate run of size %d", count);
+
+        if (count > row) {
+          GST_ERROR_OBJECT (flxdec, "Invalid BRUN packet detected."
+              "bytes to write exceeds the end of the row");
           return FALSE;
         }
 
         /* replicate run */
         row -= count;
-        x = *data++;
-
-        while (count--)
-          *dest++ = x;
+        if (!gst_byte_reader_get_uint8 (reader, &x))
+          goto error;
+        if (!gst_byte_writer_fill (writer, x, count))
+          goto error;
       }
     }
   }
 
   return TRUE;
+
+error:
+  GST_ERROR_OBJECT (flxdec, "Failed to decode BRUN packet");
+  return FALSE;
 }
 
 static gboolean
-flx_decode_delta_fli (GstFlxDec * flxdec, guchar * data, guchar * dest)
+flx_decode_delta_fli (GstFlxDec * flxdec, GstByteReader * reader,
+    GstByteWriter * writer)
 {
-  gulong count, packets, lines, start_line;
-  guchar *start_p, x;
+  guint16 start_line, lines;
+  guint line_start_i;
 
   g_return_val_if_fail (flxdec != NULL, FALSE);
   g_return_val_if_fail (flxdec->delta != NULL, FALSE);
 
   /* use last frame for delta */
-  memcpy (dest, GST_BUFFER_DATA (flxdec->delta),
-      GST_BUFFER_SIZE (flxdec->delta));
+  if (!gst_byte_writer_put_data (writer, GST_BUFFER_DATA (flxdec->delta), GST_BUFFER_SIZE (flxdec->delta)))
+    goto error;
 
-  start_line = (data[0] + (data[1] << 8));
-  lines = (data[2] + (data[3] << 8));
+  if (!gst_byte_reader_get_uint16_le (reader, &start_line))
+    goto error;
+  if (!gst_byte_reader_get_uint16_le (reader, &lines))
+    goto error;
+  GST_LOG_OBJECT (flxdec, "height %d start line %d line count %d",
+      flxdec->hdr.height, start_line, lines);
+ 
   if (start_line + lines > flxdec->hdr.height) {
     GST_ERROR_OBJECT (flxdec, "Invalid FLI packet detected. too many lines.");
     return FALSE;
   }
-  data += 4;
-
-  /* start position of delta */
-  dest += (flxdec->hdr.width * start_line);
-  start_p = dest;
 
+  line_start_i = flxdec->hdr.width * start_line;
+  if (!gst_byte_writer_set_pos (writer, line_start_i))
+    goto error;
+ 
   while (lines--) {
+    guint8 packets;
+
     /* packet count */
-    packets = *data++;
+    if (!gst_byte_reader_get_uint8 (reader, &packets))
+      goto error;
+    GST_LOG_OBJECT (flxdec, "have %d packets", packets);
 
     while (packets--) {
       /* skip count */
-      guchar skip = *data++;
-      dest += skip;
+      guint8 skip;
+      gint8 count;
+      if (!gst_byte_reader_get_uint8 (reader, &skip))
+        goto error;
+
+      /* skip bytes */
+      if (!gst_byte_writer_set_pos (writer,
+              gst_byte_writer_get_pos (writer) + skip))
+        goto error;
 
       /* RLE count */
-      count = *data++;
+      if (!gst_byte_reader_get_int8 (reader, &count))
+        goto error;
+
+      if (count < 0) {
+        guint8 x;
+ 
 
-      if (count > 0x7f) {
         /* literal run */
-        count = 0x100 - count;
+        count = ABS (count);
+        GST_LOG_OBJECT (flxdec, "have literal run of size %d at offset %d",
+            count, skip);
 
         if (skip + count > flxdec->hdr.width) {
           GST_ERROR_OBJECT (flxdec, "Invalid FLI packet detected. "
@@ -416,11 +485,16 @@ flx_decode_delta_fli (GstFlxDec * flxdec
           return FALSE;
         }
 
-        x = *data++;
-        while (count--)
-          *dest++ = x;
-
+        if (!gst_byte_reader_get_uint8 (reader, &x))
+          goto error;
+        if (!gst_byte_writer_fill (writer, x, count))
+          goto error;
       } else {
+        const guint8 *data;
+
+        GST_LOG_OBJECT (flxdec, "have replicate run of size %d at offset %d",
+            count, skip);
+
         if (skip + count > flxdec->hdr.width) {
           GST_ERROR_OBJECT (flxdec, "Invalid FLI packet detected. "
               "line too long.");
@@ -428,46 +502,59 @@ flx_decode_delta_fli (GstFlxDec * flxdec
         }
 
         /* replicate run */
-        while (count--)
-          *dest++ = *data++;
+        if (!gst_byte_reader_get_data (reader, count, &data))
+          goto error;
+        if (!gst_byte_writer_put_data (writer, data, count))
+          goto error;
       }
     }
-    start_p += flxdec->hdr.width;
-    dest = start_p;
+    line_start_i += flxdec->hdr.width;
+    if (!gst_byte_writer_set_pos (writer, line_start_i))
+      goto error;
   }
-
   return TRUE;
+
+error:
+  GST_ERROR_OBJECT (flxdec, "Failed to decode FLI packet");
+  return FALSE;
 }
 
 static gboolean
-flx_decode_delta_flc (GstFlxDec * flxdec, guchar * data, guchar * dest)
+flx_decode_delta_flc (GstFlxDec * flxdec, GstByteReader * reader,
+    GstByteWriter * writer)
 {
-  gulong count, lines, start_l, opcode;
-  guchar *start_p;
+  guint16 lines, start_l;
 
   g_return_val_if_fail (flxdec != NULL, FALSE);
   g_return_val_if_fail (flxdec->delta != NULL, FALSE);
 
   /* use last frame for delta */
-  memcpy (dest, GST_BUFFER_DATA (flxdec->delta),
-      GST_BUFFER_SIZE (flxdec->delta));
+  if (!gst_byte_writer_put_data (writer, GST_BUFFER_DATA (flxdec->delta), GST_BUFFER_SIZE (flxdec->delta)))
+    goto error;
+  if (!gst_byte_reader_get_uint16_le (reader, &lines))
+    goto error;
 
-  lines = (data[0] + (data[1] << 8));
   if (lines > flxdec->hdr.height) {
     GST_ERROR_OBJECT (flxdec, "Invalid FLC packet detected. too many lines.");
     return FALSE;
   }
-  data += 2;
 
-  start_p = dest;
   start_l = lines;
 
   while (lines) {
-    dest = start_p + (flxdec->hdr.width * (start_l - lines));
+    guint16 opcode;
+
+    if (!gst_byte_writer_set_pos (writer,
+            flxdec->hdr.width * (start_l - lines)))
+      goto error;
 
     /* process opcode(s) */
-    while ((opcode = (data[0] + (data[1] << 8))) & 0xc000) {
-      data += 2;
+    while (TRUE) {
+      if (!gst_byte_reader_get_uint16_le (reader, &opcode))
+        goto error;
+      if ((opcode & 0xc000) == 0)
+        break;
+
       if ((opcode & 0xc000) == 0xc000) {
         /* line skip count */
         gulong skip = (0x10000 - opcode);
@@ -477,27 +564,44 @@ flx_decode_delta_flc (GstFlxDec * flxdec
           return FALSE;
         }
         start_l += skip;
-        dest += flxdec->hdr.width * skip;
+        if (!gst_byte_writer_set_pos (writer,
+                gst_byte_writer_get_pos (writer) + flxdec->hdr.width * skip))
+          goto error;
       } else {
         /* last pixel */
-        dest += flxdec->hdr.width;
-        *dest++ = (opcode & 0xff);
+        if (!gst_byte_writer_set_pos (writer,
+                gst_byte_writer_get_pos (writer) + flxdec->hdr.width))
+          goto error;
+        if (!gst_byte_writer_put_uint8 (writer, opcode & 0xff))
+          goto error;
       }
     }
-    data += 2;
 
     /* last opcode is the packet count */
+    GST_LOG_OBJECT (flxdec, "have %d packets", opcode);
     while (opcode--) {
       /* skip count */
-      guchar skip = *data++;
-      dest += skip;
+      guint8 skip;
+      gint8 count;
+
+      if (!gst_byte_reader_get_uint8 (reader, &skip))
+        goto error;
+      if (!gst_byte_writer_set_pos (writer,
+              gst_byte_writer_get_pos (writer) + skip))
+        goto error;
 
       /* RLE count */
-      count = *data++;
+      if (!gst_byte_reader_get_int8 (reader, &count))
+        goto error;
+
+      if (count < 0) {
+        guint16 x;
 
-      if (count > 0x7f) {
         /* replicate word run */
-        count = 0x100 - count;
+        count = ABS (count);
+
+        GST_LOG_OBJECT (flxdec, "have replicate run of size %d at offset %d",
+            count, skip);
 
         if (skip + count > flxdec->hdr.width) {
           GST_ERROR_OBJECT (flxdec, "Invalid FLC packet detected. "
@@ -505,22 +609,31 @@ flx_decode_delta_flc (GstFlxDec * flxdec
           return FALSE;
         }
 
+        if (!gst_byte_reader_get_uint16_le (reader, &x))
+          goto error;
+
         while (count--) {
-          *dest++ = data[0];
-          *dest++ = data[1];
+          if (!gst_byte_writer_put_uint16_le (writer, x)) {
+            goto error;
+          }
         }
-        data += 2;
       } else {
+        GST_LOG_OBJECT (flxdec, "have literal run of size %d at offset %d",
+            count, skip);
+
         if (skip + count > flxdec->hdr.width) {
           GST_ERROR_OBJECT (flxdec, "Invalid FLC packet detected. "
               "line too long.");
           return FALSE;
         }
 
-        /* literal word run */
         while (count--) {
-          *dest++ = *data++;
-          *dest++ = *data++;
+          guint16 x;
+
+          if (!gst_byte_reader_get_uint16_le (reader, &x))
+            goto error;
+          if (!gst_byte_writer_put_uint16_le (writer, x))
+            goto error;
         }
       }
     }
@@ -528,13 +641,90 @@ flx_decode_delta_flc (GstFlxDec * flxdec
   }
 
   return TRUE;
+
+error:
+  GST_ERROR_OBJECT (flxdec, "Failed to decode FLI packet");
+  return FALSE;
+}
+
+static gboolean
+_read_flx_header (GstFlxDec * flxdec, GstByteReader * reader, FlxHeader * flxh)
+{
+  memset (flxh, 0, sizeof (*flxh));
+
+  if (!gst_byte_reader_get_uint32_le (reader, &flxh->size))
+    goto error;
+  if (flxh->size < FlxHeaderSize) {
+    GST_ERROR_OBJECT (flxdec, "Invalid file size in the header");
+    return FALSE;
+  }
+
+  if (!gst_byte_reader_get_uint16_le (reader, &flxh->type))
+    goto error;
+  if (!gst_byte_reader_get_uint16_le (reader, &flxh->frames))
+    goto error;
+  if (!gst_byte_reader_get_uint16_le (reader, &flxh->width))
+    goto error;
+  if (!gst_byte_reader_get_uint16_le (reader, &flxh->height))
+    goto error;
+  if (!gst_byte_reader_get_uint16_le (reader, &flxh->depth))
+    goto error;
+  if (!gst_byte_reader_get_uint16_le (reader, &flxh->flags))
+    goto error;
+  if (!gst_byte_reader_get_uint32_le (reader, &flxh->speed))
+    goto error;
+  if (!gst_byte_reader_skip (reader, 2))        /* reserved */
+    goto error;
+  /* FLC */
+  if (!gst_byte_reader_get_uint32_le (reader, &flxh->created))
+    goto error;
+  if (!gst_byte_reader_get_uint32_le (reader, &flxh->creator))
+    goto error;
+  if (!gst_byte_reader_get_uint32_le (reader, &flxh->updated))
+    goto error;
+  if (!gst_byte_reader_get_uint32_le (reader, &flxh->updater))
+    goto error;
+  if (!gst_byte_reader_get_uint16_le (reader, &flxh->aspect_dx))
+    goto error;
+  if (!gst_byte_reader_get_uint16_le (reader, &flxh->aspect_dy))
+    goto error;
+  /* EGI */
+  if (!gst_byte_reader_get_uint16_le (reader, &flxh->ext_flags))
+    goto error;
+  if (!gst_byte_reader_get_uint16_le (reader, &flxh->keyframes))
+    goto error;
+  if (!gst_byte_reader_get_uint16_le (reader, &flxh->totalframes))
+    goto error;
+  if (!gst_byte_reader_get_uint32_le (reader, &flxh->req_memory))
+    goto error;
+  if (!gst_byte_reader_get_uint16_le (reader, &flxh->max_regions))
+    goto error;
+  if (!gst_byte_reader_get_uint16_le (reader, &flxh->transp_num))
+    goto error;
+  if (!gst_byte_reader_skip (reader, 24))       /* reserved */
+    goto error;
+  /* FLC */
+  if (!gst_byte_reader_get_uint32_le (reader, &flxh->oframe1))
+    goto error;
+  if (!gst_byte_reader_get_uint32_le (reader, &flxh->oframe2))
+    goto error;
+  if (!gst_byte_reader_skip (reader, 40))       /* reserved */
+    goto error;
+
+  return TRUE;
+
+error:
+  GST_ERROR_OBJECT (flxdec, "Error reading file header");
+  return FALSE;
 }
 
 static GstFlowReturn
 gst_flxdec_chain (GstPad * pad, GstBuffer * buf)
 {
+  GstByteReader reader;
+  const guint8 *data;
   GstCaps *caps;
-  guint avail;
+  guint available;
   GstFlowReturn res = GST_FLOW_OK;
 
   GstFlxDec *flxdec;
@@ -545,29 +735,51 @@ gst_flxdec_chain (GstPad * pad, GstBuffe
   g_return_val_if_fail (flxdec != NULL, GST_FLOW_ERROR);
 
   gst_adapter_push (flxdec->adapter, buf);
-  avail = gst_adapter_available (flxdec->adapter);
+  available = gst_adapter_available (flxdec->adapter);
+  data = gst_adapter_peek (flxdec->adapter, available);
+  if (!data) {
+    GST_ELEMENT_ERROR (flxdec, STREAM, DECODE,
+        ("%s", "Failed to map buffer"), (NULL));
+    goto error;
+  }
+  gst_byte_reader_init (&reader, data, available);
 
   if (flxdec->state == GST_FLXDEC_READ_HEADER) {
-    if (avail >= FlxHeaderSize) {
-      const guint8 *data = gst_adapter_peek (flxdec->adapter, FlxHeaderSize);
+    if (available >= FlxHeaderSize) {
+      guint next_pos;
 
-      memcpy ((gchar *) & flxdec->hdr, data, FlxHeaderSize);
-      FLX_HDR_FIX_ENDIANNESS (&(flxdec->hdr));
-      gst_adapter_flush (flxdec->adapter, FlxHeaderSize);
+      next_pos = gst_byte_reader_get_pos (&reader) + FlxHeaderSize;
+      available -= FlxHeaderSize;
+
+      if (!_read_flx_header (flxdec, &reader, &flxdec->hdr)) {
+        GST_ELEMENT_ERROR (flxdec, STREAM, DECODE,
+            ("%s", "Failed to parse header"), (NULL));
+        goto unmap_input_error;
+      }
+ 
+      if (!gst_byte_reader_set_pos (&reader, next_pos)) {
+        GST_ELEMENT_ERROR (flxdec, STREAM, DECODE,
+            ("%s", "Could not read header"), (NULL));
+        goto unmap_input_error;
+      }
 
+      gst_adapter_flush (flxdec->adapter, FlxHeaderSize);
       flxh = &flxdec->hdr;
 
       /* check header */
       if (flxh->type != FLX_MAGICHDR_FLI &&
-          flxh->type != FLX_MAGICHDR_FLC && flxh->type != FLX_MAGICHDR_FLX)
-        goto wrong_type;
+          flxh->type != FLX_MAGICHDR_FLC && flxh->type != FLX_MAGICHDR_FLX) {
+        GST_ELEMENT_ERROR (flxdec, STREAM, WRONG_TYPE, (NULL),
+            ("not a flx file (type %x)", flxh->type));
+        goto unmap_input_error;
+      }
 
-      GST_LOG ("size      :  %d", flxh->size);
-      GST_LOG ("frames    :  %d", flxh->frames);
-      GST_LOG ("width     :  %d", flxh->width);
-      GST_LOG ("height    :  %d", flxh->height);
-      GST_LOG ("depth     :  %d", flxh->depth);
-      GST_LOG ("speed     :  %d", flxh->speed);
+      GST_INFO_OBJECT (flxdec, "size      :  %d", flxh->size);
+      GST_INFO_OBJECT (flxdec, "frames    :  %d", flxh->frames);
+      GST_INFO_OBJECT (flxdec, "width     :  %d", flxh->width);
+      GST_INFO_OBJECT (flxdec, "height    :  %d", flxh->height);
+      GST_INFO_OBJECT (flxdec, "depth     :  %d", flxh->depth);
+      GST_INFO_OBJECT (flxdec, "speed     :  %d", flxh->speed);
 
       flxdec->next_time = 0;
 
@@ -593,18 +805,32 @@ gst_flxdec_chain (GstPad * pad, GstBuffe
       gst_pad_set_caps (flxdec->srcpad, caps);
       gst_caps_unref (caps);
 
-      if (flxh->depth <= 8)
-        flxdec->converter =
-            flx_colorspace_converter_new (flxh->width, flxh->height);
+      /* zero means 8 */
+      if (flxh->depth == 0)
+        flxh->depth = 8;
+
+      if (flxh->depth != 8) {
+        GST_ELEMENT_ERROR (flxdec, STREAM, WRONG_TYPE,
+            ("%s", "Don't know how to decode non 8 bit depth streams"), (NULL));
+        goto unmap_input_error;
+      }
+
+      flxdec->converter =
+          flx_colorspace_converter_new (flxh->width, flxh->height);
 
       if (flxh->type == FLX_MAGICHDR_FLC || flxh->type == FLX_MAGICHDR_FLX) {
-        GST_LOG ("(FLC) aspect_dx :  %d", flxh->aspect_dx);
-        GST_LOG ("(FLC) aspect_dy :  %d", flxh->aspect_dy);
-        GST_LOG ("(FLC) oframe1   :  0x%08x", flxh->oframe1);
-        GST_LOG ("(FLC) oframe2   :  0x%08x", flxh->oframe2);
+        GST_INFO_OBJECT (flxdec, "(FLC) aspect_dx :  %d", flxh->aspect_dx);
+        GST_INFO_OBJECT (flxdec, "(FLC) aspect_dy :  %d", flxh->aspect_dy);
+        GST_INFO_OBJECT (flxdec, "(FLC) oframe1   :  0x%08x", flxh->oframe1);
+        GST_INFO_OBJECT (flxdec, "(FLC) oframe2   :  0x%08x", flxh->oframe2);
       }
 
       flxdec->size = (flxh->width * flxh->height);
+      if (flxdec->size >= G_MAXSIZE / 4) {
+        GST_ELEMENT_ERROR (flxdec, STREAM, DECODE,
+            ("%s", "Cannot allocate required memory"), (NULL));
+        goto unmap_input_error;
+      }
 
       /* create delta and output frame */
       flxdec->frame = gst_buffer_new ();
@@ -622,51 +848,72 @@ gst_flxdec_chain (GstPad * pad, GstBuffe
     GstBuffer *out;
 
     /* while we have enough data in the adapter */
-    while (avail >= FlxFrameChunkSize) {
-      FlxFrameChunk flxfh;
-      guchar *chunk;
-      const guint8 *data;
-
-      chunk = NULL;
-      data = gst_adapter_peek (flxdec->adapter, FlxFrameChunkSize);
-      memcpy (&flxfh, data, FlxFrameChunkSize);
-      FLX_FRAME_CHUNK_FIX_ENDIANNESS (&flxfh);
-
-      switch (flxfh.id) {
-        case FLX_FRAME_TYPE:
-          /* check if we have the complete frame */
-          if (avail < flxfh.size)
-            goto need_more_data;
-
-          /* flush header */
-          gst_adapter_flush (flxdec->adapter, FlxFrameChunkSize);
-
-          chunk = gst_adapter_take (flxdec->adapter,
-              flxfh.size - FlxFrameChunkSize);
-          FLX_FRAME_TYPE_FIX_ENDIANNESS ((FlxFrameType *) chunk);
-          if (((FlxFrameType *) chunk)->chunks == 0)
-            break;
+    while (available >= FlxFrameChunkSize && res == GST_FLOW_OK) {
+      guint32 size;
+      guint16 type;
+
+      data = gst_adapter_peek (flxdec->adapter, available);
+      if (!data) {
+        GST_ELEMENT_ERROR (flxdec, STREAM, DECODE,
+            ("%s", "Failed to map buffer"), (NULL));
+        goto error;
+      }
+      gst_byte_reader_init (&reader, data, available);
+      if (!gst_byte_reader_get_uint32_le (&reader, &size))
+        goto parse_error;
+      if (available < size)
+        goto need_more_data;
+
+      available -= size;
+      gst_adapter_flush (flxdec->adapter, size);
+
+      if (!gst_byte_reader_get_uint16_le (&reader, &type))
+        goto parse_error;
+
+      switch (type) {
+        case FLX_FRAME_TYPE:{
+          guint next_pos;
+          GstByteWriter writer;
+          guint16 n_chunks;
+          //GstMapInfo map;
+
+          GST_LOG_OBJECT (flxdec, "Have frame type 0x%02x of size %d", type,
+              size);
+
+          next_pos = gst_byte_reader_get_pos (&reader) + size - FlxFrameChunkSize;
+
+          if (!gst_byte_reader_get_uint16_le (&reader, &n_chunks))
+            goto parse_error;
+          GST_LOG_OBJECT (flxdec, "Have %d chunks", n_chunks);
 
-          /* create 32 bits output frame */
-          res = gst_pad_alloc_buffer_and_set_caps (flxdec->srcpad,
-              GST_BUFFER_OFFSET_NONE,
-              flxdec->size * 4, GST_PAD_CAPS (flxdec->srcpad), &out);
-          if (res != GST_FLOW_OK)
+          if (n_chunks == 0) {
+            gst_byte_reader_set_pos (&reader, next_pos);
             break;
+          }
+          if (!gst_byte_reader_skip (&reader, 8))       /* reserved */
+            goto parse_error;
+ 
+          gst_byte_writer_init_with_data (&writer, GST_BUFFER_DATA (flxdec->frame),
+              flxdec->size, TRUE);
 
           /* decode chunks */
-          if (!flx_decode_chunks (flxdec,
-                  ((FlxFrameType *) chunk)->chunks,
-                  chunk + FlxFrameTypeSize, GST_BUFFER_DATA (flxdec->frame)) {
+          if (!flx_decode_chunks (flxdec, n_chunks, &reader, &writer)) {
             GST_ELEMENT_ERROR (flxdec, STREAM, DECODE,
                 ("%s", "Could not decode chunk"), NULL);
-            return GST_FLOW_ERROR;
+            goto unmap_input_error;
           }
+          gst_byte_writer_reset (&writer);
 
           /* save copy of the current frame for possible delta. */
           memcpy (GST_BUFFER_DATA (flxdec->delta),
               GST_BUFFER_DATA (flxdec->frame), GST_BUFFER_SIZE (flxdec->delta));
 
+          res = gst_pad_alloc_buffer_and_set_caps (flxdec->srcpad,
+              GST_BUFFER_OFFSET_NONE,
+              flxdec->size * 4, GST_PAD_CAPS (flxdec->srcpad), &out);
+          if (res != GST_FLOW_OK)
+            break;
+
           /* convert current frame. */
           flx_colorspace_convert (flxdec->converter,
               GST_BUFFER_DATA (flxdec->frame), GST_BUFFER_DATA (out));
@@ -674,27 +921,25 @@ gst_flxdec_chain (GstPad * pad, GstBuffe
           GST_BUFFER_TIMESTAMP (out) = flxdec->next_time;
           flxdec->next_time += flxdec->frame_time;
 
-          gst_pad_push (flxdec->srcpad, out);
+          res = gst_pad_push (flxdec->srcpad, out);
+          gst_byte_reader_set_pos (&reader, next_pos);
           break;
+        }
       }
-
-      if (chunk)
-        g_free (chunk);
-
-      avail = gst_adapter_available (flxdec->adapter);
     }
   }
+
 need_more_data:
   gst_object_unref (flxdec);
   return res;
 
   /* ERRORS */
-wrong_type:
-  {
-    GST_ELEMENT_ERROR (flxdec, STREAM, WRONG_TYPE, (NULL),
-        ("not a flx file (type %x)", flxh->type));
-    return GST_FLOW_ERROR;
-  }
+parse_error:
+  GST_ELEMENT_ERROR (flxdec, STREAM, DECODE,
+      ("%s", "Failed to parse stream"), (NULL));
+unmap_input_error:
+error:
+  return GST_FLOW_ERROR;
 }
 
 static GstStateChangeReturn
diff -urp gst-plugins-good-0.10.31.orig/gst/flx/gstflxdec.h gst-plugins-good-0.10.31/gst/flx/gstflxdec.h
--- gst-plugins-good-0.10.31.orig/gst/flx/gstflxdec.h	2011-12-11 12:48:11.000000000 -0600
+++ gst-plugins-good-0.10.31/gst/flx/gstflxdec.h	2016-12-20 11:12:02.147915398 -0600
@@ -23,6 +23,8 @@
 #include <gst/gst.h>
 
 #include <gst/base/gstadapter.h>
+#include <gst/base/gstbytereader.h>
+#include <gst/base/gstbytewriter.h>
 #include "flx_color.h"
 
 G_BEGIN_DECLS
@@ -45,7 +47,7 @@ struct _GstFlxDec {
 
   GstBuffer *delta, *frame;
   GstAdapter *adapter;
-  gulong size;
+  gsize size;
   GstFlxDecState state;
   gint64 frame_time;
   gint64 next_time;