OSDN Git Service

tlv: improve robustness of raw value ranges
authorBenoît Thébaudeau <benoit.thebaudeau@advansee.com>
Tue, 22 May 2012 23:53:01 +0000 (01:53 +0200)
committerTakashi Iwai <tiwai@suse.de>
Tue, 22 May 2012 23:53:28 +0000 (01:53 +0200)
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>
src/control/tlv.c

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