root/sound/core/control_compat.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. snd_ctl_elem_list_compat
  2. snd_ctl_elem_info_compat
  3. get_ctl_type
  4. get_elem_size
  5. copy_ctl_value_from_user
  6. copy_ctl_value_to_user
  7. ctl_elem_read_user
  8. ctl_elem_write_user
  9. snd_ctl_elem_read_user_compat
  10. snd_ctl_elem_write_user_compat
  11. snd_ctl_elem_read_user_x32
  12. snd_ctl_elem_write_user_x32
  13. snd_ctl_elem_add_compat
  14. snd_ctl_ioctl_compat

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

/* [<][>][^][v][top][bottom][index][help] */