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