Commit message: None
CVE: CVE-2016-2429
CWE: CWE-119
Vulnerability description: libFLAC/stream_decoder.c in mediaserver in Android 4.x before 4.4.4, 5.0.x before 5.0.2, 5.1.x before 5.1.1, and 6.x before 2016-05-01 does not prevent free operations on uninitialized memory, which allows remote attackers to execute arbitrary code or cause a denial of service (heap memory corruption) via a crafted media file, aka internal bug 27211885.

Project: Android
File: stream_decoder.c

FLAC_API FLAC__bool FLAC__stream_decoder_flush(FLAC__StreamDecoder *decoder)
{
	FLAC__ASSERT(0 != decoder);
	FLAC__ASSERT(0 != decoder->private_);
	FLAC__ASSERT(0 != decoder->protected_);

	decoder->private_->samples_decoded = 0;
	decoder->private_->do_md5_checking = false;

#if FLAC__HAS_OGG
 if(decoder->private_->is_ogg)
		FLAC__ogg_decoder_aspect_flush(&decoder->protected_->ogg_decoder_aspect);
#endif

 if(!FLAC__bitreader_clear(decoder->private_->input)) {
		decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
 return false;
 }
	decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;

 return true;
}

Project: Android
File: stream_decoder.c

FLAC_API FLAC__ChannelAssignment FLAC__stream_decoder_get_channel_assignment(const FLAC__StreamDecoder *decoder)
{
	FLAC__ASSERT(0 != decoder);
	FLAC__ASSERT(0 != decoder->protected_);
 return decoder->protected_->channel_assignment;
}

Project: Android
File: stream_decoder.c

unsigned FLAC__stream_decoder_get_input_bytes_unconsumed(const FLAC__StreamDecoder *decoder)
{
	FLAC__ASSERT(0 != decoder);
	FLAC__ASSERT(FLAC__bitreader_is_consumed_byte_aligned(decoder->private_->input));
	FLAC__ASSERT(!(FLAC__bitreader_get_input_bits_unconsumed(decoder->private_->input) & 7));
 return FLAC__bitreader_get_input_bits_unconsumed(decoder->private_->input) / 8;
}

Project: Android
File: stream_decoder.c

FLAC_API FLAC__StreamDecoderState FLAC__stream_decoder_get_state(const FLAC__StreamDecoder *decoder)
{
	FLAC__ASSERT(0 != decoder);
	FLAC__ASSERT(0 != decoder->protected_);
 return decoder->protected_->state;
}

Project: Android
File: stream_decoder.c

FLAC_API FLAC__bool FLAC__stream_decoder_seek_absolute(FLAC__StreamDecoder *decoder, FLAC__uint64 sample)
{
	FLAC__uint64 length;

	FLAC__ASSERT(0 != decoder);

 if(
		decoder->protected_->state != FLAC__STREAM_DECODER_SEARCH_FOR_METADATA &&
		decoder->protected_->state != FLAC__STREAM_DECODER_READ_METADATA &&
		decoder->protected_->state != FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC &&
		decoder->protected_->state != FLAC__STREAM_DECODER_READ_FRAME &&
		decoder->protected_->state != FLAC__STREAM_DECODER_END_OF_STREAM
 )
 return false;

 if(0 == decoder->private_->seek_callback)
 return false;

	FLAC__ASSERT(decoder->private_->seek_callback);
	FLAC__ASSERT(decoder->private_->tell_callback);
	FLAC__ASSERT(decoder->private_->length_callback);
	FLAC__ASSERT(decoder->private_->eof_callback);

 if(FLAC__stream_decoder_get_total_samples(decoder) > 0 && sample >= FLAC__stream_decoder_get_total_samples(decoder))
 return false;

	decoder->private_->is_seeking = true;

 /* turn off md5 checking if a seek is attempted */
	decoder->private_->do_md5_checking = false;

 /* get the file length (currently our algorithm needs to know the length so it's also an error to get FLAC__STREAM_DECODER_LENGTH_STATUS_UNSUPPORTED) */
 if(decoder->private_->length_callback(decoder, &length, decoder->private_->client_data) != FLAC__STREAM_DECODER_LENGTH_STATUS_OK) {
		decoder->private_->is_seeking = false;
 return false;
 }

 /* if we haven't finished processing the metadata yet, do that so we have the STREAMINFO, SEEK_TABLE, and first_frame_offset */
 if(
		decoder->protected_->state == FLAC__STREAM_DECODER_SEARCH_FOR_METADATA ||
		decoder->protected_->state == FLAC__STREAM_DECODER_READ_METADATA
 ) {
 if(!FLAC__stream_decoder_process_until_end_of_metadata(decoder)) {
 /* above call sets the state for us */
			decoder->private_->is_seeking = false;
 return false;
 }
 /* check this again in case we didn't know total_samples the first time */
 if(FLAC__stream_decoder_get_total_samples(decoder) > 0 && sample >= FLAC__stream_decoder_get_total_samples(decoder)) {
			decoder->private_->is_seeking = false;
 return false;
 }
 }

 {
 const FLAC__bool ok =
#if FLAC__HAS_OGG
			decoder->private_->is_ogg?
			seek_to_absolute_sample_ogg_(decoder, length, sample) :
#endif
			seek_to_absolute_sample_(decoder, length, sample)
 ;
		decoder->private_->is_seeking = false;
 return ok;
 }
}

