stream_decoder: check state==ABORTED after process_single() for seek
authorMax Kellermann <max@duempel.org>
Wed, 6 Jul 2016 14:28:53 +0000 (16:28 +0200)
committerErik de Castro Lopo <erikd@mega-nerd.com>
Sat, 9 Jul 2016 22:19:26 +0000 (08:19 +1000)
FLAC__stream_decoder_process_single() ignores frame_sync_() errors,
which means the caller cannot rely solely on the boolean return value,
it is also required to check the new "state".

After FLAC__stream_decoder_process_until_end_of_metadata(),
state==SEARCH_FOR_FRAME_SYNC and
last_frame.header.number_type==FRAME_NUMBER.  When an application
seeks at this time, but an I/O error occurs, then
FLAC__stream_decoder_process_single() returns true, but no frame has
been read yet, i.e. last_frame.header.number_type is still
FRAME_NUMBER.  This triggers the assertion in
seek_to_absolute_sample_():

 FLAC__ASSERT(decoder->private_->last_frame.header.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER);

So what needs to be done is check for state==ABORTED after the
FLAC__stream_decoder_process_single() call.

This bug can be triggered remotely with the Music Player Daemon
(https://www.musicpd.org/), and crashes the process.

Signed-off-by: Erik de Castro Lopo <erikd@mega-nerd.com>
Closes: https://github.com/xiph/flac/pull/12

src/libFLAC/stream_decoder.c

index c626d7a..fa0ef2c 100644 (file)
@@ -3134,7 +3134,8 @@ FLAC__bool seek_to_absolute_sample_(FLAC__StreamDecoder *decoder, FLAC__uint64 s
                 * FLAC__stream_decoder_process_single() to return false.
                 */
                decoder->private_->unparseable_frame_count = 0;
-               if(!FLAC__stream_decoder_process_single(decoder)) {
+               if(!FLAC__stream_decoder_process_single(decoder) ||
+                  decoder->protected_->state == FLAC__STREAM_DECODER_ABORTED) {
                        decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR;
                        return false;
                }
@@ -3261,7 +3262,8 @@ FLAC__bool seek_to_absolute_sample_ogg_(FLAC__StreamDecoder *decoder, FLAC__uint
                        did_a_seek = false;
 
                decoder->private_->got_a_frame = false;
-               if(!FLAC__stream_decoder_process_single(decoder)) {
+               if(!FLAC__stream_decoder_process_single(decoder) ||
+                  decoder->protected_->state == FLAC__STREAM_DECODER_ABORTED) {
                        decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR;
                        return false;
                }