[PATCH v2] ALSA: hdsp: Validate DDS offset range and propagate errors

From: songxiebing

Date: Wed Nov 04 2026 - 04:06:55 EST


From: Bob Song <songxiebing@xxxxxxxxxx>

hdsp_set_dds_offset() computes the target rate as
system_sample_rate + offset_hz without validating the result. A user
can set the DDS offset to -system_sample_rate through the control API,
making rate zero and causing div_u64() in hdsp_set_dds_value() to
divide by zero. Larger offsets can also overflow the rate calculation
or push the DDS value out of range.

Validate offset_hz against the [-5000, 5000] range advertised by the
control, keep the non-positive rate check as a safety net, and
propagate the error from snd_hdsp_put_dds_offset() instead of
reporting success.

Fixes: e4b6088c8cf1 ("[ALSA] hdsp - Add support for fine tuning of sample rate support to HDSP 9632")
Cc: <stable@xxxxxxxxxxxxxxx>
Signed-off-by: Bob Song <songxiebing@xxxxxxxxxx>
---
sound/pci/rme9652/hdsp.c | 27 +++++++++++++++++++++------
1 file changed, 21 insertions(+), 6 deletions(-)

diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c
index 7dce548b9f36..467121a5fb4f 100644
--- a/sound/pci/rme9652/hdsp.c
+++ b/sound/pci/rme9652/hdsp.c
@@ -2768,6 +2768,9 @@ static int snd_hdsp_get_adat_sync_check(struct snd_kcontrol *kcontrol, struct sn
return 0;
}

+#define HDSP_DDS_OFFSET_MIN -5000
+#define HDSP_DDS_OFFSET_MAX 5000
+
#define HDSP_DDS_OFFSET(xname, xindex) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
.name = xname, \
@@ -2801,7 +2804,15 @@ static int hdsp_dds_offset(struct hdsp *hdsp)

static int hdsp_set_dds_offset(struct hdsp *hdsp, int offset_hz)
{
- int rate = hdsp->system_sample_rate + offset_hz;
+ int rate;
+
+ if (offset_hz < HDSP_DDS_OFFSET_MIN ||
+ offset_hz > HDSP_DDS_OFFSET_MAX)
+ return -EINVAL;
+
+ rate = hdsp->system_sample_rate + offset_hz;
+ if (rate <= 0)
+ return -EINVAL;
hdsp_set_dds_value(hdsp, rate);
return 0;
}
@@ -2810,8 +2821,8 @@ static int snd_hdsp_info_dds_offset(struct snd_kcontrol *kcontrol, struct snd_ct
{
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
uinfo->count = 1;
- uinfo->value.integer.min = -5000;
- uinfo->value.integer.max = 5000;
+ uinfo->value.integer.min = HDSP_DDS_OFFSET_MIN;
+ uinfo->value.integer.max = HDSP_DDS_OFFSET_MAX;
return 0;
}

@@ -2833,10 +2844,14 @@ static int snd_hdsp_put_dds_offset(struct snd_kcontrol *kcontrol, struct snd_ctl
return -EBUSY;
val = ucontrol->value.integer.value[0];
guard(spinlock_irq)(&hdsp->lock);
- if (val != hdsp_dds_offset(hdsp))
- change = (hdsp_set_dds_offset(hdsp, val) == 0) ? 1 : 0;
- else
+ if (val != hdsp_dds_offset(hdsp)) {
+ change = hdsp_set_dds_offset(hdsp, val);
+ if (change < 0)
+ return change;
+ change = 1;
+ } else {
change = 0;
+ }
return change;
}

--
2.25.1