Project: Android
File: stream_decoder.c

FLAC_API FLAC__bool FLAC__stream_decoder_set_ogg_serial_number(FLAC__StreamDecoder *decoder, long value)
{
	FLAC__ASSERT(0 != decoder);
	FLAC__ASSERT(0 != decoder->private_);
	FLAC__ASSERT(0 != decoder->protected_);
 if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED)
 return false;
#if FLAC__HAS_OGG
 /* can't check decoder->private_->is_ogg since that's not set until init time */
	FLAC__ogg_decoder_aspect_set_serial_number(&decoder->protected_->ogg_decoder_aspect, value);
 return true;
#else
 (void)value;
 return false;
#endif
}

Project: Android
File: stream_decoder.c

FLAC_API FLAC__bool FLAC__stream_decoder_skip_single_frame(FLAC__StreamDecoder *decoder)
{
	FLAC__bool got_a_frame;
	FLAC__ASSERT(0 != decoder);
	FLAC__ASSERT(0 != decoder->protected_);

 while(1) {
 switch(decoder->protected_->state) {
 case FLAC__STREAM_DECODER_SEARCH_FOR_METADATA:
 case FLAC__STREAM_DECODER_READ_METADATA:
 return false; /* above function sets the status for us */
 case FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC:
 if(!frame_sync_(decoder))
 return true; /* above function sets the status for us */
 break;
 case FLAC__STREAM_DECODER_READ_FRAME:
 if(!read_frame_(decoder, &got_a_frame, /*do_full_decode=*/false))
 return false; /* above function sets the status for us */
 if(got_a_frame)
 return true; /* above function sets the status for us */
 break;
 case FLAC__STREAM_DECODER_END_OF_STREAM:
 case FLAC__STREAM_DECODER_ABORTED:
 return true;
 default:
				FLAC__ASSERT(0);
 return false;
 }
 }
}

Project: Android
File: stream_decoder.c

FLAC__bool file_eof_callback_(const FLAC__StreamDecoder *decoder, void *client_data)
{
 (void)client_data;

 return feof(decoder->private_->file)? true : false;
}

Project: Android
File: stream_decoder.c

FLAC__StreamDecoderLengthStatus file_length_callback_(const FLAC__StreamDecoder *decoder, FLAC__uint64 *stream_length, void *client_data)
{
 struct flac_stat_s filestats;
 (void)client_data;

 if(decoder->private_->file == stdin)
 return FLAC__STREAM_DECODER_LENGTH_STATUS_UNSUPPORTED;
 else if(flac_fstat(fileno(decoder->private_->file), &filestats) != 0)
 return FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR;
 else {
 *stream_length = (FLAC__uint64)filestats.st_size;
 return FLAC__STREAM_DECODER_LENGTH_STATUS_OK;
 }
}

Project: Android
File: stream_decoder.c

FLAC__bool has_id_filtered_(FLAC__StreamDecoder *decoder, FLAC__byte *id)
{
 size_t i;

	FLAC__ASSERT(0 != decoder);
	FLAC__ASSERT(0 != decoder->private_);

 for(i = 0; i < decoder->private_->metadata_filter_ids_count; i++)
 if(0 == memcmp(decoder->private_->metadata_filter_ids + i * (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8), id, (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8)))
 return true;

 return false;
}

Project: Android
File: stream_decoder.c

