From cb985c0a59db4e0f7360239c1cddba98480cbbd0 Mon Sep 17 00:00:00 2001 From: hecko <855807+hecko@users.noreply.github.com> Date: Sat, 11 Jul 2026 03:24:00 +0000 Subject: [PATCH] AmAudio::decode: bound decoded PCM size against back buffer The decoder writes its PCM16 output into samples.back_buffer(), a fixed AUDIO_BUFFER_SIZE (8192-byte) half of the DblBuffer. decode() passed the encoded RTP payload size straight to codec->decode() with no check on how much PCM the codec would produce. AmRtpAudio::receive() reads up to AUDIO_BUFFER_SIZE bytes of RTP payload and hands it to decode(). An expanding codec (GSM ~10x, G.722 4x) fed a large payload emits far more than AUDIO_BUFFER_SIZE bytes of PCM, writing past the end of the DblBuffer -- a remotely-triggerable heap overflow on an established call. Predict the decoded sample count via bytes2samples() and reject the frame when the resulting PCM size would exceed the buffer, before the codec runs. Backported from yeti-switch/sems, which added the same pre-decode buffer-size guard in AmAudio::decode(). sems-server lacks yeti's optional codec frames2samples() hook, so this uses the existing bytes2samples() path (equivalent to yeti's fallback). --- core/AmAudio.cpp | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/core/AmAudio.cpp b/core/AmAudio.cpp index 955734b94..684cfad4b 100644 --- a/core/AmAudio.cpp +++ b/core/AmAudio.cpp @@ -389,12 +389,25 @@ int AmAudio::decode(unsigned int size) } if(codec->decode){ + // Bound the decoder's PCM output against the back buffer before the + // codec writes into it. The decoder writes into samples.back_buffer(), + // which only has AUDIO_BUFFER_SIZE bytes; an expanding codec (e.g. GSM, + // G.722) fed a large RTP payload can produce far more PCM than that and + // overflow the DblBuffer. bytes2samples() predicts the decoded sample + // count for the given encoded size. + unsigned int out_size = PCM16_S2B(bytes2samples(size)); + if(out_size > AUDIO_BUFFER_SIZE){ + ERROR("decoded buffer size for pcm16 (%u) exceeds allowed (%u)\n", + out_size, AUDIO_BUFFER_SIZE); + return -1; + } + s = (*codec->decode)(samples.back_buffer(),samples,s, fmt->channels,getSampleRate(),h_codec); if(s<0) return s; samples.swap(); } - + return s; }