Skip to content

Commit 57f8770

Browse files
committed
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>
1 parent f9f0e9e commit 57f8770

File tree

7 files changed

+366
-13
lines changed

7 files changed

+366
-13
lines changed

sound/usb/Makefile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@ snd-usb-audio-objs := card.o \
1616
power.o \
1717
proc.o \
1818
quirks.o \
19-
stream.o
19+
stream.o \
20+
validate.o
2021

2122
snd-usb-audio-$(CONFIG_SND_USB_AUDIO_USE_MEDIA_CONTROLLER) += media.o
2223

sound/usb/helper.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,8 @@ static inline int snd_usb_ctrl_intf(struct snd_usb_audio *chip)
3131
return get_iface_desc(chip->ctrl_intf)->bInterfaceNumber;
3232
}
3333

34+
/* in validate.c */
35+
bool snd_usb_validate_audio_desc(void *p, int protocol);
36+
bool snd_usb_validate_midi_desc(void *p);
37+
3438
#endif /* __USBAUDIO_HELPER_H */

sound/usb/mixer.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -785,6 +785,8 @@ static int __check_input_term(struct mixer_build *state, int id,
785785
p1 = find_audio_control_unit(state, id);
786786
if (!p1)
787787
break;
788+
if (!snd_usb_validate_audio_desc(p1, protocol))
789+
break; /* bad descriptor */
788790

789791
hdr = p1;
790792
term->id = id;
@@ -2775,6 +2777,11 @@ static int parse_audio_unit(struct mixer_build *state, int unitid)
27752777
return -EINVAL;
27762778
}
27772779