FLAC__bool seek_to_absolute_sample_(FLAC__StreamDecoder *decoder, FLAC__uint64 stream_length, FLAC__uint64 target_sample)
{
	FLAC__uint64 first_frame_offset = decoder->private_->first_frame_offset, lower_bound, upper_bound, lower_bound_sample, upper_bound_sample, this_frame_sample;
	FLAC__int64 pos = -1;
 int i;
 unsigned approx_bytes_per_frame;
	FLAC__bool first_seek = true;
 const FLAC__uint64 total_samples = FLAC__stream_decoder_get_total_samples(decoder);
 const unsigned min_blocksize = decoder->private_->stream_info.data.stream_info.min_blocksize;
 const unsigned max_blocksize = decoder->private_->stream_info.data.stream_info.max_blocksize;
 const unsigned max_framesize = decoder->private_->stream_info.data.stream_info.max_framesize;
 const unsigned min_framesize = decoder->private_->stream_info.data.stream_info.min_framesize;
 /* take these from the current frame in case they've changed mid-stream */
 unsigned channels = FLAC__stream_decoder_get_channels(decoder);
 unsigned bps = FLAC__stream_decoder_get_bits_per_sample(decoder);
 const FLAC__StreamMetadata_SeekTable *seek_table = decoder->private_->has_seek_table? &decoder->private_->seek_table.data.seek_table : 0;

 /* use values from stream info if we didn't decode a frame */
 if(channels == 0)
		channels = decoder->private_->stream_info.data.stream_info.channels;
 if(bps == 0)
		bps = decoder->private_->stream_info.data.stream_info.bits_per_sample;

 /* we are just guessing here */
 if(max_framesize > 0)
		approx_bytes_per_frame = (max_framesize + min_framesize) / 2 + 1;
 /*
	 * Check if it's a known fixed-blocksize stream.  Note that though
	 * the spec doesn't allow zeroes in the STREAMINFO block, we may
	 * never get a STREAMINFO block when decoding so the value of
	 * min_blocksize might be zero.
	 */
 else if(min_blocksize == max_blocksize && min_blocksize > 0) {
 /* note there are no () around 'bps/8' to keep precision up since it's an integer calulation */
		approx_bytes_per_frame = min_blocksize * channels * bps/8 + 64;
 }
 else
		approx_bytes_per_frame = 4096 * channels * bps/8 + 64;

 /*
	 * First, we set an upper and lower bound on where in the
	 * stream we will search.  For now we assume the worst case
	 * scenario, which is our best guess at the beginning of
	 * the first frame and end of the stream.
	 */
	lower_bound = first_frame_offset;
	lower_bound_sample = 0;
	upper_bound = stream_length;
	upper_bound_sample = total_samples > 0 ? total_samples : target_sample /*estimate it*/;

 /*
	 * Now we refine the bounds if we have a seektable with
	 * suitable points.  Note that according to the spec they
	 * must be ordered by ascending sample number.
	 *
	 * Note: to protect against invalid seek tables we will ignore points
	 * that have frame_samples==0 or sample_number>=total_samples
	 */
 if(seek_table) {
		FLAC__uint64 new_lower_bound = lower_bound;
		FLAC__uint64 new_upper_bound = upper_bound;
		FLAC__uint64 new_lower_bound_sample = lower_bound_sample;
		FLAC__uint64 new_upper_bound_sample = upper_bound_sample;

 /* find the closest seek point <= target_sample, if it exists */
 for(i = (int)seek_table->num_points - 1; i >= 0; i--) {
 if(
				seek_table->points[i].sample_number != FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER &&
				seek_table->points[i].frame_samples > 0 && /* defense against bad seekpoints */
 (total_samples <= 0 || seek_table->points[i].sample_number < total_samples) && /* defense against bad seekpoints */
				seek_table->points[i].sample_number <= target_sample
 )
 break;
 }
 if(i >= 0) { /* i.e. we found a suitable seek point... */
			new_lower_bound = first_frame_offset + seek_table->points[i].stream_offset;
			new_lower_bound_sample = seek_table->points[i].sample_number;
 }

 /* find the closest seek point > target_sample, if it exists */
 for(i = 0; i < (int)seek_table->num_points; i++) {
 if(
				seek_table->points[i].sample_number != FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER &&
				seek_table->points[i].frame_samples > 0 && /* defense against bad seekpoints */
 (total_samples <= 0 || seek_table->points[i].sample_number < total_samples) && /* defense against bad seekpoints */
				seek_table->points[i].sample_number > target_sample
 )
 break;
 }
 if(i < (int)seek_table->num_points) { /* i.e. we found a suitable seek point... */
			new_upper_bound = first_frame_offset + seek_table->points[i].stream_offset;
			new_upper_bound_sample = seek_table->points[i].sample_number;
 }
 /* final protection against unsorted seek tables; keep original values if bogus */
 if(new_upper_bound >= new_lower_bound) {
			lower_bound = new_lower_bound;
			upper_bound = new_upper_bound;
			lower_bound_sample = new_lower_bound_sample;
			upper_bound_sample = new_upper_bound_sample;
 }
 }

	FLAC__ASSERT(upper_bound_sample >= lower_bound_sample);
 /* there are 2 insidious ways that the following equality occurs, which
	 * we need to fix:
	 *  1) total_samples is 0 (unknown) and target_sample is 0
	 *  2) total_samples is 0 (unknown) and target_sample happens to be
	 *     exactly equal to the last seek point in the seek table; this
	 *     means there is no seek point above it, and upper_bound_samples
	 *     remains equal to the estimate (of target_samples) we made above
	 * in either case it does not hurt to move upper_bound_sample up by 1
	 */
 if(upper_bound_sample == lower_bound_sample)
		upper_bound_sample++;

	decoder->private_->target_sample = target_sample;
 while(1) {
 /* check if the bounds are still ok */
 if (lower_bound_sample >= upper_bound_sample || lower_bound > upper_bound) {
			decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR;
 return false;
 }
#ifndef FLAC__INTEGER_ONLY_LIBRARY
		pos = (FLAC__int64)lower_bound + (FLAC__int64)((FLAC__double)(target_sample - lower_bound_sample) / (FLAC__double)(upper_bound_sample - lower_bound_sample) * (FLAC__double)(upper_bound - lower_bound)) - approx_bytes_per_frame;
#else
 /* a little less accurate: */
 if(upper_bound - lower_bound < 0xffffffff)
			pos = (FLAC__int64)lower_bound + (FLAC__int64)(((target_sample - lower_bound_sample) * (upper_bound - lower_bound)) / (upper_bound_sample - lower_bound_sample)) - approx_bytes_per_frame;
 else /* @@@ WATCHOUT, ~2TB limit */
			pos = (FLAC__int64)lower_bound + (FLAC__int64)((((target_sample - lower_bound_sample)>>8) * ((upper_bound - lower_bound)>>8)) / ((upper_bound_sample - lower_bound_sample)>>16)) - approx_bytes_per_frame;
#endif
 if(pos >= (FLAC__int64)upper_bound)
			pos = (FLAC__int64)upper_bound - 1;
 if(pos < (FLAC__int64)lower_bound)
			pos = (FLAC__int64)lower_bound;
 if(decoder->private_->seek_callback(decoder, (FLAC__uint64)pos, decoder->private_->client_data) != FLAC__STREAM_DECODER_SEEK_STATUS_OK) {
			decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR;
 return false;
 }
 if(!FLAC__stream_decoder_flush(decoder)) {
 /* above call sets the state for us */
 return false;
 }
 /* Now we need to get a frame.  First we need to reset our
		 * unparseable_frame_count; if we get too many unparseable
		 * frames in a row, the read callback will return
		 * FLAC__STREAM_DECODER_READ_STATUS_ABORT, causing
		 * FLAC__stream_decoder_process_single() to return false.
		 */
		decoder->private_->unparseable_frame_count = 0;
 if(!FLAC__stream_decoder_process_single(decoder)) {
			decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR;
 return false;
 }
 /* our write callback will change the state when it gets to the target frame */
 /* actually, we could have got_a_frame if our decoder is at FLAC__STREAM_DECODER_END_OF_STREAM so we need to check for that also */
#if 0
 /*@@@@@@ used to be the following; not clear if the check for end of stream is needed anymore */
 if(decoder->protected_->state != FLAC__SEEKABLE_STREAM_DECODER_SEEKING && decoder->protected_->state != FLAC__STREAM_DECODER_END_OF_STREAM)
 break;
#endif
 if(!decoder->private_->is_seeking)
 break;

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

 if (0 == decoder->private_->samples_decoded || (this_frame_sample + decoder->private_->last_frame.header.blocksize >= upper_bound_sample && !first_seek)) {
 if (pos == (FLAC__int64)lower_bound) {
 /* can't move back any more than the first frame, something is fatally wrong */
				decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR;
 return false;
 }
 /* our last move backwards wasn't big enough, try again */
			approx_bytes_per_frame = approx_bytes_per_frame? approx_bytes_per_frame * 2 : 16;
 continue;
 }
 /* allow one seek over upper bound, so we can get a correct upper_bound_sample for streams with unknown total_samples */
		first_seek = false;

 /* make sure we are not seeking in corrupted stream */
 if (this_frame_sample < lower_bound_sample) {
			decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR;
 return false;
 }

 /* we need to narrow the search */
 if(target_sample < this_frame_sample) {
			upper_bound_sample = this_frame_sample + decoder->private_->last_frame.header.blocksize;
/*@@@@@@ what will decode position be if at end of stream? */
 if(!FLAC__stream_decoder_get_decode_position(decoder, &upper_bound)) {
				decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR;
 return false;
 }
			approx_bytes_per_frame = (unsigned)(2 * (upper_bound - pos) / 3 + 16);
 }
 else { /* target_sample >= this_frame_sample + this frame's blocksize */
			lower_bound_sample = this_frame_sample + decoder->private_->last_frame.header.blocksize;
 if(!FLAC__stream_decoder_get_decode_position(decoder, &lower_bound)) {
				decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR;
 return false;
 }
			approx_bytes_per_frame = (unsigned)(2 * (lower_bound - pos) / 3 + 16);
 }
 }

 return true;
}