libFLAC: Fix an out-of-bounds heap read

When doing a flac to flac conversion, bad data read from the input file
was making it all the way through the encoder to cause a read past the
end of the buffer in the CRC calculation.

Fix had two parts:

* bitwriter.c: Make a debug only assert (assert bits < 32) into a proper
  failure.
* stream_encoder.c: Catch the error condition of wasted bits being greater
  that bits_pers_sample and limit it to the bits_per_sample value.

Found using the American Fuzzy Lop fuzzer.
This commit is contained in:
Erik de Castro Lopo
2015-09-26 08:17:13 +10:00
parent 5fab59f8bc
commit d91eb4ae75
2 changed files with 13 additions and 5 deletions

View File

@@ -309,10 +309,12 @@ inline FLAC__bool FLAC__bitwriter_write_raw_uint32(FLAC__BitWriter *bw, FLAC__ui
/* WATCHOUT: code does not work with <32bit words; we can make things much faster with this assertion */
FLAC__ASSERT(FLAC__BITS_PER_WORD >= 32);
FLAC__ASSERT(0 != bw);
FLAC__ASSERT(0 != bw->buffer);
if(bw == 0 || bw->buffer == 0)
return false;
if (bits > 32)
return false;
FLAC__ASSERT(bits <= 32);
if(bits == 0)
return true;

View File

@@ -3178,7 +3178,10 @@ FLAC__bool process_subframes_(FLAC__StreamEncoder *encoder, FLAC__bool is_fracti
*/
if(do_independent) {
for(channel = 0; channel < encoder->protected_->channels; channel++) {
const unsigned w = get_wasted_bits_(encoder->private_->integer_signal[channel], encoder->protected_->blocksize);
unsigned w = get_wasted_bits_(encoder->private_->integer_signal[channel], encoder->protected_->blocksize);
if (w > encoder->protected_->bits_per_sample) {
w = encoder->protected_->bits_per_sample;
}
encoder->private_->subframe_workspace[channel][0].wasted_bits = encoder->private_->subframe_workspace[channel][1].wasted_bits = w;
encoder->private_->subframe_bps[channel] = encoder->protected_->bits_per_sample - w;
}
@@ -3186,7 +3189,10 @@ FLAC__bool process_subframes_(FLAC__StreamEncoder *encoder, FLAC__bool is_fracti
if(do_mid_side) {
FLAC__ASSERT(encoder->protected_->channels == 2);
for(channel = 0; channel < 2; channel++) {
const unsigned w = get_wasted_bits_(encoder->private_->integer_signal_mid_side[channel], encoder->protected_->blocksize);
unsigned w = get_wasted_bits_(encoder->private_->integer_signal_mid_side[channel], encoder->protected_->blocksize);
if (w > encoder->protected_->bits_per_sample) {
w = encoder->protected_->bits_per_sample;
}
encoder->private_->subframe_workspace_mid_side[channel][0].wasted_bits = encoder->private_->subframe_workspace_mid_side[channel][1].wasted_bits = w;
encoder->private_->subframe_bps_mid_side[channel] = encoder->protected_->bits_per_sample - w + (channel==0? 0:1);
}