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