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(&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 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} __attribute__((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; 83 int err; 84 85 data = kzalloc(sizeof(*data), GFP_KERNEL); 86 if (! data) 87 return -ENOMEM; 88 89 err = -EFAULT; 90 /* copy id */ 91 if (copy_from_user(&data->id, &data32->id, sizeof(data->id))) 92 goto error; 93 /* we need to copy the item index. 94 * hope this doesn't break anything.. 95 */ 96 if (get_user(data->value.enumerated.item, &data32->value.enumerated.item)) 97 goto error; 98 99 err = snd_power_wait(ctl->card, SNDRV_CTL_POWER_D0); 100 if (err < 0) 101 goto error; 102 err = snd_ctl_elem_info(ctl, data); 103 if (err < 0) 104 goto error; 105 /* restore info to 32bit */ 106 err = -EFAULT; 107 /* id, type, access, count */ 108 if (copy_to_user(&data32->id, &data->id, sizeof(data->id)) || 109 copy_to_user(&data32->type, &data->type, 3 * sizeof(u32))) 110 goto error; 111 if (put_user(data->owner, &data32->owner)) 112 goto error; 113 switch (data->type) { 114 case SNDRV_CTL_ELEM_TYPE_BOOLEAN: 115 case SNDRV_CTL_ELEM_TYPE_INTEGER: 116 if (put_user(data->value.integer.min, &data32->value.integer.min) || 117 put_user(data->value.integer.max, &data32->value.integer.max) || 118 put_user(data->value.integer.step, &data32->value.integer.step)) 119 goto error; 120 break; 121 case SNDRV_CTL_ELEM_TYPE_INTEGER64: 122 if (copy_to_user(&data32->value.integer64, 123 &data->value.integer64, 124 sizeof(data->value.integer64))) 125 goto error; 126 break; 127 case SNDRV_CTL_ELEM_TYPE_ENUMERATED: 128 if (copy_to_user(&data32->value.enumerated, 129 &data->value.enumerated, 130 sizeof(data->value.enumerated))) 131 goto error; 132 break; 133 default: 134 break; 135 } 136 err = 0; 137 error: 138 kfree(data); 139 return err; 140} 141 142/* read / write */ 143struct snd_ctl_elem_value32 { 144 struct snd_ctl_elem_id id; 145 unsigned int indirect; /* bit-field causes misalignment */ 146 union { 147 s32 integer[128]; 148 unsigned char data[512]; 149#ifndef CONFIG_X86_64 150 s64 integer64[64]; 151#endif 152 } value; 153 unsigned char reserved[128]; 154}; 155 156#ifdef CONFIG_X86_X32 157/* x32 has a different alignment for 64bit values from ia32 */ 158struct snd_ctl_elem_value_x32 { 159 struct snd_ctl_elem_id id; 160 unsigned int indirect; /* bit-field causes misalignment */ 161 union { 162 s32 integer[128]; 163 unsigned char data[512]; 164 s64 integer64[64]; 165 } value; 166 unsigned char reserved[128]; 167}; 168#endif /* CONFIG_X86_X32 */ 169 170/* get the value type and count of the control */ 171static int get_ctl_type(struct snd_card *card, struct snd_ctl_elem_id *id, 172 int *countp) 173{ 174 struct snd_kcontrol *kctl; 175 struct snd_ctl_elem_info *info; 176 int err; 177 178 down_read(&card->controls_rwsem); 179 kctl = snd_ctl_find_id(card, id); 180 if (! kctl) { 181 up_read(&card->controls_rwsem); 182 return -ENOENT; 183 } 184 info = kzalloc(sizeof(*info), GFP_KERNEL); 185 if (info == NULL) { 186 up_read(&card->controls_rwsem); 187 return -ENOMEM; 188 } 189 info->id = *id; 190 err = kctl->info(kctl, info); 191 up_read(&card->controls_rwsem); 192 if (err >= 0) { 193 err = info->type; 194 *countp = info->count; 195 } 196 kfree(info); 197 return err; 198} 199 200static int get_elem_size(int type, int count) 201{ 202 switch (type) { 203 case SNDRV_CTL_ELEM_TYPE_INTEGER64: 204 return sizeof(s64) * count; 205 case SNDRV_CTL_ELEM_TYPE_ENUMERATED: 206 return sizeof(int) * count; 207 case SNDRV_CTL_ELEM_TYPE_BYTES: 208 return 512; 209 case SNDRV_CTL_ELEM_TYPE_IEC958: 210 return sizeof(struct snd_aes_iec958); 211 default: 212 return -1; 213 } 214} 215 216static int copy_ctl_value_from_user(struct snd_card *card, 217 struct snd_ctl_elem_value *data, 218 void __user *userdata, 219 void __user *valuep, 220 int *typep, int *countp) 221{ 222 struct snd_ctl_elem_value32 __user *data32 = userdata; 223 int i, type, size; 224 int count; 225 unsigned int indirect; 226 227 if (copy_from_user(&data->id, &data32->id, sizeof(data->id))) 228 return -EFAULT; 229 if (get_user(indirect, &data32->indirect)) 230 return -EFAULT; 231 if (indirect) 232 return -EINVAL; 233 type = get_ctl_type(card, &data->id, &count); 234 if (type < 0) 235 return type; 236 237 if (type == SNDRV_CTL_ELEM_TYPE_BOOLEAN || 238 type == SNDRV_CTL_ELEM_TYPE_INTEGER) { 239 for (i = 0; i < count; i++) { 240 s32 __user *intp = valuep; 241 int val; 242 if (get_user(val, &intp[i])) 243 return -EFAULT; 244 data->value.integer.value[i] = val; 245 } 246 } else { 247 size = get_elem_size(type, count); 248 if (size < 0) { 249 dev_err(card->dev, "snd_ioctl32_ctl_elem_value: unknown type %d\n", type); 250 return -EINVAL; 251 } 252 if (copy_from_user(data->value.bytes.data, valuep, size)) 253 return -EFAULT; 254 } 255 256 *typep = type; 257 *countp = count; 258 return 0; 259} 260 261/* restore the value to 32bit */ 262static int copy_ctl_value_to_user(void __user *userdata, 263 void __user *valuep, 264 struct snd_ctl_elem_value *data, 265 int type, int count) 266{ 267 struct snd_ctl_elem_value32 __user *data32 = userdata; 268 int i, size; 269 270 if (type == SNDRV_CTL_ELEM_TYPE_BOOLEAN || 271 type == SNDRV_CTL_ELEM_TYPE_INTEGER) { 272 for (i = 0; i < count; i++) { 273 s32 __user *intp = valuep; 274 int val; 275 val = data->value.integer.value[i]; 276 if (put_user(val, &intp[i])) 277 return -EFAULT; 278 } 279 } else { 280 size = get_elem_size(type, count); 281 if (copy_to_user(valuep, data->value.bytes.data, size)) 282 return -EFAULT; 283 } 284 if (copy_to_user(&data32->id, &data->id, sizeof(data32->id))) 285 return -EFAULT; 286 return 0; 287} 288 289static int ctl_elem_read_user(struct snd_card *card, 290 void __user *userdata, void __user *valuep) 291{ 292 struct snd_ctl_elem_value *data; 293 int err, type, count; 294 295 data = kzalloc(sizeof(*data), GFP_KERNEL); 296 if (data == NULL) 297 return -ENOMEM; 298 299 err = copy_ctl_value_from_user(card, data, userdata, valuep, 300 &type, &count); 301 if (err < 0) 302 goto error; 303 304 err = snd_power_wait(card, SNDRV_CTL_POWER_D0); 305 if (err < 0) 306 goto error; 307 down_read(&card->controls_rwsem); 308 err = snd_ctl_elem_read(card, data); 309 up_read(&card->controls_rwsem); 310 if (err < 0) 311 goto error; 312 err = copy_ctl_value_to_user(userdata, valuep, data, type, count); 313 error: 314 kfree(data); 315 return err; 316} 317 318static int ctl_elem_write_user(struct snd_ctl_file *file, 319 void __user *userdata, void __user *valuep) 320{ 321 struct snd_ctl_elem_value *data; 322 struct snd_card *card = file->card; 323 int err, type, count; 324 325 data = kzalloc(sizeof(*data), GFP_KERNEL); 326 if (data == NULL) 327 return -ENOMEM; 328 329 err = copy_ctl_value_from_user(card, data, userdata, valuep, 330 &type, &count); 331 if (err < 0) 332 goto error; 333 334 err = snd_power_wait(card, SNDRV_CTL_POWER_D0); 335 if (err < 0) 336 goto error; 337 down_write(&card->controls_rwsem); 338 err = snd_ctl_elem_write(card, file, data); 339 up_write(&card->controls_rwsem); 340 if (err < 0) 341 goto error; 342 err = copy_ctl_value_to_user(userdata, valuep, data, type, count); 343 error: 344 kfree(data); 345 return err; 346} 347 348static int snd_ctl_elem_read_user_compat(struct snd_card *card, 349 struct snd_ctl_elem_value32 __user *data32) 350{ 351 return ctl_elem_read_user(card, data32, &data32->value); 352} 353 354static int snd_ctl_elem_write_user_compat(struct snd_ctl_file *file, 355 struct snd_ctl_elem_value32 __user *data32) 356{ 357 return ctl_elem_write_user(file, data32, &data32->value); 358} 359 360#ifdef CONFIG_X86_X32 361static int snd_ctl_elem_read_user_x32(struct snd_card *card, 362 struct snd_ctl_elem_value_x32 __user *data32) 363{ 364 return ctl_elem_read_user(card, data32, &data32->value); 365} 366 367static int snd_ctl_elem_write_user_x32(struct snd_ctl_file *file, 368 struct snd_ctl_elem_value_x32 __user *data32) 369{ 370 return ctl_elem_write_user(file, data32, &data32->value); 371} 372#endif /* CONFIG_X86_X32 */ 373 374/* add or replace a user control */ 375static int snd_ctl_elem_add_compat(struct snd_ctl_file *file, 376 struct snd_ctl_elem_info32 __user *data32, 377 int replace) 378{ 379 struct snd_ctl_elem_info *data; 380 int err; 381 382 data = kzalloc(sizeof(*data), GFP_KERNEL); 383 if (! data) 384 return -ENOMEM; 385 386 err = -EFAULT; 387 /* id, type, access, count */ \ 388 if (copy_from_user(&data->id, &data32->id, sizeof(data->id)) || 389 copy_from_user(&data->type, &data32->type, 3 * sizeof(u32))) 390 goto error; 391 if (get_user(data->owner, &data32->owner)) 392 goto error; 393 switch (data->type) { 394 case SNDRV_CTL_ELEM_TYPE_BOOLEAN: 395 case SNDRV_CTL_ELEM_TYPE_INTEGER: 396 if (get_user(data->value.integer.min, &data32->value.integer.min) || 397 get_user(data->value.integer.max, &data32->value.integer.max) || 398 get_user(data->value.integer.step, &data32->value.integer.step)) 399 goto error; 400 break; 401 case SNDRV_CTL_ELEM_TYPE_INTEGER64: 402 if (copy_from_user(&data->value.integer64, 403 &data32->value.integer64, 404 sizeof(data->value.integer64))) 405 goto error; 406 break; 407 case SNDRV_CTL_ELEM_TYPE_ENUMERATED: 408 if (copy_from_user(&data->value.enumerated, 409 &data32->value.enumerated, 410 sizeof(data->value.enumerated))) 411 goto error; 412 data->value.enumerated.names_ptr = 413 (uintptr_t)compat_ptr(data->value.enumerated.names_ptr); 414 break; 415 default: 416 break; 417 } 418 err = snd_ctl_elem_add(file, data, replace); 419 error: 420 kfree(data); 421 return err; 422} 423 424enum { 425 SNDRV_CTL_IOCTL_ELEM_LIST32 = _IOWR('U', 0x10, struct snd_ctl_elem_list32), 426 SNDRV_CTL_IOCTL_ELEM_INFO32 = _IOWR('U', 0x11, struct snd_ctl_elem_info32), 427 SNDRV_CTL_IOCTL_ELEM_READ32 = _IOWR('U', 0x12, struct snd_ctl_elem_value32), 428 SNDRV_CTL_IOCTL_ELEM_WRITE32 = _IOWR('U', 0x13, struct snd_ctl_elem_value32), 429 SNDRV_CTL_IOCTL_ELEM_ADD32 = _IOWR('U', 0x17, struct snd_ctl_elem_info32), 430 SNDRV_CTL_IOCTL_ELEM_REPLACE32 = _IOWR('U', 0x18, struct snd_ctl_elem_info32), 431#ifdef CONFIG_X86_X32 432 SNDRV_CTL_IOCTL_ELEM_READ_X32 = _IOWR('U', 0x12, struct snd_ctl_elem_value_x32), 433 SNDRV_CTL_IOCTL_ELEM_WRITE_X32 = _IOWR('U', 0x13, struct snd_ctl_elem_value_x32), 434#endif /* CONFIG_X86_X32 */ 435}; 436 437static inline long snd_ctl_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg) 438{ 439 struct snd_ctl_file *ctl; 440 struct snd_kctl_ioctl *p; 441 void __user *argp = compat_ptr(arg); 442 int err; 443 444 ctl = file->private_data; 445 if (snd_BUG_ON(!ctl || !ctl->card)) 446 return -ENXIO; 447 448 switch (cmd) { 449 case SNDRV_CTL_IOCTL_PVERSION: 450 case SNDRV_CTL_IOCTL_CARD_INFO: 451 case SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS: 452 case SNDRV_CTL_IOCTL_POWER: 453 case SNDRV_CTL_IOCTL_POWER_STATE: 454 case SNDRV_CTL_IOCTL_ELEM_LOCK: 455 case SNDRV_CTL_IOCTL_ELEM_UNLOCK: 456 case SNDRV_CTL_IOCTL_ELEM_REMOVE: 457 case SNDRV_CTL_IOCTL_TLV_READ: 458 case SNDRV_CTL_IOCTL_TLV_WRITE: 459 case SNDRV_CTL_IOCTL_TLV_COMMAND: 460 return snd_ctl_ioctl(file, cmd, (unsigned long)argp); 461 case SNDRV_CTL_IOCTL_ELEM_LIST32: 462 return snd_ctl_elem_list_compat(ctl->card, argp); 463 case SNDRV_CTL_IOCTL_ELEM_INFO32: 464 return snd_ctl_elem_info_compat(ctl, argp); 465 case SNDRV_CTL_IOCTL_ELEM_READ32: 466 return snd_ctl_elem_read_user_compat(ctl->card, argp); 467 case SNDRV_CTL_IOCTL_ELEM_WRITE32: 468 return snd_ctl_elem_write_user_compat(ctl, argp); 469 case SNDRV_CTL_IOCTL_ELEM_ADD32: 470 return snd_ctl_elem_add_compat(ctl, argp, 0); 471 case SNDRV_CTL_IOCTL_ELEM_REPLACE32: 472 return snd_ctl_elem_add_compat(ctl, argp, 1); 473#ifdef CONFIG_X86_X32 474 case SNDRV_CTL_IOCTL_ELEM_READ_X32: 475 return snd_ctl_elem_read_user_x32(ctl->card, argp); 476 case SNDRV_CTL_IOCTL_ELEM_WRITE_X32: 477 return snd_ctl_elem_write_user_x32(ctl, argp); 478#endif /* CONFIG_X86_X32 */ 479 } 480 481 down_read(&snd_ioctl_rwsem); 482 list_for_each_entry(p, &snd_control_compat_ioctls, list) { 483 if (p->fioctl) { 484 err = p->fioctl(ctl->card, ctl, cmd, arg); 485 if (err != -ENOIOCTLCMD) { 486 up_read(&snd_ioctl_rwsem); 487 return err; 488 } 489 } 490 } 491 up_read(&snd_ioctl_rwsem); 492 return -ENOIOCTLCMD; 493} 494