From 8a98baa696c9dfff181d95dcdc6143b96d145a4c Mon Sep 17 00:00:00 2001 From: Stefan Knoblich Date: Fri, 10 Aug 2012 17:05:46 +0200 Subject: [PATCH] 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 --- .../freetdm/src/ftmod/ftmod_isdn/ftmod_isdn.c | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/libs/freetdm/src/ftmod/ftmod_isdn/ftmod_isdn.c b/libs/freetdm/src/ftmod/ftmod_isdn/ftmod_isdn.c index 11139f7fb4..99ff253835 100644 --- a/libs/freetdm/src/ftmod/ftmod_isdn/ftmod_isdn.c +++ b/libs/freetdm/src/ftmod/ftmod_isdn/ftmod_isdn.c @@ -1936,6 +1936,11 @@ static void *ftdm_isdn_tones_run(ftdm_thread_t *me, void *obj) 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) { len *= 2; } @@ -1943,6 +1948,12 @@ static void *ftdm_isdn_tones_run(ftdm_thread_t *me, void *obj) /* seek to current 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); 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; } + /* + * 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) { status = codec_func(frame, sizeof(frame), &rlen); } else { @@ -1968,11 +1985,12 @@ static void *ftdm_isdn_tones_run(ftdm_thread_t *me, void *obj) * of data actually written to channel. */ 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 { data->offset += rlen; } + /* Limit offset to [0..Rate(Samples/s)-1] in SLIN (2 bytes per sample) units. */ data->offset %= (ts.rate << 1); } }