]> git.alsa-project.org Git - alsa-lib.git/commitdiff
Fix TLV dB parser in case of used container
authorArkadiusz Bokowy <arkadiusz.bokowy@gmail.com>
Sat, 31 Aug 2024 18:31:02 +0000 (20:31 +0200)
committerJaroslav Kysela <perex@perex.cz>
Fri, 6 Sep 2024 08:51:06 +0000 (10:51 +0200)
In case when dB information does not appear as the only TLV type in the
stream (it might be wrapped in a container, but the container can not
have any other type), the TLV parser fails to get the dB TLV pointer.

This commit fixes it by distinguishing between TLV parse error and dB
information not being found in a container (-ENOENT), so the parser can iterate
over all elements in the container.

Also, it fixes out-of-bounds read in case of malicious TLV record.

Closes: https://github.com/alsa-project/alsa-lib/pull/409
Signed-off-by: Arkadiusz Bokowy <arkadiusz.bokowy@gmail.com>
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
src/control/tlv.c

index 3a2b731df53fb1cce47bdfce8bd9d1cc7b91fa47..fed46acd55098a36ce14fbf7b8421c6661fba15c 100644 (file)
@@ -40,6 +40,8 @@
 #define int_index(size)        (((size) + sizeof(int) - 1) / sizeof(int))
 /* max size of a TLV entry for dB information (including compound one) */
 #define MAX_TLV_RANGE_SIZE     256
+/* min length of a TLV stream to contain type and size */
+#define MIN_TLV_STREAM_LEN     ((SNDRV_CTL_TLVO_LEN + 1) * sizeof(int))
 #endif
 
 /**
  * \param tlv the TLV source
  * \param tlv_size the byte size of TLV source
  * \param db_tlvp the pointer stored the dB TLV information
- * \return the byte size of dB TLV information if found in the given
- *   TLV source, or a negative error code.
+ * \return The byte size of dB TLV information if found in the given TLV
+ *   source, -ENOENT if not found, or a negative error code in case of an error.
  *
  * This function parses the given TLV source and stores the TLV start
  * point if the TLV information regarding dB conversion is found.
- * The stored TLV pointer can be passed to the convesion functions
+ * The stored TLV pointer can be passed to the conversion functions
  * #snd_tlv_convert_to_dB(), #snd_tlv_convert_from_dB() and
  * #snd_tlv_get_dB_range().
  */
@@ -64,6 +66,13 @@ int snd_tlv_parse_dB_info(unsigned int *tlv,
        unsigned int size;
        int err;
 
+       /* Validate that it is possible to read the type and size
+        * without reading past the end of the buffer. */
+       if (tlv_size < MIN_TLV_STREAM_LEN) {
+               SNDERR("TLV stream too short");
+               return -EINVAL;
+       }
+
        *db_tlvp = NULL;
        type = tlv[SNDRV_CTL_TLVO_TYPE];
        size = tlv[SNDRV_CTL_TLVO_LEN];
@@ -79,7 +88,7 @@ int snd_tlv_parse_dB_info(unsigned int *tlv,
                while (size > 0) {
                        unsigned int len;
                        err = snd_tlv_parse_dB_info(tlv, size, db_tlvp);
-                       if (err < 0)
+                       if (err < 0 && err != -ENOENT)
                                return err; /* error */
                        if (err > 0)
                                return err; /* found */
@@ -114,7 +123,7 @@ int snd_tlv_parse_dB_info(unsigned int *tlv,
        default:
                break;
        }
-       return -EINVAL; /* not found */
+       return -ENOENT;
 }
 
 /**