2780+
if (!snd_usb_validate_audio_desc(p1, protocol)) {
2781+
usb_audio_dbg(state->chip, "invalid unit %d\n", unitid);
2782+
return 0; /* skip invalid unit */
2783+
}
2784+
27782785
if (protocol == UAC_VERSION_1 || protocol == UAC_VERSION_2) {
27792786
switch (p1[2]) {
27802787
case UAC_INPUT_TERMINAL:
@@ -3145,6 +3152,9 @@ static int snd_usb_mixer_controls(struct usb_mixer_interface *mixer)
31453152
while ((p = snd_usb_find_csint_desc(mixer->hostif->extra,
31463153
mixer->hostif->extralen,
31473154
p, UAC_OUTPUT_TERMINAL)) != NULL) {
3155+
if (!snd_usb_validate_audio_desc(p, mixer->protocol))
3156+
continue; /* skip invalid descriptor */
3157+
31483158
if (mixer->protocol == UAC_VERSION_1) {
31493159
struct uac1_output_terminal_descriptor *desc = p;
31503160

sound/usb/power.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ snd_usb_find_power_domain(struct usb_host_interface *ctrl_iface,
3131
struct uac3_power_domain_descriptor *pd_desc = p;
3232
int i;
3333

34+
if (!snd_usb_validate_audio_desc(p, UAC_VERSION_3))
35+
continue;
3436
for (i = 0; i < pd_desc->bNrEntities; i++) {
3537
if (pd_desc->baEntityID[i] == id) {
3638
pd->pd_id = pd_desc->bPowerDomainID;

sound/usb/quirks.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,9 @@ static int create_yamaha_midi_quirk(struct snd_usb_audio *chip,
248248
NULL, USB_MS_MIDI_OUT_JACK);
249249
if (!injd && !outjd)
250250
return -ENODEV;
251+
if (!snd_usb_validate_midi_desc(injd) ||
252+
!snd_usb_validate_midi_desc(outjd))
253+
return -ENODEV;
251254
if (injd && (injd->bLength < 5 ||
252255
(injd->bJackType != USB_MS_EMBEDDED &&
253256
injd->bJackType != USB_MS_EXTERNAL)))

sound/usb/stream.c

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -627,16 +627,14 @@ static int parse_uac_endpoint_attributes(struct snd_usb_audio *chip,
627627
*/
628628
static void *
629629
snd_usb_find_input_terminal_descriptor(struct usb_host_interface *ctrl_iface,
630-
int terminal_id, bool uac23)
630+
int terminal_id, int protocol)
631631
{
632632
struct uac2_input_terminal_descriptor *term = NULL;
633-
size_t minlen = uac23 ? sizeof(struct uac2_input_terminal_descriptor) :
634-
sizeof(struct uac_input_terminal_descriptor);
635633

636634
while ((term = snd_usb_find_csint_desc(ctrl_iface->extra,
637635
ctrl_iface->extralen,
638636
term, UAC_INPUT_TERMINAL))) {
639-
if (term->bLength < minlen)
637+
if (!snd_usb_validate_audio_desc(term, protocol))
640638
continue;
641639
if (term->bTerminalID == terminal_id)
642640
return term;
@@ -647,16 +645,17 @@ snd_usb_find_input_terminal_descriptor(struct usb_host_interface *ctrl_iface,
647645

648646
static void *
649647
snd_usb_find_output_terminal_descriptor(struct usb_host_interface *ctrl_iface,
650-
int terminal_id)
648+
int terminal_id, int protocol)
651649
{
652650
/* OK to use with both UAC2 and UAC3 */
653651
struct uac2_output_terminal_descriptor *term = NULL;
654652

655653
while ((term = snd_usb_find_csint_desc(ctrl_iface->extra,
656654
ctrl_iface->extralen,
657655
term, UAC_OUTPUT_TERMINAL))) {
658-
if (term->bLength >= sizeof(*term) &&
659-
term->bTerminalID == terminal_id)
656+
if (!snd_usb_validate_audio_desc(term, protocol))
657+
continue;
658+
if (term->bTerminalID == terminal_id)
660659
return term;
661660
}
662661

@@ -731,7 +730,7 @@ snd_usb_get_audioformat_uac12(struct snd_usb_audio *chip,
731730

732731
iterm = snd_usb_find_input_terminal_descriptor(chip->ctrl_intf,
733732
as->bTerminalLink,
734-
false);
733+
protocol);
735734
if (iterm) {
736735
num_channels = iterm->bNrChannels;
737736
chconfig = le16_to_cpu(iterm->wChannelConfig);
@@ -767,7 +766,7 @@ snd_usb_get_audioformat_uac12(struct snd_usb_audio *chip,
767766
*/
768767
input_term = snd_usb_find_input_terminal_descriptor(chip->ctrl_intf,
769768
as->bTerminalLink,
770-
true);
769+
protocol);
771770
if (input_term) {
772771
clock = input_term->bCSourceID;
773772
if (!chconfig && (num_channels == input_term->bNrChannels))
@@ -776,7 +775,8 @@ snd_usb_get_audioformat_uac12(struct snd_usb_audio *chip,
776775
}
777776

778777
output_term = snd_usb_find_output_terminal_descriptor(chip->ctrl_intf,
779-
as->bTerminalLink);
778+
as->bTerminalLink,
779+
protocol);
780780
if (output_term) {
781781
clock = output_term->bCSourceID;
782782
goto found_clock;
@@ -1002,14 +1002,15 @@ snd_usb_get_audioformat_uac3(struct snd_usb_audio *chip,
10021002
*/
10031003
input_term = snd_usb_find_input_terminal_descriptor(chip->ctrl_intf,
10041004
as->bTerminalLink,
1005-
true);
1005+
UAC_VERSION_3);
10061006
if (input_term) {
10071007
clock = input_term->bCSourceID;
10081008
goto found_clock;
10091009
}
10101010

10111011
output_term = snd_usb_find_output_terminal_descriptor(chip->ctrl_intf,
1012-
as->bTerminalLink);
1012+
as->bTerminalLink,
1013+
UAC_VERSION_3);
10131014
if (output_term) {
10141015
clock = output_term->bCSourceID;
10151016
goto found_clock;

0 commit comments

Comments
 (0)