tlv: improve robustness of raw value ranges

snd_tlv_convert_from_dB() relies on rangemin/max blindly.
Since this function is exported, it is better for robustness and
consistency to parse the range properly, which this patch does.

Signed-off-by: Benoît Thébaudeau <benoit.thebaudeau@advansee.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
Benoît Thébaudeau 2012-05-23 01:53:01 +02:00 committed by Takashi Iwai
parent afaffe80d9
commit 70b958f460

View file

@ -291,41 +291,37 @@ int snd_tlv_convert_from_dB(unsigned int *tlv, long rangemin, long rangemax,
{ {
switch (tlv[0]) { switch (tlv[0]) {
case SND_CTL_TLVT_DB_RANGE: { case SND_CTL_TLVT_DB_RANGE: {
long dbmin, dbmax, prev_rangemax; long dbmin, dbmax, prev_submax;
unsigned int pos, len; unsigned int pos, len;
len = int_index(tlv[1]); len = int_index(tlv[1]);
if (len > MAX_TLV_RANGE_SIZE) if (len < 6 || len > MAX_TLV_RANGE_SIZE)
return -EINVAL; return -EINVAL;
if (snd_tlv_get_dB_range(tlv, rangemin, rangemax,
&dbmin, &dbmax))
return -EINVAL;
if (db_gain <= dbmin) {
*value = rangemin;
return 0;
} else if (db_gain >= dbmax) {
*value = rangemax;
return 0;
}
pos = 2; pos = 2;
prev_rangemax = 0; prev_submax = 0;
while (pos + 4 <= len) { while (pos + 4 <= len) {
rangemin = (int)tlv[pos]; long submin, submax;
rangemax = (int)tlv[pos + 1]; submin = (int)tlv[pos];
submax = (int)tlv[pos + 1];
if (rangemax < submax)
submax = rangemax;
if (!snd_tlv_get_dB_range(tlv + pos + 2, if (!snd_tlv_get_dB_range(tlv + pos + 2,
rangemin, rangemax, submin, submax,
&dbmin, &dbmax) && &dbmin, &dbmax) &&
db_gain >= dbmin && db_gain <= dbmax) db_gain >= dbmin && db_gain <= dbmax)
return snd_tlv_convert_from_dB(tlv + pos + 2, return snd_tlv_convert_from_dB(tlv + pos + 2,
rangemin, rangemax, submin, submax,
db_gain, value, xdir); db_gain, value, xdir);
else if (db_gain < dbmin) { else if (db_gain < dbmin) {
*value = xdir ? rangemin : prev_rangemax; *value = xdir || pos == 2 ? submin : prev_submax;
return 0; return 0;
} }
prev_rangemax = rangemax; prev_submax = submax;
if (rangemax == submax)
break;
pos += int_index(tlv[pos + 3]) + 4; pos += int_index(tlv[pos + 3]) + 4;
} }
return -EINVAL; *value = prev_submax;
return 0;
} }
case SND_CTL_TLVT_DB_SCALE: { case SND_CTL_TLVT_DB_SCALE: {
int min, step, max; int min, step, max;