From 3bd10b4f0ea8c5a7e2da2b8d00a15b6ddf26e66f Mon Sep 17 00:00:00 2001 From: Ondrej Holy Date: Tue, 28 Apr 2026 04:41:15 +0000 Subject: [PATCH] [codec,dsp] fix array bounds checks Backport of commit 16df2300e1e3f5a51f68fb1626429e58b531b7c8. Adapted for 3.10.x: kept `int channel` parameter type in `dsp_encode_ima_adpcm_sample` (not `size_t`), kept `+=` style for step index updates. Made-with: Cursor --- libfreerdp/codec/dsp.c | 79 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 70 insertions(+), 9 deletions(-) diff --git a/libfreerdp/codec/dsp.c b/libfreerdp/codec/dsp.c index 5e0f78a..b672074 100644 --- a/libfreerdp/codec/dsp.c +++ b/libfreerdp/codec/dsp.c @@ -321,7 +321,14 @@ static const INT16 ima_step_size_table[] = { static UINT16 dsp_decode_ima_adpcm_sample(ADPCM* WINPR_RESTRICT adpcm, unsigned int channel, BYTE sample) { - const INT32 ss = ima_step_size_table[adpcm->ima.last_step[channel]]; + WINPR_ASSERT(channel < ARRAYSIZE(adpcm->ima.last_step)); + WINPR_ASSERT(channel < ARRAYSIZE(adpcm->ima.last_sample)); + + const INT16 offset = adpcm->ima.last_step[channel]; + WINPR_ASSERT(offset >= 0); + WINPR_ASSERT(offset < ARRAYSIZE(ima_step_size_table)); + + const INT32 ss = ima_step_size_table[offset]; INT32 d = (ss >> 3); if (sample & 1) @@ -344,6 +351,8 @@ static UINT16 dsp_decode_ima_adpcm_sample(ADPCM* WINPR_RESTRICT adpcm, unsigned d = 32767; adpcm->ima.last_sample[channel] = (INT16)d; + + WINPR_ASSERT(sample < ARRAYSIZE(ima_step_index_table)); adpcm->ima.last_step[channel] += ima_step_index_table[sample]; if (adpcm->ima.last_step[channel] < 0) @@ -386,6 +395,9 @@ static BOOL freerdp_dsp_decode_ima_adpcm(FREERDP_DSP_CONTEXT* WINPR_RESTRICT con { if (size % block_size == 0) { + if (size < 4) + return FALSE; + context->adpcm.ima.last_sample[0] = (INT16)(((UINT16)(*src)) | (((UINT16)(*(src + 1))) << 8)); context->adpcm.ima.last_step[0] = (INT16)(*(src + 2)); @@ -395,6 +407,8 @@ static BOOL freerdp_dsp_decode_ima_adpcm(FREERDP_DSP_CONTEXT* WINPR_RESTRICT con if (channels > 1) { + if (size < 4) + return FALSE; context->adpcm.ima.last_sample[1] = (INT16)(((UINT16)(*src)) | (((UINT16)(*(src + 1))) << 8)); context->adpcm.ima.last_step[1] = (INT16)(*(src + 2)); @@ -406,6 +420,8 @@ static BOOL freerdp_dsp_decode_ima_adpcm(FREERDP_DSP_CONTEXT* WINPR_RESTRICT con if (channels > 1) { + if (size < 8) + return FALSE; for (size_t i = 0; i < 8; i++) { BYTE* dst = Stream_Pointer(out); @@ -434,6 +450,8 @@ static BOOL freerdp_dsp_decode_ima_adpcm(FREERDP_DSP_CONTEXT* WINPR_RESTRICT con } else { + if (size < 1) + return FALSE; BYTE* dst = Stream_Pointer(out); if (!Stream_SafeSeek(out, 4)) return FALSE; @@ -775,7 +793,14 @@ static const struct static BYTE dsp_encode_ima_adpcm_sample(ADPCM* WINPR_RESTRICT adpcm, int channel, INT16 sample) { - INT32 ss = ima_step_size_table[adpcm->ima.last_step[channel]]; + WINPR_ASSERT(channel < ARRAYSIZE(adpcm->ima.last_step)); + WINPR_ASSERT(channel < ARRAYSIZE(adpcm->ima.last_sample)); + + const INT16 offset = adpcm->ima.last_step[channel]; + WINPR_ASSERT(offset >= 0); + WINPR_ASSERT(offset < ARRAYSIZE(ima_step_size_table)); + + INT32 ss = ima_step_size_table[offset]; INT32 e = sample - adpcm->ima.last_sample[channel]; INT32 d = e; INT32 diff = ss >> 3; @@ -822,6 +847,8 @@ static BYTE dsp_encode_ima_adpcm_sample(ADPCM* WINPR_RESTRICT adpcm, int channel diff = 32767; adpcm->ima.last_sample[channel] = (INT16)diff; + + WINPR_ASSERT(enc < ARRAYSIZE(ima_step_index_table)); adpcm->ima.last_step[channel] += ima_step_index_table[enc]; if (adpcm->ima.last_step[channel] < 0) @@ -937,11 +964,22 @@ static BOOL valid_ms_adpcm_format(const FREERDP_DSP_CONTEXT* WINPR_RESTRICT cont static INLINE INT16 freerdp_dsp_decode_ms_adpcm_sample(ADPCM* WINPR_RESTRICT adpcm, BYTE sample, int channel) { + WINPR_ASSERT(channel < ARRAYSIZE(adpcm->ms.sample1)); + WINPR_ASSERT(channel < ARRAYSIZE(adpcm->ms.sample2)); + WINPR_ASSERT(channel < ARRAYSIZE(adpcm->ms.delta)); + WINPR_ASSERT(channel < ARRAYSIZE(adpcm->ms.predictor)); + const INT8 nibble = (sample & 0x08 ? (INT8)sample - 16 : (INT8)sample); + const BYTE predictor = adpcm->ms.predictor[channel]; + INT32 coeff1 = 0; + if (predictor < ARRAYSIZE(ms_adpcm_coeffs1)) + coeff1 = ms_adpcm_coeffs1[predictor]; + + INT32 coeff2 = 0; + if (predictor < ARRAYSIZE(ms_adpcm_coeffs2)) + coeff2 = ms_adpcm_coeffs2[predictor]; INT32 presample = - ((adpcm->ms.sample1[channel] * ms_adpcm_coeffs1[adpcm->ms.predictor[channel]]) + - (adpcm->ms.sample2[channel] * ms_adpcm_coeffs2[adpcm->ms.predictor[channel]])) / - 256; + ((adpcm->ms.sample1[channel] * coeff1) + (adpcm->ms.sample2[channel] * coeff2)) / 256; presample += nibble * adpcm->ms.delta[channel]; if (presample > 32767) @@ -951,7 +989,12 @@ static INLINE INT16 freerdp_dsp_decode_ms_adpcm_sample(ADPCM* WINPR_RESTRICT adp adpcm->ms.sample2[channel] = adpcm->ms.sample1[channel]; adpcm->ms.sample1[channel] = presample; - adpcm->ms.delta[channel] = adpcm->ms.delta[channel] * ms_adpcm_adaptation_table[sample] / 256; + + INT32 tableval = 0; + if (sample < ARRAYSIZE(ms_adpcm_adaptation_table)) + tableval = ms_adpcm_adaptation_table[sample]; + + adpcm->ms.delta[channel] = adpcm->ms.delta[channel] * tableval / 256; if (adpcm->ms.delta[channel] < 16) adpcm->ms.delta[channel] = 16; @@ -978,6 +1021,9 @@ static BOOL freerdp_dsp_decode_ms_adpcm(FREERDP_DSP_CONTEXT* WINPR_RESTRICT cont { if (channels > 1) { + if (size < 14) + return FALSE; + context->adpcm.ms.predictor[0] = *src++; context->adpcm.ms.predictor[1] = *src++; context->adpcm.ms.delta[0] = read_int16(src); @@ -1000,6 +1046,9 @@ static BOOL freerdp_dsp_decode_ms_adpcm(FREERDP_DSP_CONTEXT* WINPR_RESTRICT cont } else { + if (size < 7) + return FALSE; + context->adpcm.ms.predictor[0] = *src++; context->adpcm.ms.delta[0] = read_int16(src); src += 2; @@ -1016,6 +1065,8 @@ static BOOL freerdp_dsp_decode_ms_adpcm(FREERDP_DSP_CONTEXT* WINPR_RESTRICT cont if (channels > 1) { { + if (size < 1) + return FALSE; const BYTE sample = *src++; size--; Stream_Write_INT16( @@ -1024,6 +1075,8 @@ static BOOL freerdp_dsp_decode_ms_adpcm(FREERDP_DSP_CONTEXT* WINPR_RESTRICT cont out, freerdp_dsp_decode_ms_adpcm_sample(&context->adpcm, sample & 0x0F, 1)); } { + if (size < 1) + return FALSE; const BYTE sample = *src++; size--; Stream_Write_INT16( @@ -1034,6 +1087,8 @@ static BOOL freerdp_dsp_decode_ms_adpcm(FREERDP_DSP_CONTEXT* WINPR_RESTRICT cont } else { + if (size < 1) + return FALSE; const BYTE sample = *src++; size--; Stream_Write_INT16(out, @@ -1047,8 +1102,13 @@ static BOOL freerdp_dsp_decode_ms_adpcm(FREERDP_DSP_CONTEXT* WINPR_RESTRICT cont } static BYTE freerdp_dsp_encode_ms_adpcm_sample(ADPCM* WINPR_RESTRICT adpcm, INT32 sample, - int channel) + size_t channel) { + WINPR_ASSERT(channel < ARRAYSIZE(adpcm->ms.sample1)); + WINPR_ASSERT(channel < ARRAYSIZE(adpcm->ms.sample2)); + WINPR_ASSERT(channel < ARRAYSIZE(adpcm->ms.delta)); + WINPR_ASSERT(channel < ARRAYSIZE(adpcm->ms.predictor)); + INT32 presample = ((adpcm->ms.sample1[channel] * ms_adpcm_coeffs1[adpcm->ms.predictor[channel]]) + (adpcm->ms.sample2[channel] * ms_adpcm_coeffs2[adpcm->ms.predictor[channel]])) / @@ -1072,8 +1132,9 @@ static BYTE freerdp_dsp_encode_ms_adpcm_sample(ADPCM* WINPR_RESTRICT adpcm, INT3 adpcm->ms.sample2[channel] = adpcm->ms.sample1[channel]; adpcm->ms.sample1[channel] = presample; - adpcm->ms.delta[channel] = - adpcm->ms.delta[channel] * ms_adpcm_adaptation_table[(((BYTE)errordelta) & 0x0F)] / 256; + const size_t offset = (((BYTE)errordelta) & 0x0F); + WINPR_ASSERT(offset < ARRAYSIZE(ms_adpcm_adaptation_table)); + adpcm->ms.delta[channel] = adpcm->ms.delta[channel] * ms_adpcm_adaptation_table[offset] / 256; if (adpcm->ms.delta[channel] < 16) adpcm->ms.delta[channel] = 16; -- 2.53.0