freerdp/codec-dsp-fix-array-bounds-checks.patch
2026-05-11 17:35:23 -04:00

225 lines
8.2 KiB
Diff

From 3bd10b4f0ea8c5a7e2da2b8d00a15b6ddf26e66f Mon Sep 17 00:00:00 2001
From: Ondrej Holy <oholy@redhat.com>
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