[ALSA] ak4xxx - Check value ranges in ctl callbacks
Check the value ranges in ctl put callbacks properly in ak4xxx-adda driver.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
diff --git a/sound/i2c/other/ak4xxx-adda.c b/sound/i2c/other/ak4xxx-adda.c
index de03f68..39bb03a 100644
--- a/sound/i2c/other/ak4xxx-adda.c
+++ b/sound/i2c/other/ak4xxx-adda.c
@@ -377,8 +377,11 @@
static int snd_akm4xxx_volume_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- return put_ak_reg(kcontrol, AK_GET_ADDR(kcontrol->private_value),
- ucontrol->value.integer.value[0]);
+ unsigned int mask = AK_GET_MASK(kcontrol->private_value);
+ unsigned int val = ucontrol->value.integer.value[0];
+ if (val > mask)
+ return -EINVAL;
+ return put_ak_reg(kcontrol, AK_GET_ADDR(kcontrol->private_value), val);
}
static int snd_akm4xxx_stereo_volume_info(struct snd_kcontrol *kcontrol,
@@ -409,11 +412,16 @@
struct snd_ctl_elem_value *ucontrol)
{
int addr = AK_GET_ADDR(kcontrol->private_value);
+ unsigned int mask = AK_GET_MASK(kcontrol->private_value);
+ unsigned int val[2];
int change;
- change = put_ak_reg(kcontrol, addr, ucontrol->value.integer.value[0]);
- change |= put_ak_reg(kcontrol, addr + 1,
- ucontrol->value.integer.value[1]);
+ val[0] = ucontrol->value.integer.value[0];
+ val[1] = ucontrol->value.integer.value[1];
+ if (val[0] > mask || val[1] > mask)
+ return -EINVAL;
+ change = put_ak_reg(kcontrol, addr, val[0]);
+ change |= put_ak_reg(kcontrol, addr + 1, val[1]);
return change;
}
@@ -508,6 +516,18 @@
#define AK5365_NUM_INPUTS 5
+static int ak4xxx_capture_num_inputs(struct snd_akm4xxx *ak, int mixer_ch)
+{
+ int num_names;
+ const char **input_names;
+
+ input_names = ak->adc_info[mixer_ch].input_names;
+ num_names = 0;
+ while (num_names < AK5365_NUM_INPUTS && input_names[num_names])
+ ++num_names;
+ return num_names;
+}
+
static int ak4xxx_capture_source_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
@@ -516,18 +536,16 @@
const char **input_names;
int num_names, idx;
- input_names = ak->adc_info[mixer_ch].input_names;
-
- num_names = 0;
- while (num_names < AK5365_NUM_INPUTS && input_names[num_names])
- ++num_names;
-
+ num_names = ak4xxx_capture_num_inputs(ak, mixer_ch);
+ if (!num_names)
+ return -EINVAL;
uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
uinfo->count = 1;
uinfo->value.enumerated.items = num_names;
idx = uinfo->value.enumerated.item;
if (idx >= num_names)
return -EINVAL;
+ input_names = ak->adc_info[mixer_ch].input_names;
strncpy(uinfo->value.enumerated.name, input_names[idx],
sizeof(uinfo->value.enumerated.name));
return 0;
@@ -551,10 +569,15 @@
struct snd_ctl_elem_value *ucontrol)
{
struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
+ int mixer_ch = AK_GET_SHIFT(kcontrol->private_value);
int chip = AK_GET_CHIP(kcontrol->private_value);
int addr = AK_GET_ADDR(kcontrol->private_value);
int mask = AK_GET_MASK(kcontrol->private_value);
unsigned char oval, val;
+ int num_names = ak4xxx_capture_num_inputs(ak, mixer_ch);
+
+ if (ucontrol->value.enumerated.item[0] >= num_names)
+ return -EINVAL;
oval = snd_akm4xxx_get(ak, chip, addr);
val = oval & ~mask;