shithub: sox

Download patch

ref: 37e998b098e802cdf94ad31d97f3a0038d2d1900
parent: e81229cddb9147b812f1f9e939f7cda25d950546
author: Mans Rullgard <mans@mansr.com>
date: Fri Apr 27 18:27:01 EDT 2018

voc: abort if channel count or sample format changes [bug #265]

A corrupted file can have blocks with differing values for channel
count or sample format.  Detect this and abort.

--- a/src/voc.c
+++ b/src/voc.c
@@ -168,9 +168,9 @@
   long srate;                   /* rate code (byte) of silence */
   size_t blockseek;         /* start of current output block */
   long samples;                 /* number of samples output */
-  uint16_t format;              /* VOC audio format */
+  int format;                   /* VOC audio format */
   int size;                     /* word length of data */
-  unsigned char channels;       /* number of sound channels */
+  int channels;                 /* number of sound channels */
   long total_size;              /* total size of all audio in file */
   int extended;                 /* Has an extended block been read? */
   adpcm_t adpcm;
@@ -238,6 +238,8 @@
     lsx_readb(ft, &uc);
 
   v->rate = -1;
+  v->format = -1;
+  v->channels = -1;
   v->block_remaining = 0;
   v->total_size = 0;    /* ANN added */
   v->extended = 0;
@@ -552,6 +554,7 @@
 {
   priv_t * v = (priv_t *) ft->priv;
   unsigned char uc, block;
+  uint16_t u16;
   sox_uint24_t sblen;
   uint16_t new_rate_16;
   uint32_t new_rate_32;
@@ -593,9 +596,17 @@
           }
           v->rate = uc;
           ft->signal.rate = 1000000.0 / (256 - v->rate);
+          if (v->channels != -1 && v->channels != 1) {
+            lsx_fail_errno(ft, SOX_EFMT, "channel count changed");
+            return SOX_EOF;
+          }
           v->channels = 1;
         }
         lsx_readb(ft, &uc);
+        if (v->format != -1 && uc != v->format) {
+          lsx_fail_errno(ft, SOX_EFMT, "format changed");
+          return SOX_EOF;
+        }
         v->format = uc;
         v->extended = 0;
         v->block_remaining = sblen - 2;
@@ -615,8 +626,18 @@
         ft->signal.rate = new_rate_32;
         lsx_readb(ft, &uc);
         v->size = uc;
-        lsx_readb(ft, &(v->channels));
-        lsx_readw(ft, &(v->format));    /* ANN: added format */
+        lsx_readb(ft, &uc);
+        if (v->channels != -1 && uc != v->channels) {
+          lsx_fail_errno(ft, SOX_EFMT, "channel count changed");
+          return SOX_EOF;
+        }
+        v->channels = uc;
+        lsx_readw(ft, &u16);    /* ANN: added format */
+        if (v->format != -1 && u16 != v->format) {
+          lsx_fail_errno(ft, SOX_EFMT, "format changed");
+          return SOX_EOF;
+        }
+        v->format = u16;
         lsx_skipbytes(ft, (size_t) 4);
         v->block_remaining = sblen - 12;
         return (SOX_SUCCESS);
@@ -698,6 +719,11 @@
         v->rate = new_rate_16;
         lsx_readb(ft, &uc); /* bits_per_sample */
         lsx_readb(ft, &uc);
+        if (v->channels != -1 && uc != v->channels) {
+          lsx_fail_errno(ft, SOX_EFMT, "channel count changed");
+          return SOX_EOF;
+        }
+        v->channels = uc;
         ft->signal.channels = uc? 2 : 1;      /* Stereo */
         /* Needed number of channels before finishing
          * compute for rate */