Skip to content

Commit

Permalink
Fix TLV dB parser in case of used container
Browse files Browse the repository at this point in the history
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: #409
Signed-off-by: Arkadiusz Bokowy <[email protected]>
Signed-off-by: Jaroslav Kysela <[email protected]>
  • Loading branch information
arkq authored and perexg committed Sep 6, 2024
1 parent fc58f8f commit 9ac93d1
Showing 1 changed file with 14 additions and 5 deletions.
19 changes: 14 additions & 5 deletions src/control/tlv.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,19 +40,21 @@
#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

/**
* \brief Parse TLV stream and retrieve dB information
* \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().
*/
Expand All @@ -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];
Expand All @@ -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 */
Expand Down Expand Up @@ -114,7 +123,7 @@ int snd_tlv_parse_dB_info(unsigned int *tlv,
default:
break;
}
return -EINVAL; /* not found */
return -ENOENT;
}

/**
Expand Down

0 comments on commit 9ac93d1

Please sign in to comment.