ftmod_isdn: Avoid stack smashing buffer overflow in isdn_tones_run().

The len variable can, in certain situations (large burst of incoming non-SLIN audio),
exceed the size of the on-stack frame buffer, which causes ftdm_buffer_read_loop() to
overwrite the dt_buffer pointer.

Use ftdm_min() to make sure len (after conversion to SLIN units) isn't larger
than the frame buffer size.

Also adds are couple more code comments.

Signed-off-by: Stefan Knoblich <stkn@openisdn.net>
This commit is contained in:
Stefan Knoblich 2012-08-10 17:05:46 +02:00
parent 036063d2a9
commit 2ad2b6d31b
1 changed files with 19 additions and 1 deletions

View File

@ -1936,6 +1936,11 @@ static void *ftdm_isdn_tones_run(ftdm_thread_t *me, void *obj)
continue; continue;
} }
/*
* Teletone operates on SLIN data (2 bytes per sample).
* Convert the length of non-SLIN codecs, so we read
* the right amount of samples from the buffer.
*/
if (chan->effective_codec != FTDM_CODEC_SLIN) { if (chan->effective_codec != FTDM_CODEC_SLIN) {
len *= 2; len *= 2;
} }
@ -1943,6 +1948,12 @@ static void *ftdm_isdn_tones_run(ftdm_thread_t *me, void *obj)
/* seek to current offset */ /* seek to current offset */
ftdm_buffer_seek(dt_buffer, data->offset); ftdm_buffer_seek(dt_buffer, data->offset);
/*
* ftdm_channel_read() can read up to sizeof(frame) bytes
* (in certain situations). Avoid overflowing the stack (and smashing dt_buffer)
* if the codec is not slin and we had to double the length.
*/
len = ftdm_min(len, sizeof(frame));
rlen = ftdm_buffer_read_loop(dt_buffer, frame, len); rlen = ftdm_buffer_read_loop(dt_buffer, frame, len);
if (chan->effective_codec != FTDM_CODEC_SLIN) { if (chan->effective_codec != FTDM_CODEC_SLIN) {
@ -1954,6 +1965,12 @@ static void *ftdm_isdn_tones_run(ftdm_thread_t *me, void *obj)
codec_func = fio_slin2alaw; codec_func = fio_slin2alaw;
} }
/*
* Convert SLIN to native format (a-law/u-law),
* input size is 2 bytes per sample, output size
* (after conversion) is one byte per sample
* (= max. half the input size).
*/
if (codec_func) { if (codec_func) {
status = codec_func(frame, sizeof(frame), &rlen); status = codec_func(frame, sizeof(frame), &rlen);
} else { } else {
@ -1968,11 +1985,12 @@ static void *ftdm_isdn_tones_run(ftdm_thread_t *me, void *obj)
* of data actually written to channel. * of data actually written to channel.
*/ */
if (chan->effective_codec != FTDM_CODEC_SLIN) { if (chan->effective_codec != FTDM_CODEC_SLIN) {
data->offset += rlen << 1; /* teletone buffer is slin (= len * 2) */ data->offset += rlen << 1; /* Teletone buffer is in SLIN (= rlen * 2) */
} else { } else {
data->offset += rlen; data->offset += rlen;
} }
/* Limit offset to [0..Rate(Samples/s)-1] in SLIN (2 bytes per sample) units. */
data->offset %= (ts.rate << 1); data->offset %= (ts.rate << 1);
} }
} }