flac: Explicitly reject FLAC files with more than two channels (FS#13306)

It's not clear that we've ever intended to support >2ch files, based on
'#define MAX_CHANNELS 2' and other logic that only seems to care about
mono vs not.

Change-Id: I15e92fb29cceef32e63fc3a821f6e96bbde930b6
This commit is contained in:
Solomon Peachy 2024-10-14 08:53:43 -04:00
parent 542eeae11c
commit 772eff8ca6

View file

@ -119,7 +119,7 @@ static bool flac_init(FLACContext* fc, int first_frame_offset)
return false; return false;
} }
if (ci->memcmp(buf,"fLaC",4) != 0) if (ci->memcmp(buf,"fLaC",4) != 0)
{ {
return false; return false;
} }
@ -138,7 +138,7 @@ static bool flac_init(FLACContext* fc, int first_frame_offset)
if ((buf[0] & 0x7f) == 0) /* 0 is the STREAMINFO block */ if ((buf[0] & 0x7f) == 0) /* 0 is the STREAMINFO block */
{ {
if (ci->read_filebuf(buf, blocklength) < blocklength) return false; if (ci->read_filebuf(buf, blocklength) < blocklength) return false;
fc->filesize = ci->filesize; fc->filesize = ci->filesize;
fc->min_blocksize = (buf[0] << 8) | buf[1]; fc->min_blocksize = (buf[0] << 8) | buf[1];
int max_blocksize = (buf[2] << 8) | buf[3]; int max_blocksize = (buf[2] << 8) | buf[3];
@ -151,34 +151,40 @@ static bool flac_init(FLACContext* fc, int first_frame_offset)
fc->max_blocksize = max_blocksize; fc->max_blocksize = max_blocksize;
fc->min_framesize = (buf[4] << 16) | (buf[5] << 8) | buf[6]; fc->min_framesize = (buf[4] << 16) | (buf[5] << 8) | buf[6];
fc->max_framesize = (buf[7] << 16) | (buf[8] << 8) | buf[9]; fc->max_framesize = (buf[7] << 16) | (buf[8] << 8) | buf[9];
fc->samplerate = (buf[10] << 12) | (buf[11] << 4) fc->samplerate = (buf[10] << 12) | (buf[11] << 4)
| ((buf[12] & 0xf0) >> 4); | ((buf[12] & 0xf0) >> 4);
fc->channels = ((buf[12]&0x0e)>>1) + 1; fc->channels = ((buf[12]&0x0e)>>1) + 1;
fc->bps = (((buf[12]&0x01) << 4) | ((buf[13]&0xf0)>>4) ) + 1; fc->bps = (((buf[12]&0x01) << 4) | ((buf[13]&0xf0)>>4) ) + 1;
/* totalsamples is a 36-bit field, but we assume <= 32 bits are if (fc->channels > MAX_CHANNELS) {
LOGF("FLAC: Too many channels (%d > %d)\n",
fc->channels, MAX_CHANNELS);
return false;
}
/* totalsamples is a 36-bit field, but we assume <= 32 bits are
used */ used */
fc->totalsamples = (buf[14] << 24) | (buf[15] << 16) fc->totalsamples = (buf[14] << 24) | (buf[15] << 16)
| (buf[16] << 8) | buf[17]; | (buf[16] << 8) | buf[17];
/* Calculate track length (in ms) and estimate the bitrate /* Calculate track length (in ms) and estimate the bitrate
(in kbit/s) */ (in kbit/s) */
fc->length = ((int64_t) fc->totalsamples * 1000) / fc->samplerate; fc->length = ((int64_t) fc->totalsamples * 1000) / fc->samplerate;
found_streaminfo=true; found_streaminfo=true;
} else if ((buf[0] & 0x7f) == 3) { /* 3 is the SEEKTABLE block */ } else if ((buf[0] & 0x7f) == 3) { /* 3 is the SEEKTABLE block */
while ((nseekpoints < MAX_SUPPORTED_SEEKTABLE_SIZE) && while ((nseekpoints < MAX_SUPPORTED_SEEKTABLE_SIZE) &&
(blocklength >= 18)) { (blocklength >= 18)) {
if (ci->read_filebuf(buf,18) < 18) return false; if (ci->read_filebuf(buf,18) < 18) return false;
blocklength-=18; blocklength-=18;
seekpoint_hi=(buf[0] << 24) | (buf[1] << 16) | seekpoint_hi=(buf[0] << 24) | (buf[1] << 16) |
(buf[2] << 8) | buf[3]; (buf[2] << 8) | buf[3];
seekpoint_lo=(buf[4] << 24) | (buf[5] << 16) | seekpoint_lo=(buf[4] << 24) | (buf[5] << 16) |
(buf[6] << 8) | buf[7]; (buf[6] << 8) | buf[7];
offset_hi=(buf[8] << 24) | (buf[9] << 16) | offset_hi=(buf[8] << 24) | (buf[9] << 16) |
(buf[10] << 8) | buf[11]; (buf[10] << 8) | buf[11];
offset_lo=(buf[12] << 24) | (buf[13] << 16) | offset_lo=(buf[12] << 24) | (buf[13] << 16) |
(buf[14] << 8) | buf[15]; (buf[14] << 8) | buf[15];
blocksize=(buf[16] << 8) | buf[17]; blocksize=(buf[16] << 8) | buf[17];
@ -202,7 +208,7 @@ static bool flac_init(FLACContext* fc, int first_frame_offset)
} }
if (found_streaminfo) { if (found_streaminfo) {
fc->bitrate = ((int64_t) (fc->filesize-fc->metadatalength) * 8) fc->bitrate = ((int64_t) (fc->filesize-fc->metadatalength) * 8)
/ fc->length; / fc->length;
return true; return true;
} else { } else {
@ -254,7 +260,7 @@ static bool frame_sync(FLACContext* fc) {
/* Decode the frame to verify the frame crc and /* Decode the frame to verify the frame crc and
* fill fc with its metadata. * fill fc with its metadata.
*/ */
if(flac_decode_frame(fc, if(flac_decode_frame(fc,
bit_buffer, buff_size, ci->yield) < 0) { bit_buffer, buff_size, ci->yield) < 0) {
return false; return false;
} }
@ -326,7 +332,7 @@ static bool flac_seek(FLACContext* fc, uint32_t target_sample) {
(int64_t)(upper_bound - lower_bound)) / (int64_t)(upper_bound - lower_bound)) /
(upper_bound_sample - lower_bound_sample)) - (upper_bound_sample - lower_bound_sample)) -
approx_bytes_per_frame); approx_bytes_per_frame);
if(pos >= (off_t)upper_bound) if(pos >= (off_t)upper_bound)
pos = (off_t)upper_bound-1; pos = (off_t)upper_bound-1;
if(pos < (off_t)lower_bound) if(pos < (off_t)lower_bound)
@ -431,7 +437,7 @@ static bool flac_seek_offset(FLACContext* fc, uint32_t offset) {
if(frame_sync(fc)) if(frame_sync(fc))
got_a_frame = true; got_a_frame = true;
} }
if(!got_a_frame) { if(!got_a_frame) {
ci->seek_buffer(fc->metadatalength); ci->seek_buffer(fc->metadatalength);
return false; return false;
@ -471,7 +477,7 @@ enum codec_status codec_run(void)
/* Need to save resume for later use (cleared indirectly by flac_init) */ /* Need to save resume for later use (cleared indirectly by flac_init) */
elapsedtime = ci->id3->elapsed; elapsedtime = ci->id3->elapsed;
samplesdone = ci->id3->offset; samplesdone = ci->id3->offset;
if (!flac_init(&fc,ci->id3->first_frame_offset)) { if (!flac_init(&fc,ci->id3->first_frame_offset)) {
LOGF("FLAC: Error initialising codec\n"); LOGF("FLAC: Error initialising codec\n");
return CODEC_ERROR; return CODEC_ERROR;
@ -526,7 +532,7 @@ enum codec_status codec_run(void)
ci->yield(); ci->yield();
ci->pcmbuf_insert(&fc.decoded[0][fc.sample_skip], &fc.decoded[1][fc.sample_skip], ci->pcmbuf_insert(&fc.decoded[0][fc.sample_skip], &fc.decoded[1][fc.sample_skip],
fc.blocksize - fc.sample_skip); fc.blocksize - fc.sample_skip);
fc.sample_skip = 0; fc.sample_skip = 0;
/* Update the elapsed-time indicator */ /* Update the elapsed-time indicator */