mp3dec: Fix possible endless loop.
authorAndre Noll <maan@systemlinux.org>
Wed, 17 Aug 2011 17:08:17 +0000 (19:08 +0200)
committerAndre Noll <maan@systemlinux.org>
Thu, 18 Aug 2011 20:14:47 +0000 (22:14 +0200)
If the header of the last frame of a (corrupt) mp3 file can be decoded
but the rest of the frame can not, the mp3 decoder may end up in a
busy loop.

Fix this by performing the same check as for errors during header
decode. This adds some code duplication but as we are late in the
release cycle, let's go for the minimal fix for now.

error.h
mp3dec_filter.c

diff --git a/error.h b/error.h
index a56faf5..306546d 100644 (file)
--- a/error.h
+++ b/error.h
@@ -318,6 +318,7 @@ extern const char **para_errlist[];
        PARA_ERROR(MAD_FRAME_DECODE, "mad frame decode error"), \
        PARA_ERROR(MP3DEC_SYNTAX, "syntax error in mp3dec config"), \
        PARA_ERROR(MP3DEC_EOF, "mp3dec: end of file"), \
+       PARA_ERROR(MP3DEC_CORRUPT, "too many corrupt frames"), \
 
 
 #define FILTER_ERRORS \
index 6982f26..3ad9025 100644 (file)
@@ -74,6 +74,8 @@ static void mp3dec_close(struct filter_node *fn)
        fn->private_data = NULL;
 }
 
+#define MP3DEC_MAX_FRAME 8192
+
 static void mp3dec_post_select(__a_unused struct sched *s, struct task *t)
 {
        struct filter_node *fn = container_of(t, struct filter_node, task);
@@ -99,7 +101,7 @@ next_buffer:
         * other buffer tree nodes a chance to run. This is necessary to avoid
         * buffer underruns on slow machines.
         */
-       len = PARA_MIN(len, (size_t)8192);
+       len = PARA_MIN(len, (size_t)MP3DEC_MAX_FRAME);
        mad_stream_buffer(&pmd->stream, (unsigned char *)inbuffer, len);
 next_frame:
        ret = mad_header_decode(&pmd->frame.header, &pmd->stream);
@@ -112,12 +114,14 @@ next_frame:
                                goto err;
                        }
                        fn->min_iqs += 100;
+                       ret = -E_MP3DEC_CORRUPT;
+                       if (fn->min_iqs > MP3DEC_MAX_FRAME)
+                               goto err;
                }
                if (loaded == 0)
                        goto next_buffer;
                return;
        }
-       fn->min_iqs = 0;
        pmd->sample_rate = pmd->frame.header.samplerate;
        pmd->channels = MAD_NCHANNELS(&pmd->frame.header);
 decode:
@@ -126,15 +130,24 @@ decode:
                ret = handle_decode_error(pmd);
                if (ret < 0)
                        goto err;
-               mad_stream_sync(&pmd->stream);
-               if (pmd->stream.error == MAD_ERROR_BUFLEN)
+               ret = mad_stream_sync(&pmd->stream);
+               if (pmd->stream.error == MAD_ERROR_BUFLEN) {
+                       ret = -E_MP3DEC_EOF;
+                       if (len == iqs && btr_no_parent(btrn))
+                               goto err;
+                       fn->min_iqs += 100;
+                       ret = -E_MP3DEC_CORRUPT;
+                       if (fn->min_iqs > MP3DEC_MAX_FRAME)
+                               goto err;
                        return;
+               }
                if (pmd->stream.error != MAD_ERROR_BADDATAPTR)
                        goto decode;
                used = used_mad_buffer_bytes(&pmd->stream, len);
                btr_consume(btrn, used);
                return;
        }
+       fn->min_iqs = 0;
        mad_synth_frame(&pmd->synth, &pmd->frame);
        outbuffer = para_malloc(pmd->synth.pcm.length * 2 * pmd->channels);
        loaded = 0;