ALSA: usb-audio: More validations of descriptor units

Introduce a new helper to validate each audio descriptor unit before
and check the unit before actually accessing it.  This should harden
against the OOB access cases with malformed descriptors that have been
recently frequently reported by fuzzers.

The existing descriptor checks are still kept although they become
superfluous after this patch.  They'll be cleaned up eventually
later.

Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
Takashi Iwai
2019-08-20 17:17:09 +02:00
parent f9f0e9ed35
commit 57f8770620
7 changed files with 366 additions and 13 deletions

View File

@@ -627,16 +627,14 @@ static int parse_uac_endpoint_attributes(struct snd_usb_audio *chip,
*/
static void *
snd_usb_find_input_terminal_descriptor(struct usb_host_interface *ctrl_iface,
int terminal_id, bool uac23)
int terminal_id, int protocol)
{
struct uac2_input_terminal_descriptor *term = NULL;
size_t minlen = uac23 ? sizeof(struct uac2_input_terminal_descriptor) :
sizeof(struct uac_input_terminal_descriptor);
while ((term = snd_usb_find_csint_desc(ctrl_iface->extra,
ctrl_iface->extralen,
term, UAC_INPUT_TERMINAL))) {
if (term->bLength < minlen)
if (!snd_usb_validate_audio_desc(term, protocol))
continue;
if (term->bTerminalID == terminal_id)
return term;
@@ -647,7 +645,7 @@ snd_usb_find_input_terminal_descriptor(struct usb_host_interface *ctrl_iface,
static void *
snd_usb_find_output_terminal_descriptor(struct usb_host_interface *ctrl_iface,
int terminal_id)
int terminal_id, int protocol)
{
/* OK to use with both UAC2 and UAC3 */
struct uac2_output_terminal_descriptor *term = NULL;
@@ -655,8 +653,9 @@ snd_usb_find_output_terminal_descriptor(struct usb_host_interface *ctrl_iface,
while ((term = snd_usb_find_csint_desc(ctrl_iface->extra,
ctrl_iface->extralen,
term, UAC_OUTPUT_TERMINAL))) {
if (term->bLength >= sizeof(*term) &&
term->bTerminalID == terminal_id)
if (!snd_usb_validate_audio_desc(term, protocol))
continue;
if (term->bTerminalID == terminal_id)
return term;
}
@@ -731,7 +730,7 @@ snd_usb_get_audioformat_uac12(struct snd_usb_audio *chip,
iterm = snd_usb_find_input_terminal_descriptor(chip->ctrl_intf,
as->bTerminalLink,
false);
protocol);
if (iterm) {
num_channels = iterm->bNrChannels;
chconfig = le16_to_cpu(iterm->wChannelConfig);
@@ -767,7 +766,7 @@ snd_usb_get_audioformat_uac12(struct snd_usb_audio *chip,
*/
input_term = snd_usb_find_input_terminal_descriptor(chip->ctrl_intf,
as->bTerminalLink,
true);
protocol);
if (input_term) {
clock = input_term->bCSourceID;
if (!chconfig && (num_channels == input_term->bNrChannels))
@@ -776,7 +775,8 @@ snd_usb_get_audioformat_uac12(struct snd_usb_audio *chip,
}
output_term = snd_usb_find_output_terminal_descriptor(chip->ctrl_intf,
as->bTerminalLink);
as->bTerminalLink,
protocol);
if (output_term) {
clock = output_term->bCSourceID;
goto found_clock;
@@ -1002,14 +1002,15 @@ snd_usb_get_audioformat_uac3(struct snd_usb_audio *chip,
*/
input_term = snd_usb_find_input_terminal_descriptor(chip->ctrl_intf,
as->bTerminalLink,
true);
UAC_VERSION_3);
if (input_term) {
clock = input_term->bCSourceID;
goto found_clock;
}
output_term = snd_usb_find_output_terminal_descriptor(chip->ctrl_intf,
as->bTerminalLink);
as->bTerminalLink,
UAC_VERSION_3);
if (output_term) {
clock = output_term->bCSourceID;
goto found_clock;