xref: /linux/sound/core/control_compat.c (revision 1e525507)
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 
13 struct 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 
22 static 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(&data, data32, 4 * sizeof(u32)))
31 		return -EFAULT;
32 	/* pids */
33 	if (get_user(ptr, &data32->pids))
34 		return -EFAULT;
35 	data.pids = compat_ptr(ptr);
36 	err = snd_ctl_elem_list(card, &data);
37 	if (err < 0)
38 		return err;
39 	/* copy the result */
40 	if (copy_to_user(data32, &data, 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 
50 struct 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 
79 static 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(sizeof(*data), GFP_KERNEL);
86 	if (! data)
87 		return -ENOMEM;
88 
89 	/* copy id */
90 	if (copy_from_user(&data->id, &data32->id, 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, data);
99 	if (err < 0)
100 		return err;
101 	/* restore info to 32bit */
102 	/* id, type, access, count */
103 	if (copy_to_user(&data32->id, &data->id, sizeof(data->id)) ||
104 	    copy_to_user(&data32->type, &data->type, 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(&data32->value.integer64,
118 				 &data->value.integer64,
119 				 sizeof(data->value.integer64)))
120 			return -EFAULT;
121 		break;
122 	case SNDRV_CTL_ELEM_TYPE_ENUMERATED:
123 		if (copy_to_user(&data32->value.enumerated,
124 				 &data->value.enumerated,
125 				 sizeof(data->value.enumerated)))
126 			return -EFAULT;
127 		break;
128 	default:
129 		break;
130 	}
131 	return 0;
132 }
133 
134 /* read / write */
135 struct 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 */
150 struct 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 */
163 static 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)(&card->controls_rwsem);
171 	kctl = snd_ctl_find_id_locked(card, id);
172 	if (!kctl)
173 		return -ENOENT;
174 	info = kzalloc(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 
189 static 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 
205 static 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(&data->id, &data32->id, 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, &data->id, &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((__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(data->value.bytes.data, valuep, size))
242 			return -EFAULT;
243 	}
244 
245 	*typep = type;
246 	*countp = count;
247 	return 0;
248 }
249 
250 /* restore the value to 32bit */
251 static 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((__force snd_ctl_elem_type_t)type, count);
270 		if (copy_to_user(valuep, data->value.bytes.data, size))
271 			return -EFAULT;
272 	}
273 	if (copy_to_user(&data32->id, &data->id, sizeof(data32->id)))
274 		return -EFAULT;
275 	return 0;
276 }
277 
278 static 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(sizeof(*data), GFP_KERNEL);
285 	if (data == NULL)
286 		return -ENOMEM;
287 
288 	err = copy_ctl_value_from_user(card, data, userdata, valuep,
289 				       &type, &count);
290 	if (err < 0)
291 		return err;
292 
293 	err = snd_ctl_elem_read(card, data);
294 	if (err < 0)
295 		return err;
296 	return copy_ctl_value_to_user(userdata, valuep, data, type, count);
297 }
298 
299 static 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(sizeof(*data), GFP_KERNEL);
307 	if (data == NULL)
308 		return -ENOMEM;
309 
310 	err = copy_ctl_value_from_user(card, data, userdata, valuep,
311 				       &type, &count);
312 	if (err < 0)
313 		return err;
314 
315 	err = snd_ctl_elem_write(card, file, data);
316 	if (err < 0)
317 		return err;
318 	return copy_ctl_value_to_user(userdata, valuep, data, type, count);
319 }
320 
321 static 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, data32, &data32->value);
325 }
326 
327 static 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, data32, &data32->value);
331 }
332 
333 #ifdef CONFIG_X86_X32_ABI
334 static 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, data32, &data32->value);
338 }
339 
340 static 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, data32, &data32->value);
344 }
345 #endif /* CONFIG_X86_X32_ABI */
346 
347 /* add or replace a user control */
348 static 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(sizeof(*data), GFP_KERNEL);
355 	if (! data)
356 		return -ENOMEM;
357 
358 	/* id, type, access, count */ \
359 	if (copy_from_user(&data->id, &data32->id, sizeof(data->id)) ||
360 	    copy_from_user(&data->type, &data32->type, 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(&data->value.integer64,
374 				   &data32->value.integer64,
375 				   sizeof(data->value.integer64)))
376 			return -EFAULT;
377 		break;
378 	case SNDRV_CTL_ELEM_TYPE_ENUMERATED:
379 		if (copy_from_user(&data->value.enumerated,
380 				   &data32->value.enumerated,
381 				   sizeof(data->value.enumerated)))
382 			return -EFAULT;
383 		data->value.enumerated.names_ptr =
384 			(uintptr_t)compat_ptr(data->value.enumerated.names_ptr);
385 		break;
386 	default:
387 		break;
388 	}
389 	return snd_ctl_elem_add(file, data, replace);
390 }
391 
392 enum {
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 
405 static 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(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, (unsigned long)argp);
429 	case SNDRV_CTL_IOCTL_ELEM_LIST32:
430 		return snd_ctl_elem_list_compat(ctl->card, argp);
431 	case SNDRV_CTL_IOCTL_ELEM_INFO32:
432 		return snd_ctl_elem_info_compat(ctl, argp);
433 	case SNDRV_CTL_IOCTL_ELEM_READ32:
434 		return snd_ctl_elem_read_user_compat(ctl->card, argp);
435 	case SNDRV_CTL_IOCTL_ELEM_WRITE32:
436 		return snd_ctl_elem_write_user_compat(ctl, argp);
437 	case SNDRV_CTL_IOCTL_ELEM_ADD32:
438 		return snd_ctl_elem_add_compat(ctl, argp, 0);
439 	case SNDRV_CTL_IOCTL_ELEM_REPLACE32:
440 		return snd_ctl_elem_add_compat(ctl, argp, 1);
441 #ifdef CONFIG_X86_X32_ABI
442 	case SNDRV_CTL_IOCTL_ELEM_READ_X32:
443 		return snd_ctl_elem_read_user_x32(ctl->card, argp);
444 	case SNDRV_CTL_IOCTL_ELEM_WRITE_X32:
445 		return snd_ctl_elem_write_user_x32(ctl, argp);
446 #endif /* CONFIG_X86_X32_ABI */
447 	}
448 
449 	guard(rwsem_read)(&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