summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2019-08-20 11:17:09 -0400
committerTakashi Iwai <tiwai@suse.de>2019-08-22 04:35:59 -0400
commit57f8770620e9b51c61089751f0b5ad3dbe376ff2 (patch)
tree3302223d107681aa8b7558e68fdf1bf322cdc4b4
parentf9f0e9ed350e15d51ad07364b4cf910de50c472a (diff)
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>
-rw-r--r--sound/usb/Makefile3
-rw-r--r--sound/usb/helper.h4
-rw-r--r--sound/usb/mixer.c10
-rw-r--r--sound/usb/power.c2
-rw-r--r--sound/usb/quirks.c3
-rw-r--r--sound/usb/stream.c25
-rw-r--r--sound/usb/validate.c332
7 files changed, 366 insertions, 13 deletions
diff --git a/sound/usb/Makefile b/sound/usb/Makefile
index e1ce257ab705..d27a21b0ff9c 100644
--- a/sound/usb/Makefile
+++ b/sound/usb/Makefile
@@ -16,7 +16,8 @@ snd-usb-audio-objs := card.o \
16 power.o \ 16 power.o \
17 proc.o \ 17 proc.o \
18 quirks.o \ 18 quirks.o \
19 stream.o 19 stream.o \
20 validate.o
20 21
21snd-usb-audio-$(CONFIG_SND_USB_AUDIO_USE_MEDIA_CONTROLLER) += media.o 22snd-usb-audio-$(CONFIG_SND_USB_AUDIO_USE_MEDIA_CONTROLLER) += media.o
22 23
diff --git a/sound/usb/helper.h b/sound/usb/helper.h
index 6afb70156ec4..5e8a18b4e7b9 100644
--- a/sound/usb/helper.h
+++ b/sound/usb/helper.h
@@ -31,4 +31,8 @@ static inline int snd_usb_ctrl_intf(struct snd_usb_audio *chip)
31 return get_iface_desc(chip->ctrl_intf)->bInterfaceNumber; 31 return get_iface_desc(chip->ctrl_intf)->bInterfaceNumber;
32} 32}
33 33
34/* in validate.c */
35bool snd_usb_validate_audio_desc(void *p, int protocol);
36bool snd_usb_validate_midi_desc(void *p);
37
34#endif /* __USBAUDIO_HELPER_H */ 38#endif /* __USBAUDIO_HELPER_H */
diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
index eceab19766db..a1093fb9bf09 100644
--- a/sound/usb/mixer.c
+++ b/sound/usb/mixer.c
@@ -785,6 +785,8 @@ static int __check_input_term(struct mixer_build *state, int id,
785 p1 = find_audio_control_unit(state, id); 785 p1 = find_audio_control_unit(state, id);
786 if (!p1) 786 if (!p1)
787 break; 787 break;
788 if (!snd_usb_validate_audio_desc(p1, protocol))
789 break; /* bad descriptor */
788 790
789 hdr = p1; 791 hdr = p1;
790 term->id = id; 792 term->id = id;
@@ -2775,6 +2777,11 @@ static int parse_audio_unit(struct mixer_build *state, int unitid)
2775 return -EINVAL; 2777 return -EINVAL;
2776 } 2778 }
2777 2779
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
2778 if (protocol == UAC_VERSION_1 || protocol == UAC_VERSION_2) { 2785 if (protocol == UAC_VERSION_1 || protocol == UAC_VERSION_2) {
2779 switch (p1[2]) { 2786 switch (p1[2]) {
2780 case UAC_INPUT_TERMINAL: 2787 case UAC_INPUT_TERMINAL:
@@ -3145,6 +3152,9 @@ static int snd_usb_mixer_controls(struct usb_mixer_interface *mixer)
3145 while ((p = snd_usb_find_csint_desc(mixer->hostif->extra, 3152 while ((p = snd_usb_find_csint_desc(mixer->hostif->extra,
3146 mixer->hostif->extralen, 3153 mixer->hostif->extralen,
3147 p, UAC_OUTPUT_TERMINAL)) != NULL) { 3154 p, UAC_OUTPUT_TERMINAL)) != NULL) {
3155 if (!snd_usb_validate_audio_desc(p, mixer->protocol))
3156 continue; /* skip invalid descriptor */
3157
3148 if (mixer->protocol == UAC_VERSION_1) { 3158 if (mixer->protocol == UAC_VERSION_1) {
3149 struct uac1_output_terminal_descriptor *desc = p; 3159 struct uac1_output_terminal_descriptor *desc = p;
3150 3160
diff --git a/sound/usb/power.c b/sound/usb/power.c
index bd303a1ba1b7..606a2cb23eab 100644
--- a/sound/usb/power.c
+++ b/sound/usb/power.c
@@ -31,6 +31,8 @@ snd_usb_find_power_domain(struct usb_host_interface *ctrl_iface,
31 struct uac3_power_domain_descriptor *pd_desc = p; 31 struct uac3_power_domain_descriptor *pd_desc = p;
32 int i; 32 int i;
33 33
34 if (!snd_usb_validate_audio_desc(p, UAC_VERSION_3))
35 continue;
34 for (i = 0; i < pd_desc->bNrEntities; i++) { 36 for (i = 0; i < pd_desc->bNrEntities; i++) {
35 if (pd_desc->baEntityID[i] == id) { 37 if (pd_desc->baEntityID[i] == id) {
36 pd->pd_id = pd_desc->bPowerDomainID; 38 pd->pd_id = pd_desc->bPowerDomainID;
diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c
index 78858918cbc1..7e9735aa7ac9 100644
--- a/sound/usb/quirks.c
+++ b/sound/usb/quirks.c
@@ -248,6 +248,9 @@ static int create_yamaha_midi_quirk(struct snd_usb_audio *chip,
248 NULL, USB_MS_MIDI_OUT_JACK); 248 NULL, USB_MS_MIDI_OUT_JACK);
249 if (!injd && !outjd) 249 if (!injd && !outjd)
250 return -ENODEV; 250 return -ENODEV;
251 if (!snd_usb_validate_midi_desc(injd) ||
252 !snd_usb_validate_midi_desc(outjd))
253 return -ENODEV;
251 if (injd && (injd->bLength < 5 || 254 if (injd && (injd->bLength < 5 ||
252 (injd->bJackType != USB_MS_EMBEDDED && 255 (injd->bJackType != USB_MS_EMBEDDED &&
253 injd->bJackType != USB_MS_EXTERNAL))) 256 injd->bJackType != USB_MS_EXTERNAL)))
diff --git a/sound/usb/stream.c b/sound/usb/stream.c
index e852c7fd6109..a0649c8ae460 100644
--- a/sound/usb/stream.c
+++ b/sound/usb/stream.c
@@ -627,16 +627,14 @@ static int parse_uac_endpoint_attributes(struct snd_usb_audio *chip,
627 */ 627 */
628static void * 628static void *
629snd_usb_find_input_terminal_descriptor(struct usb_host_interface *ctrl_iface, 629snd_usb_find_input_terminal_descriptor(struct usb_host_interface *ctrl_iface,
630 int terminal_id, bool uac23) 630 int terminal_id, int protocol)
631{ 631{
632 struct uac2_input_terminal_descriptor *term = NULL; 632 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);
635 633
636 while ((term = snd_usb_find_csint_desc(ctrl_iface->extra, 634 while ((term = snd_usb_find_csint_desc(ctrl_iface->extra,
637 ctrl_iface->extralen, 635 ctrl_iface->extralen,
638 term, UAC_INPUT_TERMINAL))) { 636 term, UAC_INPUT_TERMINAL))) {
639 if (term->bLength < minlen) 637 if (!snd_usb_validate_audio_desc(term, protocol))
640 continue; 638 continue;
641 if (term->bTerminalID == terminal_id) 639 if (term->bTerminalID == terminal_id)
642 return term; 640 return term;
@@ -647,7 +645,7 @@ snd_usb_find_input_terminal_descriptor(struct usb_host_interface *ctrl_iface,
647 645
648static void * 646static void *
649snd_usb_find_output_terminal_descriptor(struct usb_host_interface *ctrl_iface, 647snd_usb_find_output_terminal_descriptor(struct usb_host_interface *ctrl_iface,
650 int terminal_id) 648 int terminal_id, int protocol)
651{ 649{
652 /* OK to use with both UAC2 and UAC3 */ 650 /* OK to use with both UAC2 and UAC3 */
653 struct uac2_output_terminal_descriptor *term = NULL; 651 struct uac2_output_terminal_descriptor *term = NULL;
@@ -655,8 +653,9 @@ snd_usb_find_output_terminal_descriptor(struct usb_host_interface *ctrl_iface,
655 while ((term = snd_usb_find_csint_desc(ctrl_iface->extra, 653 while ((term = snd_usb_find_csint_desc(ctrl_iface->extra,
656 ctrl_iface->extralen, 654 ctrl_iface->extralen,
657 term, UAC_OUTPUT_TERMINAL))) { 655 term, UAC_OUTPUT_TERMINAL))) {
658 if (term->bLength >= sizeof(*term) && 656 if (!snd_usb_validate_audio_desc(term, protocol))
659 term->bTerminalID == terminal_id) 657 continue;
658 if (term->bTerminalID == terminal_id)
660 return term; 659 return term;
661 } 660 }
662 661
@@ -731,7 +730,7 @@ snd_usb_get_audioformat_uac12(struct snd_usb_audio *chip,
731 730
732 iterm = snd_usb_find_input_terminal_descriptor(chip->ctrl_intf, 731 iterm = snd_usb_find_input_terminal_descriptor(chip->ctrl_intf,
733 as->bTerminalLink, 732 as->bTerminalLink,
734 false); 733 protocol);
735 if (iterm) { 734 if (iterm) {
736 num_channels = iterm->bNrChannels; 735 num_channels = iterm->bNrChannels;
737 chconfig = le16_to_cpu(iterm->wChannelConfig); 736 chconfig = le16_to_cpu(iterm->wChannelConfig);
@@ -767,7 +766,7 @@ snd_usb_get_audioformat_uac12(struct snd_usb_audio *chip,
767 */ 766 */
768 input_term = snd_usb_find_input_terminal_descriptor(chip->ctrl_intf, 767 input_term = snd_usb_find_input_terminal_descriptor(chip->ctrl_intf,
769 as->bTerminalLink, 768 as->bTerminalLink,
770 true); 769 protocol);
771 if (input_term) { 770 if (input_term) {
772 clock = input_term->bCSourceID; 771 clock = input_term->bCSourceID;
773 if (!chconfig && (num_channels == input_term->bNrChannels)) 772 if (!chconfig && (num_channels == input_term->bNrChannels))
@@ -776,7 +775,8 @@ snd_usb_get_audioformat_uac12(struct snd_usb_audio *chip,
776 } 775 }
777 776
778 output_term = snd_usb_find_output_terminal_descriptor(chip->ctrl_intf, 777 output_term = snd_usb_find_output_terminal_descriptor(chip->ctrl_intf,
779 as->bTerminalLink); 778 as->bTerminalLink,
779 protocol);
780 if (output_term) { 780 if (output_term) {
781 clock = output_term->bCSourceID; 781 clock = output_term->bCSourceID;
782 goto found_clock; 782 goto found_clock;
@@ -1002,14 +1002,15 @@ snd_usb_get_audioformat_uac3(struct snd_usb_audio *chip,
1002 */ 1002 */
1003 input_term = snd_usb_find_input_terminal_descriptor(chip->ctrl_intf, 1003 input_term = snd_usb_find_input_terminal_descriptor(chip->ctrl_intf,
1004 as->bTerminalLink, 1004 as->bTerminalLink,
1005 true); 1005 UAC_VERSION_3);
1006 if (input_term) { 1006 if (input_term) {
1007 clock = input_term->bCSourceID; 1007 clock = input_term->bCSourceID;
1008 goto found_clock; 1008 goto found_clock;
1009 } 1009 }
1010 1010
1011 output_term = snd_usb_find_output_terminal_descriptor(chip->ctrl_intf, 1011 output_term = snd_usb_find_output_terminal_descriptor(chip->ctrl_intf,
1012 as->bTerminalLink); 1012 as->bTerminalLink,
1013 UAC_VERSION_3);
1013 if (output_term) { 1014 if (output_term) {
1014 clock = output_term->bCSourceID; 1015 clock = output_term->bCSourceID;
1015 goto found_clock; 1016 goto found_clock;
diff --git a/sound/usb/validate.c b/sound/usb/validate.c
new file mode 100644
index 000000000000..3c8f73a0eb12
--- /dev/null
+++ b/sound/usb/validate.c
@@ -0,0 +1,332 @@
1// SPDX-License-Identifier: GPL-2.0-or-later
2//
3// Validation of USB-audio class descriptors
4//
5
6#include <linux/init.h>
7#include <linux/usb.h>
8#include <linux/usb/audio.h>
9#include <linux/usb/audio-v2.h>
10#include <linux/usb/audio-v3.h>
11#include <linux/usb/midi.h>
12#include "usbaudio.h"
13#include "helper.h"
14
15struct usb_desc_validator {
16 unsigned char protocol;
17 unsigned char type;
18 bool (*func)(const void *p, const struct usb_desc_validator *v);
19 size_t size;
20};
21
22#define UAC_VERSION_ALL (unsigned char)(-1)
23
24/* UAC1 only */
25static bool validate_uac1_header(const void *p,
26 const struct usb_desc_validator *v)
27{
28 const struct uac1_ac_header_descriptor *d = p;
29
30 return d->bLength >= sizeof(*d) &&
31 d->bLength >= sizeof(*d) + d->bInCollection;
32}
33
34/* for mixer unit; covering all UACs */
35static bool validate_mixer_unit(const void *p,
36 const struct usb_desc_validator *v)
37{
38 const struct uac_mixer_unit_descriptor *d = p;
39 size_t len;
40
41 if (d->bLength < sizeof(*d) || !d->bNrInPins)
42 return false;
43 len = sizeof(*d) + d->bNrInPins;
44 /* We can't determine the bitmap size only from this unit descriptor,
45 * so just check with the remaining length.
46 * The actual bitmap is checked at mixer unit parser.
47 */
48 switch (v->protocol) {
49 case UAC_VERSION_1:
50 default:
51 len += 2 + 1; /* wChannelConfig, iChannelNames */
52 /* bmControls[n*m] */
53 len += 1; /* iMixer */
54 break;
55 case UAC_VERSION_2:
56 len += 4 + 1; /* bmChannelConfig, iChannelNames */
57 /* bmMixerControls[n*m] */
58 len += 1 + 1; /* bmControls, iMixer */
59 break;
60 case UAC_VERSION_3:
61 len += 2; /* wClusterDescrID */
62 /* bmMixerControls[n*m] */
63 break;
64 }
65 return d->bLength >= len;
66}
67
68/* both for processing and extension units; covering all UACs */
69static bool validate_processing_unit(const void *p,
70 const struct usb_desc_validator *v)
71{
72 const struct uac_processing_unit_descriptor *d = p;
73 const unsigned char *hdr = p;
74 size_t len, m;
75
76 if (d->bLength < sizeof(*d))
77 return false;
78 len = d->bLength < sizeof(*d) + d->bNrInPins;
79 if (d->bLength < len)
80 return false;
81 switch (v->protocol) {
82 case UAC_VERSION_1:
83 default:
84 /* bNrChannels, wChannelConfig, iChannelNames, bControlSize */
85 len += 1 + 2 + 1 + 1;
86 if (d->bLength < len) /* bControlSize */
87 return false;
88 m = hdr[len];
89 len += 1 + m + 1; /* bControlSize, bmControls, iProcessing */
90 break;
91 case UAC_VERSION_2:
92 /* bNrChannels, bmChannelConfig, iChannelNames */
93 len += 1 + 4 + 1;
94 if (v->type == UAC2_PROCESSING_UNIT_V2)
95 len += 2; /* bmControls -- 2 bytes for PU */
96 else
97 len += 1; /* bmControls -- 1 byte for EU */
98 len += 1; /* iProcessing */
99 break;
100 case UAC_VERSION_3:
101 /* wProcessingDescrStr, bmControls */
102 len += 2 + 4;
103 break;
104 }
105 if (d->bLength < len)
106 return false;
107
108 switch (v->protocol) {
109 case UAC_VERSION_1:
110 default:
111 if (v->type == UAC1_EXTENSION_UNIT)
112 return true; /* OK */
113 switch (d->wProcessType) {
114 case UAC_PROCESS_UP_DOWNMIX:
115 case UAC_PROCESS_DOLBY_PROLOGIC:
116 if (d->bLength < len + 1) /* bNrModes */
117 return false;
118 m = hdr[len];
119 len += 1 + m * 2; /* bNrModes, waModes(n) */
120 break;
121 default:
122 break;
123 }
124 break;
125 case UAC_VERSION_2:
126 if (v->type == UAC2_EXTENSION_UNIT_V2)
127 return true; /* OK */
128 switch (d->wProcessType) {
129 case UAC2_PROCESS_UP_DOWNMIX:
130 case UAC2_PROCESS_DOLBY_PROLOCIC: /* SiC! */
131 if (d->bLength < len + 1) /* bNrModes */
132 return false;
133 m = hdr[len];
134 len += 1 + m * 4; /* bNrModes, daModes(n) */
135 break;
136 default:
137 break;
138 }
139 break;
140 case UAC_VERSION_3:
141 if (v->type == UAC3_EXTENSION_UNIT) {
142 len += 2; /* wClusterDescrID */
143 break;
144 }
145 switch (d->wProcessType) {
146 case UAC3_PROCESS_UP_DOWNMIX:
147 if (d->bLength < len + 1) /* bNrModes */
148 return false;
149 m = hdr[len];
150 len += 1 + m * 2; /* bNrModes, waClusterDescrID(n) */
151 break;
152 case UAC3_PROCESS_MULTI_FUNCTION:
153 len += 2 + 4; /* wClusterDescrID, bmAlgorighms */
154 break;
155 default:
156 break;
157 }
158 break;
159 }
160 if (d->bLength < len)
161 return false;
162
163 return true;
164}
165
166/* both for selector and clock selector units; covering all UACs */
167static bool validate_selector_unit(const void *p,
168 const struct usb_desc_validator *v)
169{
170 const struct uac_selector_unit_descriptor *d = p;
171 size_t len;
172
173 if (d->bLength < sizeof(*d))
174 return false;
175 len = sizeof(*d) + d->bNrInPins;
176 switch (v->protocol) {
177 case UAC_VERSION_1:
178 default:
179 len += 1; /* iSelector */
180 break;
181 case UAC_VERSION_2:
182 len += 1 + 1; /* bmControls, iSelector */
183 break;
184 case UAC_VERSION_3:
185 len += 4 + 2; /* bmControls, wSelectorDescrStr */
186 break;
187 }
188 return d->bLength >= len;
189}
190
191static bool validate_uac1_feature_unit(const void *p,
192 const struct usb_desc_validator *v)
193{
194 const struct uac_feature_unit_descriptor *d = p;
195
196 if (d->bLength < sizeof(*d) || !d->bControlSize)
197 return false;
198 /* at least bmaControls(0) for master channel + iFeature */
199 return d->bLength >= sizeof(*d) + d->bControlSize + 1;
200}
201
202static bool validate_uac2_feature_unit(const void *p,
203 const struct usb_desc_validator *v)
204{
205 const struct uac2_feature_unit_descriptor *d = p;
206
207 if (d->bLength < sizeof(*d))
208 return false;
209 /* at least bmaControls(0) for master channel + iFeature */
210 return d->bLength >= sizeof(*d) + 4 + 1;
211}
212
213static bool validate_uac3_feature_unit(const void *p,
214 const struct usb_desc_validator *v)
215{
216 const struct uac3_feature_unit_descriptor *d = p;
217
218 if (d->bLength < sizeof(*d))
219 return false;
220 /* at least bmaControls(0) for master channel + wFeatureDescrStr */
221 return d->bLength >= sizeof(*d) + 4 + 2;
222}
223
224static bool validate_midi_out_jack(const void *p,
225 const struct usb_desc_validator *v)
226{
227 const struct usb_midi_out_jack_descriptor *d = p;
228
229 return d->bLength >= sizeof(*d) &&
230 d->bLength >= sizeof(*d) + d->bNrInputPins * 2;
231}
232
233#define FIXED(p, t, s) { .protocol = (p), .type = (t), .size = sizeof(s) }
234#define FUNC(p, t, f) { .protocol = (p), .type = (t), .func = (f) }
235
236static struct usb_desc_validator audio_validators[] = {
237 /* UAC1 */
238 FUNC(UAC_VERSION_1, UAC_HEADER, validate_uac1_header),
239 FIXED(UAC_VERSION_1, UAC_INPUT_TERMINAL,
240 struct uac_input_terminal_descriptor),
241 FIXED(UAC_VERSION_1, UAC_OUTPUT_TERMINAL,
242 struct uac1_output_terminal_descriptor),
243 FUNC(UAC_VERSION_1, UAC_MIXER_UNIT, validate_mixer_unit),
244 FUNC(UAC_VERSION_1, UAC_SELECTOR_UNIT, validate_selector_unit),
245 FUNC(UAC_VERSION_1, UAC_FEATURE_UNIT, validate_uac1_feature_unit),
246 FUNC(UAC_VERSION_1, UAC1_PROCESSING_UNIT, validate_processing_unit),
247 FUNC(UAC_VERSION_1, UAC1_EXTENSION_UNIT, validate_processing_unit),
248
249 /* UAC2 */
250 FIXED(UAC_VERSION_2, UAC_HEADER, struct uac2_ac_header_descriptor),
251 FIXED(UAC_VERSION_2, UAC_INPUT_TERMINAL,
252 struct uac2_input_terminal_descriptor),
253 FIXED(UAC_VERSION_2, UAC_OUTPUT_TERMINAL,
254 struct uac2_output_terminal_descriptor),
255 FUNC(UAC_VERSION_2, UAC_MIXER_UNIT, validate_mixer_unit),
256 FUNC(UAC_VERSION_2, UAC_SELECTOR_UNIT, validate_selector_unit),
257 FUNC(UAC_VERSION_2, UAC_FEATURE_UNIT, validate_uac2_feature_unit),
258 /* UAC_VERSION_2, UAC2_EFFECT_UNIT: not implemented yet */
259 FUNC(UAC_VERSION_2, UAC2_PROCESSING_UNIT_V2, validate_processing_unit),
260 FUNC(UAC_VERSION_2, UAC2_EXTENSION_UNIT_V2, validate_processing_unit),
261 FIXED(UAC_VERSION_2, UAC2_CLOCK_SOURCE,
262 struct uac_clock_source_descriptor),
263 FUNC(UAC_VERSION_2, UAC2_CLOCK_SELECTOR, validate_selector_unit),
264 FIXED(UAC_VERSION_2, UAC2_CLOCK_MULTIPLIER,
265 struct uac_clock_multiplier_descriptor),
266 /* UAC_VERSION_2, UAC2_SAMPLE_RATE_CONVERTER: not implemented yet */
267
268 /* UAC3 */
269 FIXED(UAC_VERSION_2, UAC_HEADER, struct uac3_ac_header_descriptor),
270 FIXED(UAC_VERSION_3, UAC_INPUT_TERMINAL,
271 struct uac3_input_terminal_descriptor),
272 FIXED(UAC_VERSION_3, UAC_OUTPUT_TERMINAL,
273 struct uac3_output_terminal_descriptor),
274 /* UAC_VERSION_3, UAC3_EXTENDED_TERMINAL: not implemented yet */
275 FUNC(UAC_VERSION_3, UAC3_MIXER_UNIT, validate_mixer_unit),
276 FUNC(UAC_VERSION_3, UAC3_SELECTOR_UNIT, validate_selector_unit),
277 FUNC(UAC_VERSION_3, UAC_FEATURE_UNIT, validate_uac3_feature_unit),
278 /* UAC_VERSION_3, UAC3_EFFECT_UNIT: not implemented yet */
279 FUNC(UAC_VERSION_3, UAC3_PROCESSING_UNIT, validate_processing_unit),
280 FUNC(UAC_VERSION_3, UAC3_EXTENSION_UNIT, validate_processing_unit),
281 FIXED(UAC_VERSION_3, UAC3_CLOCK_SOURCE,
282 struct uac3_clock_source_descriptor),
283 FUNC(UAC_VERSION_3, UAC3_CLOCK_SELECTOR, validate_selector_unit),
284 FIXED(UAC_VERSION_3, UAC3_CLOCK_MULTIPLIER,
285 struct uac3_clock_multiplier_descriptor),
286 /* UAC_VERSION_3, UAC3_SAMPLE_RATE_CONVERTER: not implemented yet */
287 /* UAC_VERSION_3, UAC3_CONNECTORS: not implemented yet */
288 { } /* terminator */
289};
290
291static struct usb_desc_validator midi_validators[] = {
292 FIXED(UAC_VERSION_ALL, USB_MS_HEADER,
293 struct usb_ms_header_descriptor),
294 FIXED(UAC_VERSION_ALL, USB_MS_MIDI_IN_JACK,
295 struct usb_midi_in_jack_descriptor),
296 FUNC(UAC_VERSION_ALL, USB_MS_MIDI_OUT_JACK,
297 validate_midi_out_jack),
298 { } /* terminator */
299};
300
301
302/* Validate the given unit descriptor, return true if it's OK */
303static bool validate_desc(unsigned char *hdr, int protocol,
304 const struct usb_desc_validator *v)
305{
306 if (hdr[1] != USB_DT_CS_INTERFACE)
307 return true; /* don't care */
308
309 for (; v->type; v++) {
310 if (v->type == hdr[2] &&
311 (v->protocol == UAC_VERSION_ALL ||
312 v->protocol == protocol)) {
313 if (v->func)
314 return v->func(hdr, v);
315 /* check for the fixed size */
316 return hdr[0] >= v->size;
317 }
318 }
319
320 return true; /* not matching, skip validation */
321}
322
323bool snd_usb_validate_audio_desc(void *p, int protocol)
324{
325 return validate_desc(p, protocol, audio_validators);
326}
327
328bool snd_usb_validate_midi_desc(void *p)
329{
330 return validate_desc(p, UAC_VERSION_1, midi_validators);
331}
332