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 (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; |
78 | len = 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 */ |
85 | len += 1 + 2 + 1; |
86 | if (d->bLength < len + 1) /* 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 (le16_to_cpu(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 (le16_to_cpu(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 (le16_to_cpu(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 */ |
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 | |
236 | static const 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 | |
291 | static const 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 */ |
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 | { |
325 | unsigned char *c = p; |
326 | bool valid; |
327 | |
328 | valid = validate_desc(hdr: p, protocol, v: audio_validators); |
329 | if (!valid && snd_usb_skip_validation) { |
330 | print_hex_dump(KERN_ERR, prefix_str: "USB-audio: buggy audio desc: " , |
331 | prefix_type: DUMP_PREFIX_NONE, rowsize: 16, groupsize: 1, buf: c, len: c[0], ascii: true); |
332 | valid = true; |
333 | } |
334 | return valid; |
335 | } |
336 | |
337 | bool snd_usb_validate_midi_desc(void *p) |
338 | { |
339 | unsigned char *c = p; |
340 | bool valid; |
341 | |
342 | valid = validate_desc(hdr: p, UAC_VERSION_1, v: midi_validators); |
343 | if (!valid && snd_usb_skip_validation) { |
344 | print_hex_dump(KERN_ERR, prefix_str: "USB-audio: buggy midi desc: " , |
345 | prefix_type: DUMP_PREFIX_NONE, rowsize: 16, groupsize: 1, buf: c, len: c[0], ascii: true); |
346 | valid = true; |
347 | } |
348 | return valid; |
349 | } |
350 | |