Add checks that supplied samples are bounded within bits-per-sample

The encoder did not check whether samples provided through
FLAC__stream_encoder_process or FLAC__stream_encoder_process_interleaved
were bounded to fall within the set bits_per_sample (bps). This created
all kinds of trouble within the encoder, as there are numerous times
where the encoder chooses between different datapaths, data types and
encoding strategies based on the set bps.

https://sourceforge.net/p/flac/bugs/468/ also proved that invalid FLAC
files have been created with libFLAC in the past because of this

See https://github.com/xiph/flac/pull/273 for detailed description of
the commit

Credit: Oss-Fuzz
Issue: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=19758
Issue: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=31727
This commit is contained in:
Martijn van Beurden 2022-04-11 20:13:09 +02:00 committed by GitHub
parent 2610594d04
commit 4a8ec07e95
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 22 additions and 2 deletions

View File

@ -2174,8 +2174,10 @@ FLAC_API FLAC__uint64 FLAC__stream_encoder_get_total_samples_estimate(const FLAC
FLAC_API FLAC__bool FLAC__stream_encoder_process(FLAC__StreamEncoder *encoder, const FLAC__int32 * const buffer[], uint32_t samples)
{
uint32_t i, j = 0, channel;
uint32_t i, j = 0, k = 0, channel;
const uint32_t channels = encoder->protected_->channels, blocksize = encoder->protected_->blocksize;
const FLAC__int32 sample_max = INT32_MAX >> (32 - encoder->protected_->bits_per_sample);
const FLAC__int32 sample_min = INT32_MIN >> (32 - encoder->protected_->bits_per_sample);
FLAC__ASSERT(0 != encoder);
FLAC__ASSERT(0 != encoder->private_);
@ -2189,6 +2191,12 @@ FLAC_API FLAC__bool FLAC__stream_encoder_process(FLAC__StreamEncoder *encoder, c
append_to_verify_fifo_(&encoder->private_->verify.input_fifo, buffer, j, channels, n);
for(channel = 0; channel < channels; channel++) {
for(i = encoder->private_->current_sample_number, k = j; i <= blocksize && k < samples; i++, k++) {
if(buffer[channel][k] < sample_min || buffer[channel][k] > sample_max){
encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR;
return false;
}
}
if (buffer[channel] == NULL) {
return false;
}
@ -2233,6 +2241,8 @@ FLAC_API FLAC__bool FLAC__stream_encoder_process_interleaved(FLAC__StreamEncoder
uint32_t i, j, k, channel;
FLAC__int32 x, mid, side;
const uint32_t channels = encoder->protected_->channels, blocksize = encoder->protected_->blocksize;
const FLAC__int32 sample_max = INT32_MAX >> (32 - encoder->protected_->bits_per_sample);
const FLAC__int32 sample_min = INT32_MIN >> (32 - encoder->protected_->bits_per_sample);
FLAC__ASSERT(0 != encoder);
FLAC__ASSERT(0 != encoder->private_);
@ -2254,6 +2264,11 @@ FLAC_API FLAC__bool FLAC__stream_encoder_process_interleaved(FLAC__StreamEncoder
/* "i <= blocksize" to overread 1 sample; see comment in OVERREAD_ decl */
for(i = encoder->private_->current_sample_number; i <= blocksize && j < samples; i++, j++) {
if(buffer[k] < sample_min || buffer[k] > sample_max ||
buffer[k+1] < sample_min || buffer[k+1] > sample_max){
encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR;
return false;
}
encoder->private_->integer_signal[0][i] = mid = side = buffer[k++];
x = buffer[k++];
encoder->private_->integer_signal[1][i] = x;
@ -2289,8 +2304,13 @@ FLAC_API FLAC__bool FLAC__stream_encoder_process_interleaved(FLAC__StreamEncoder
/* "i <= blocksize" to overread 1 sample; see comment in OVERREAD_ decl */
for(i = encoder->private_->current_sample_number; i <= blocksize && j < samples; i++, j++) {
for(channel = 0; channel < channels; channel++)
for(channel = 0; channel < channels; channel++){
if(buffer[k] < sample_min || buffer[k] > sample_max){
encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR;
return false;
}
encoder->private_->integer_signal[channel][i] = buffer[k++];
}
}
encoder->private_->current_sample_number = i;
/* we only process if we have a full block + 1 extra sample; final block is always handled by FLAC__stream_encoder_finish() */