1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * compat ioctls for control API
4 *
5 * Copyright (c) by Takashi Iwai <tiwai@suse.de>
6 */
7
8/* this file included from control.c */
9
10#include <linux/compat.h>
11#include <linux/slab.h>
12
13struct snd_ctl_elem_list32 {
14 u32 offset;
15 u32 space;
16 u32 used;
17 u32 count;
18 u32 pids;
19 unsigned char reserved[50];
20} /* don't set packed attribute here */;
21
22static int snd_ctl_elem_list_compat(struct snd_card *card,
23 struct snd_ctl_elem_list32 __user *data32)
24{
25 struct snd_ctl_elem_list data = {};
26 compat_caddr_t ptr;
27 int err;
28
29 /* offset, space, used, count */
30 if (copy_from_user(to: &data, from: data32, n: 4 * sizeof(u32)))
31 return -EFAULT;
32 /* pids */
33 if (get_user(ptr, &data32->pids))
34 return -EFAULT;
35 data.pids = compat_ptr(uptr: ptr);
36 err = snd_ctl_elem_list(card, list: &data);
37 if (err < 0)
38 return err;
39 /* copy the result */
40 if (copy_to_user(to: data32, from: &data, n: 4 * sizeof(u32)))
41 return -EFAULT;
42 return 0;
43}
44
45/*
46 * control element info
47 * it uses union, so the things are not easy..
48 */
49
50struct snd_ctl_elem_info32 {
51 struct snd_ctl_elem_id id; // the size of struct is same
52 s32 type;
53 u32 access;
54 u32 count;
55 s32 owner;
56 union {
57 struct {
58 s32 min;
59 s32 max;
60 s32 step;
61 } integer;
62 struct {
63 u64 min;
64 u64 max;
65 u64 step;
66 } integer64;
67 struct {
68 u32 items;
69 u32 item;
70 char name[64];
71 u64 names_ptr;
72 u32 names_length;
73 } enumerated;
74 unsigned char reserved[128];
75 } value;
76 unsigned char reserved[64];
77} __packed;
78
79static int snd_ctl_elem_info_compat(struct snd_ctl_file *ctl,
80 struct snd_ctl_elem_info32 __user *data32)
81{
82 struct snd_ctl_elem_info *data __free(kfree) = NULL;
83 int err;
84
85 data = kzalloc(size: sizeof(*data), GFP_KERNEL);
86 if (! data)
87 return -ENOMEM;
88
89 /* copy id */
90 if (copy_from_user(to: &data->id, from: &data32->id, n: sizeof(data->id)))
91 return -EFAULT;
92 /* we need to copy the item index.
93 * hope this doesn't break anything..
94 */
95 if (get_user(data->value.enumerated.item, &data32->value.enumerated.item))
96 return -EFAULT;
97
98 err = snd_ctl_elem_info(ctl, info: data);
99 if (err < 0)
100 return err;
101 /* restore info to 32bit */
102 /* id, type, access, count */
103 if (copy_to_user(to: &data32->id, from: &data->id, n: sizeof(data->id)) ||
104 copy_to_user(to: &data32->type, from: &data->type, n: 3 * sizeof(u32)))
105 return -EFAULT;
106 if (put_user(data->owner, &data32->owner))
107 return -EFAULT;
108 switch (data->type) {
109 case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
110 case SNDRV_CTL_ELEM_TYPE_INTEGER:
111 if (put_user(data->value.integer.min, &data32->value.integer.min) ||
112 put_user(data->value.integer.max, &data32->value.integer.max) ||
113 put_user(data->value.integer.step, &data32->value.integer.step))
114 return -EFAULT;
115 break;
116 case SNDRV_CTL_ELEM_TYPE_INTEGER64:
117 if (copy_to_user(to: &data32->value.integer64,
118 from: &data->value.integer64,
119 n: sizeof(data->value.integer64)))
120 return -EFAULT;
121 break;
122 case SNDRV_CTL_ELEM_TYPE_ENUMERATED:
123 if (copy_to_user(to: &data32->value.enumerated,
124 from: &data->value.enumerated,
125 n: sizeof(data->value.enumerated)))
126 return -EFAULT;
127 break;
128 default:
129 break;
130 }
131 return 0;
132}
133
134/* read / write */
135struct snd_ctl_elem_value32 {
136 struct snd_ctl_elem_id id;
137 unsigned int indirect; /* bit-field causes misalignment */
138 union {
139 s32 integer[128];
140 unsigned char data[512];
141#ifndef CONFIG_X86_64
142 s64 integer64[64];
143#endif
144 } value;
145 unsigned char reserved[128];
146};
147
148#ifdef CONFIG_X86_X32_ABI
149/* x32 has a different alignment for 64bit values from ia32 */
150struct snd_ctl_elem_value_x32 {
151 struct snd_ctl_elem_id id;
152 unsigned int indirect; /* bit-field causes misalignment */
153 union {
154 s32 integer[128];
155 unsigned char data[512];
156 s64 integer64[64];
157 } value;
158 unsigned char reserved[128];
159};
160#endif /* CONFIG_X86_X32_ABI */
161
162/* get the value type and count of the control */
163static int get_ctl_type(struct snd_card *card, struct snd_ctl_elem_id *id,
164 int *countp)
165{
166 struct snd_kcontrol *kctl;
167 struct snd_ctl_elem_info *info __free(kfree) = NULL;
168 int err;
169
170 guard(rwsem_read)(T: &card->controls_rwsem);
171 kctl = snd_ctl_find_id_locked(card, id);
172 if (!kctl)
173 return -ENOENT;
174 info = kzalloc(size: sizeof(*info), GFP_KERNEL);
175 if (info == NULL)
176 return -ENOMEM;
177 info->id = *id;
178 err = snd_power_ref_and_wait(card);
179 if (!err)
180 err = kctl->info(kctl, info);
181 snd_power_unref(card);
182 if (err >= 0) {
183 err = info->type;
184 *countp = info->count;
185 }
186 return err;
187}
188
189static int get_elem_size(snd_ctl_elem_type_t type, int count)
190{
191 switch (type) {
192 case SNDRV_CTL_ELEM_TYPE_INTEGER64:
193 return sizeof(s64) * count;
194 case SNDRV_CTL_ELEM_TYPE_ENUMERATED:
195 return sizeof(int) * count;
196 case SNDRV_CTL_ELEM_TYPE_BYTES:
197 return 512;
198 case SNDRV_CTL_ELEM_TYPE_IEC958:
199 return sizeof(struct snd_aes_iec958);
200 default:
201 return -1;
202 }
203}
204
205static int copy_ctl_value_from_user(struct snd_card *card,
206 struct snd_ctl_elem_value *data,
207 void __user *userdata,
208 void __user *valuep,
209 int *typep, int *countp)
210{
211 struct snd_ctl_elem_value32 __user *data32 = userdata;
212 int i, type, size;
213 int count;
214 unsigned int indirect;
215
216 if (copy_from_user(to: &data->id, from: &data32->id, n: sizeof(data->id)))
217 return -EFAULT;
218 if (get_user(indirect, &data32->indirect))
219 return -EFAULT;
220 if (indirect)
221 return -EINVAL;
222 type = get_ctl_type(card, id: &data->id, countp: &count);
223 if (type < 0)
224 return type;
225
226 if (type == (__force int)SNDRV_CTL_ELEM_TYPE_BOOLEAN ||
227 type == (__force int)SNDRV_CTL_ELEM_TYPE_INTEGER) {
228 for (i = 0; i < count; i++) {
229 s32 __user *intp = valuep;
230 int val;
231 if (get_user(val, &intp[i]))
232 return -EFAULT;
233 data->value.integer.value[i] = val;
234 }
235 } else {
236 size = get_elem_size(type: (__force snd_ctl_elem_type_t)type, count);
237 if (size < 0) {
238 dev_err(card->dev, "snd_ioctl32_ctl_elem_value: unknown type %d\n", type);
239 return -EINVAL;
240 }
241 if (copy_from_user(to: data->value.bytes.data, from: valuep, n: size))
242 return -EFAULT;
243 }
244
245 *typep = type;
246 *countp = count;
247 return 0;
248}
249
250/* restore the value to 32bit */
251static int copy_ctl_value_to_user(void __user *userdata,
252 void __user *valuep,
253 struct snd_ctl_elem_value *data,
254 int type, int count)
255{
256 struct snd_ctl_elem_value32 __user *data32 = userdata;
257 int i, size;
258
259 if (type == (__force int)SNDRV_CTL_ELEM_TYPE_BOOLEAN ||
260 type == (__force int)SNDRV_CTL_ELEM_TYPE_INTEGER) {
261 for (i = 0; i < count; i++) {
262 s32 __user *intp = valuep;
263 int val;
264 val = data->value.integer.value[i];
265 if (put_user(val, &intp[i]))
266 return -EFAULT;
267 }
268 } else {
269 size = get_elem_size(type: (__force snd_ctl_elem_type_t)type, count);
270 if (copy_to_user(to: valuep, from: data->value.bytes.data, n: size))
271 return -EFAULT;
272 }
273 if (copy_to_user(to: &data32->id, from: &data->id, n: sizeof(data32->id)))
274 return -EFAULT;
275 return 0;
276}
277
278static int ctl_elem_read_user(struct snd_card *card,
279 void __user *userdata, void __user *valuep)
280{
281 struct snd_ctl_elem_value *data __free(kfree) = NULL;
282 int err, type, count;
283
284 data = kzalloc(size: sizeof(*data), GFP_KERNEL);
285 if (data == NULL)
286 return -ENOMEM;
287
288 err = copy_ctl_value_from_user(card, data, userdata, valuep,
289 typep: &type, countp: &count);
290 if (err < 0)
291 return err;
292
293 err = snd_ctl_elem_read(card, control: data);
294 if (err < 0)
295 return err;
296 return copy_ctl_value_to_user(userdata, valuep, data, type, count);
297}
298
299static int ctl_elem_write_user(struct snd_ctl_file *file,
300 void __user *userdata, void __user *valuep)
301{
302 struct snd_ctl_elem_value *data __free(kfree) = NULL;
303 struct snd_card *card = file->card;
304 int err, type, count;
305
306 data = kzalloc(size: sizeof(*data), GFP_KERNEL);
307 if (data == NULL)
308 return -ENOMEM;
309
310 err = copy_ctl_value_from_user(card, data, userdata, valuep,
311 typep: &type, countp: &count);
312 if (err < 0)
313 return err;
314
315 err = snd_ctl_elem_write(card, file, control: data);
316 if (err < 0)
317 return err;
318 return copy_ctl_value_to_user(userdata, valuep, data, type, count);
319}
320
321static int snd_ctl_elem_read_user_compat(struct snd_card *card,
322 struct snd_ctl_elem_value32 __user *data32)
323{
324 return ctl_elem_read_user(card, userdata: data32, valuep: &data32->value);
325}
326
327static int snd_ctl_elem_write_user_compat(struct snd_ctl_file *file,
328 struct snd_ctl_elem_value32 __user *data32)
329{
330 return ctl_elem_write_user(file, userdata: data32, valuep: &data32->value);
331}
332
333#ifdef CONFIG_X86_X32_ABI
334static int snd_ctl_elem_read_user_x32(struct snd_card *card,
335 struct snd_ctl_elem_value_x32 __user *data32)
336{
337 return ctl_elem_read_user(card, userdata: data32, valuep: &data32->value);
338}
339
340static int snd_ctl_elem_write_user_x32(struct snd_ctl_file *file,
341 struct snd_ctl_elem_value_x32 __user *data32)
342{
343 return ctl_elem_write_user(file, userdata: data32, valuep: &data32->value);
344}
345#endif /* CONFIG_X86_X32_ABI */
346
347/* add or replace a user control */
348static int snd_ctl_elem_add_compat(struct snd_ctl_file *file,
349 struct snd_ctl_elem_info32 __user *data32,
350 int replace)
351{
352 struct snd_ctl_elem_info *data __free(kfree) = NULL;
353
354 data = kzalloc(size: sizeof(*data), GFP_KERNEL);
355 if (! data)
356 return -ENOMEM;
357
358 /* id, type, access, count */ \
359 if (copy_from_user(to: &data->id, from: &data32->id, n: sizeof(data->id)) ||
360 copy_from_user(to: &data->type, from: &data32->type, n: 3 * sizeof(u32)))
361 return -EFAULT;
362 if (get_user(data->owner, &data32->owner))
363 return -EFAULT;
364 switch (data->type) {
365 case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
366 case SNDRV_CTL_ELEM_TYPE_INTEGER:
367 if (get_user(data->value.integer.min, &data32->value.integer.min) ||
368 get_user(data->value.integer.max, &data32->value.integer.max) ||
369 get_user(data->value.integer.step, &data32->value.integer.step))
370 return -EFAULT;
371 break;
372 case SNDRV_CTL_ELEM_TYPE_INTEGER64:
373 if (copy_from_user(to: &data->value.integer64,
374 from: &data32->value.integer64,
375 n: sizeof(data->value.integer64)))
376 return -EFAULT;
377 break;
378 case SNDRV_CTL_ELEM_TYPE_ENUMERATED:
379 if (copy_from_user(to: &data->value.enumerated,
380 from: &data32->value.enumerated,
381 n: sizeof(data->value.enumerated)))
382 return -EFAULT;
383 data->value.enumerated.names_ptr =
384 (uintptr_t)compat_ptr(uptr: data->value.enumerated.names_ptr);
385 break;
386 default:
387 break;
388 }
389 return snd_ctl_elem_add(file, info: data, replace);
390}
391
392enum {
393 SNDRV_CTL_IOCTL_ELEM_LIST32 = _IOWR('U', 0x10, struct snd_ctl_elem_list32),
394 SNDRV_CTL_IOCTL_ELEM_INFO32 = _IOWR('U', 0x11, struct snd_ctl_elem_info32),
395 SNDRV_CTL_IOCTL_ELEM_READ32 = _IOWR('U', 0x12, struct snd_ctl_elem_value32),
396 SNDRV_CTL_IOCTL_ELEM_WRITE32 = _IOWR('U', 0x13, struct snd_ctl_elem_value32),
397 SNDRV_CTL_IOCTL_ELEM_ADD32 = _IOWR('U', 0x17, struct snd_ctl_elem_info32),
398 SNDRV_CTL_IOCTL_ELEM_REPLACE32 = _IOWR('U', 0x18, struct snd_ctl_elem_info32),
399#ifdef CONFIG_X86_X32_ABI
400 SNDRV_CTL_IOCTL_ELEM_READ_X32 = _IOWR('U', 0x12, struct snd_ctl_elem_value_x32),
401 SNDRV_CTL_IOCTL_ELEM_WRITE_X32 = _IOWR('U', 0x13, struct snd_ctl_elem_value_x32),
402#endif /* CONFIG_X86_X32_ABI */
403};
404
405static inline long snd_ctl_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg)
406{
407 struct snd_ctl_file *ctl;
408 struct snd_kctl_ioctl *p;
409 void __user *argp = compat_ptr(uptr: arg);
410 int err;
411
412 ctl = file->private_data;
413 if (snd_BUG_ON(!ctl || !ctl->card))
414 return -ENXIO;
415
416 switch (cmd) {
417 case SNDRV_CTL_IOCTL_PVERSION:
418 case SNDRV_CTL_IOCTL_CARD_INFO:
419 case SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS:
420 case SNDRV_CTL_IOCTL_POWER:
421 case SNDRV_CTL_IOCTL_POWER_STATE:
422 case SNDRV_CTL_IOCTL_ELEM_LOCK:
423 case SNDRV_CTL_IOCTL_ELEM_UNLOCK:
424 case SNDRV_CTL_IOCTL_ELEM_REMOVE:
425 case SNDRV_CTL_IOCTL_TLV_READ:
426 case SNDRV_CTL_IOCTL_TLV_WRITE:
427 case SNDRV_CTL_IOCTL_TLV_COMMAND:
428 return snd_ctl_ioctl(file, cmd, arg: (unsigned long)argp);
429 case SNDRV_CTL_IOCTL_ELEM_LIST32:
430 return snd_ctl_elem_list_compat(card: ctl->card, data32: argp);
431 case SNDRV_CTL_IOCTL_ELEM_INFO32:
432 return snd_ctl_elem_info_compat(ctl, data32: argp);
433 case SNDRV_CTL_IOCTL_ELEM_READ32:
434 return snd_ctl_elem_read_user_compat(card: ctl->card, data32: argp);
435 case SNDRV_CTL_IOCTL_ELEM_WRITE32:
436 return snd_ctl_elem_write_user_compat(file: ctl, data32: argp);
437 case SNDRV_CTL_IOCTL_ELEM_ADD32:
438 return snd_ctl_elem_add_compat(file: ctl, data32: argp, replace: 0);
439 case SNDRV_CTL_IOCTL_ELEM_REPLACE32:
440 return snd_ctl_elem_add_compat(file: ctl, data32: argp, replace: 1);
441#ifdef CONFIG_X86_X32_ABI
442 case SNDRV_CTL_IOCTL_ELEM_READ_X32:
443 return snd_ctl_elem_read_user_x32(card: ctl->card, data32: argp);
444 case SNDRV_CTL_IOCTL_ELEM_WRITE_X32:
445 return snd_ctl_elem_write_user_x32(file: ctl, data32: argp);
446#endif /* CONFIG_X86_X32_ABI */
447 }
448
449 guard(rwsem_read)(T: &snd_ioctl_rwsem);
450 list_for_each_entry(p, &snd_control_compat_ioctls, list) {
451 if (p->fioctl) {
452 err = p->fioctl(ctl->card, ctl, cmd, arg);
453 if (err != -ENOIOCTLCMD)
454 return err;
455 }
456 }
457 return -ENOIOCTLCMD;
458}
459

source code of linux/sound/core/control_compat.c