Commit | Line | Data |
---|---|---|
57f87706 TI |
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 | ||
15 | struct 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 */ | |
25 | static 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 */ | |
35 | static 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 */ | |
69 | static 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; | |
ba8bf096 | 78 | len = sizeof(*d) + d->bNrInPins; |
57f87706 TI |
79 | if (d->bLength < len) |
80 | return false; | |
81 | switch (v->protocol) { | |
82 | case UAC_VERSION_1: | |
83 | default: | |
976a68f0 TI |
84 | /* bNrChannels, wChannelConfig, iChannelNames */ |
85 | len += 1 + 2 + 1; | |
86 | if (d->bLength < len + 1) /* bControlSize */ | |
57f87706 TI |
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 */ | |
f8e5f90b | 113 | switch (le16_to_cpu(d->wProcessType)) { |
57f87706 TI |
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 */ | |
f8e5f90b | 128 | switch (le16_to_cpu(d->wProcessType)) { |
57f87706 TI |
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 | } | |
f8e5f90b | 145 | switch (le16_to_cpu(d->wProcessType)) { |
57f87706 TI |
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 */ | |
167 | static 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 | ||
191 | static 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 | ||
202 | static 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 | ||
213 | static 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 | ||
224 | static 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 | ||
a01df925 | 236 | static const struct usb_desc_validator audio_validators[] = { |
57f87706 TI |
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 | ||
a01df925 | 291 | static const struct usb_desc_validator midi_validators[] = { |
57f87706 TI |
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 */ | |
303 | static 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 | ||
323 | bool snd_usb_validate_audio_desc(void *p, int protocol) | |
324 | { | |
f35ef592 TI |
325 | unsigned char *c = p; |
326 | bool valid; | |
327 | ||
328 | valid = validate_desc(p, protocol, audio_validators); | |
329 | if (!valid && snd_usb_skip_validation) { | |
330 | print_hex_dump(KERN_ERR, "USB-audio: buggy audio desc: ", | |
331 | DUMP_PREFIX_NONE, 16, 1, c, c[0], true); | |
332 | valid = true; | |
333 | } | |
334 | return valid; | |
57f87706 TI |
335 | } |
336 | ||
337 | bool snd_usb_validate_midi_desc(void *p) | |
338 | { | |
f35ef592 TI |
339 | unsigned char *c = p; |
340 | bool valid; | |
341 | ||
342 | valid = validate_desc(p, UAC_VERSION_1, midi_validators); | |
343 | if (!valid && snd_usb_skip_validation) { | |
344 | print_hex_dump(KERN_ERR, "USB-audio: buggy midi desc: ", | |
345 | DUMP_PREFIX_NONE, 16, 1, c, c[0], true); | |
346 | valid = true; | |
347 | } | |
348 | return valid; | |
57f87706 | 349 | } |