Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * compat ioctls for control API
0004  *
0005  *   Copyright (c) by Takashi Iwai <tiwai@suse.de>
0006  */
0007 
0008 /* this file included from control.c */
0009 
0010 #include <linux/compat.h>
0011 #include <linux/slab.h>
0012 
0013 struct snd_ctl_elem_list32 {
0014     u32 offset;
0015     u32 space;
0016     u32 used;
0017     u32 count;
0018     u32 pids;
0019     unsigned char reserved[50];
0020 } /* don't set packed attribute here */;
0021 
0022 static int snd_ctl_elem_list_compat(struct snd_card *card,
0023                     struct snd_ctl_elem_list32 __user *data32)
0024 {
0025     struct snd_ctl_elem_list data = {};
0026     compat_caddr_t ptr;
0027     int err;
0028 
0029     /* offset, space, used, count */
0030     if (copy_from_user(&data, data32, 4 * sizeof(u32)))
0031         return -EFAULT;
0032     /* pids */
0033     if (get_user(ptr, &data32->pids))
0034         return -EFAULT;
0035     data.pids = compat_ptr(ptr);
0036     err = snd_ctl_elem_list(card, &data);
0037     if (err < 0)
0038         return err;
0039     /* copy the result */
0040     if (copy_to_user(data32, &data, 4 * sizeof(u32)))
0041         return -EFAULT;
0042     return 0;
0043 }
0044 
0045 /*
0046  * control element info
0047  * it uses union, so the things are not easy..
0048  */
0049 
0050 struct snd_ctl_elem_info32 {
0051     struct snd_ctl_elem_id id; // the size of struct is same
0052     s32 type;
0053     u32 access;
0054     u32 count;
0055     s32 owner;
0056     union {
0057         struct {
0058             s32 min;
0059             s32 max;
0060             s32 step;
0061         } integer;
0062         struct {
0063             u64 min;
0064             u64 max;
0065             u64 step;
0066         } integer64;
0067         struct {
0068             u32 items;
0069             u32 item;
0070             char name[64];
0071             u64 names_ptr;
0072             u32 names_length;
0073         } enumerated;
0074         unsigned char reserved[128];
0075     } value;
0076     unsigned char reserved[64];
0077 } __attribute__((packed));
0078 
0079 static int snd_ctl_elem_info_compat(struct snd_ctl_file *ctl,
0080                     struct snd_ctl_elem_info32 __user *data32)
0081 {
0082     struct snd_ctl_elem_info *data;
0083     int err;
0084 
0085     data = kzalloc(sizeof(*data), GFP_KERNEL);
0086     if (! data)
0087         return -ENOMEM;
0088 
0089     err = -EFAULT;
0090     /* copy id */
0091     if (copy_from_user(&data->id, &data32->id, sizeof(data->id)))
0092         goto error;
0093     /* we need to copy the item index.
0094      * hope this doesn't break anything..
0095      */
0096     if (get_user(data->value.enumerated.item, &data32->value.enumerated.item))
0097         goto error;
0098 
0099     err = snd_ctl_elem_info(ctl, data);
0100     if (err < 0)
0101         goto error;
0102     /* restore info to 32bit */
0103     err = -EFAULT;
0104     /* id, type, access, count */
0105     if (copy_to_user(&data32->id, &data->id, sizeof(data->id)) ||
0106         copy_to_user(&data32->type, &data->type, 3 * sizeof(u32)))
0107         goto error;
0108     if (put_user(data->owner, &data32->owner))
0109         goto error;
0110     switch (data->type) {
0111     case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
0112     case SNDRV_CTL_ELEM_TYPE_INTEGER:
0113         if (put_user(data->value.integer.min, &data32->value.integer.min) ||
0114             put_user(data->value.integer.max, &data32->value.integer.max) ||
0115             put_user(data->value.integer.step, &data32->value.integer.step))
0116             goto error;
0117         break;
0118     case SNDRV_CTL_ELEM_TYPE_INTEGER64:
0119         if (copy_to_user(&data32->value.integer64,
0120                  &data->value.integer64,
0121                  sizeof(data->value.integer64)))
0122             goto error;
0123         break;
0124     case SNDRV_CTL_ELEM_TYPE_ENUMERATED:
0125         if (copy_to_user(&data32->value.enumerated,
0126                  &data->value.enumerated,
0127                  sizeof(data->value.enumerated)))
0128             goto error;
0129         break;
0130     default:
0131         break;
0132     }
0133     err = 0;
0134  error:
0135     kfree(data);
0136     return err;
0137 }
0138 
0139 /* read / write */
0140 struct snd_ctl_elem_value32 {
0141     struct snd_ctl_elem_id id;
0142     unsigned int indirect;  /* bit-field causes misalignment */
0143         union {
0144         s32 integer[128];
0145         unsigned char data[512];
0146 #ifndef CONFIG_X86_64
0147         s64 integer64[64];
0148 #endif
0149         } value;
0150         unsigned char reserved[128];
0151 };
0152 
0153 #ifdef CONFIG_X86_X32_ABI
0154 /* x32 has a different alignment for 64bit values from ia32 */
0155 struct snd_ctl_elem_value_x32 {
0156     struct snd_ctl_elem_id id;
0157     unsigned int indirect;  /* bit-field causes misalignment */
0158     union {
0159         s32 integer[128];
0160         unsigned char data[512];
0161         s64 integer64[64];
0162     } value;
0163     unsigned char reserved[128];
0164 };
0165 #endif /* CONFIG_X86_X32_ABI */
0166 
0167 /* get the value type and count of the control */
0168 static int get_ctl_type(struct snd_card *card, struct snd_ctl_elem_id *id,
0169             int *countp)
0170 {
0171     struct snd_kcontrol *kctl;
0172     struct snd_ctl_elem_info *info;
0173     int err;
0174 
0175     down_read(&card->controls_rwsem);
0176     kctl = snd_ctl_find_id(card, id);
0177     if (! kctl) {
0178         up_read(&card->controls_rwsem);
0179         return -ENOENT;
0180     }
0181     info = kzalloc(sizeof(*info), GFP_KERNEL);
0182     if (info == NULL) {
0183         up_read(&card->controls_rwsem);
0184         return -ENOMEM;
0185     }
0186     info->id = *id;
0187     err = snd_power_ref_and_wait(card);
0188     if (!err)
0189         err = kctl->info(kctl, info);
0190     snd_power_unref(card);
0191     up_read(&card->controls_rwsem);
0192     if (err >= 0) {
0193         err = info->type;
0194         *countp = info->count;
0195     }
0196     kfree(info);
0197     return err;
0198 }
0199 
0200 static int get_elem_size(int type, int count)
0201 {
0202     switch (type) {
0203     case SNDRV_CTL_ELEM_TYPE_INTEGER64:
0204         return sizeof(s64) * count;
0205     case SNDRV_CTL_ELEM_TYPE_ENUMERATED:
0206         return sizeof(int) * count;
0207     case SNDRV_CTL_ELEM_TYPE_BYTES:
0208         return 512;
0209     case SNDRV_CTL_ELEM_TYPE_IEC958:
0210         return sizeof(struct snd_aes_iec958);
0211     default:
0212         return -1;
0213     }
0214 }
0215 
0216 static int copy_ctl_value_from_user(struct snd_card *card,
0217                     struct snd_ctl_elem_value *data,
0218                     void __user *userdata,
0219                     void __user *valuep,
0220                     int *typep, int *countp)
0221 {
0222     struct snd_ctl_elem_value32 __user *data32 = userdata;
0223     int i, type, size;
0224     int count;
0225     unsigned int indirect;
0226 
0227     if (copy_from_user(&data->id, &data32->id, sizeof(data->id)))
0228         return -EFAULT;
0229     if (get_user(indirect, &data32->indirect))
0230         return -EFAULT;
0231     if (indirect)
0232         return -EINVAL;
0233     type = get_ctl_type(card, &data->id, &count);
0234     if (type < 0)
0235         return type;
0236 
0237     if (type == SNDRV_CTL_ELEM_TYPE_BOOLEAN ||
0238         type == SNDRV_CTL_ELEM_TYPE_INTEGER) {
0239         for (i = 0; i < count; i++) {
0240             s32 __user *intp = valuep;
0241             int val;
0242             if (get_user(val, &intp[i]))
0243                 return -EFAULT;
0244             data->value.integer.value[i] = val;
0245         }
0246     } else {
0247         size = get_elem_size(type, count);
0248         if (size < 0) {
0249             dev_err(card->dev, "snd_ioctl32_ctl_elem_value: unknown type %d\n", type);
0250             return -EINVAL;
0251         }
0252         if (copy_from_user(data->value.bytes.data, valuep, size))
0253             return -EFAULT;
0254     }
0255 
0256     *typep = type;
0257     *countp = count;
0258     return 0;
0259 }
0260 
0261 /* restore the value to 32bit */
0262 static int copy_ctl_value_to_user(void __user *userdata,
0263                   void __user *valuep,
0264                   struct snd_ctl_elem_value *data,
0265                   int type, int count)
0266 {
0267     struct snd_ctl_elem_value32 __user *data32 = userdata;
0268     int i, size;
0269 
0270     if (type == SNDRV_CTL_ELEM_TYPE_BOOLEAN ||
0271         type == SNDRV_CTL_ELEM_TYPE_INTEGER) {
0272         for (i = 0; i < count; i++) {
0273             s32 __user *intp = valuep;
0274             int val;
0275             val = data->value.integer.value[i];
0276             if (put_user(val, &intp[i]))
0277                 return -EFAULT;
0278         }
0279     } else {
0280         size = get_elem_size(type, count);
0281         if (copy_to_user(valuep, data->value.bytes.data, size))
0282             return -EFAULT;
0283     }
0284     if (copy_to_user(&data32->id, &data->id, sizeof(data32->id)))
0285         return -EFAULT;
0286     return 0;
0287 }
0288 
0289 static int ctl_elem_read_user(struct snd_card *card,
0290                   void __user *userdata, void __user *valuep)
0291 {
0292     struct snd_ctl_elem_value *data;
0293     int err, type, count;
0294 
0295     data = kzalloc(sizeof(*data), GFP_KERNEL);
0296     if (data == NULL)
0297         return -ENOMEM;
0298 
0299     err = copy_ctl_value_from_user(card, data, userdata, valuep,
0300                        &type, &count);
0301     if (err < 0)
0302         goto error;
0303 
0304     err = snd_ctl_elem_read(card, data);
0305     if (err < 0)
0306         goto error;
0307     err = copy_ctl_value_to_user(userdata, valuep, data, type, count);
0308  error:
0309     kfree(data);
0310     return err;
0311 }
0312 
0313 static int ctl_elem_write_user(struct snd_ctl_file *file,
0314                    void __user *userdata, void __user *valuep)
0315 {
0316     struct snd_ctl_elem_value *data;
0317     struct snd_card *card = file->card;
0318     int err, type, count;
0319 
0320     data = kzalloc(sizeof(*data), GFP_KERNEL);
0321     if (data == NULL)
0322         return -ENOMEM;
0323 
0324     err = copy_ctl_value_from_user(card, data, userdata, valuep,
0325                        &type, &count);
0326     if (err < 0)
0327         goto error;
0328 
0329     err = snd_ctl_elem_write(card, file, data);
0330     if (err < 0)
0331         goto error;
0332     err = copy_ctl_value_to_user(userdata, valuep, data, type, count);
0333  error:
0334     kfree(data);
0335     return err;
0336 }
0337 
0338 static int snd_ctl_elem_read_user_compat(struct snd_card *card,
0339                      struct snd_ctl_elem_value32 __user *data32)
0340 {
0341     return ctl_elem_read_user(card, data32, &data32->value);
0342 }
0343 
0344 static int snd_ctl_elem_write_user_compat(struct snd_ctl_file *file,
0345                       struct snd_ctl_elem_value32 __user *data32)
0346 {
0347     return ctl_elem_write_user(file, data32, &data32->value);
0348 }
0349 
0350 #ifdef CONFIG_X86_X32_ABI
0351 static int snd_ctl_elem_read_user_x32(struct snd_card *card,
0352                       struct snd_ctl_elem_value_x32 __user *data32)
0353 {
0354     return ctl_elem_read_user(card, data32, &data32->value);
0355 }
0356 
0357 static int snd_ctl_elem_write_user_x32(struct snd_ctl_file *file,
0358                        struct snd_ctl_elem_value_x32 __user *data32)
0359 {
0360     return ctl_elem_write_user(file, data32, &data32->value);
0361 }
0362 #endif /* CONFIG_X86_X32_ABI */
0363 
0364 /* add or replace a user control */
0365 static int snd_ctl_elem_add_compat(struct snd_ctl_file *file,
0366                    struct snd_ctl_elem_info32 __user *data32,
0367                    int replace)
0368 {
0369     struct snd_ctl_elem_info *data;
0370     int err;
0371 
0372     data = kzalloc(sizeof(*data), GFP_KERNEL);
0373     if (! data)
0374         return -ENOMEM;
0375 
0376     err = -EFAULT;
0377     /* id, type, access, count */ \
0378     if (copy_from_user(&data->id, &data32->id, sizeof(data->id)) ||
0379         copy_from_user(&data->type, &data32->type, 3 * sizeof(u32)))
0380         goto error;
0381     if (get_user(data->owner, &data32->owner))
0382         goto error;
0383     switch (data->type) {
0384     case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
0385     case SNDRV_CTL_ELEM_TYPE_INTEGER:
0386         if (get_user(data->value.integer.min, &data32->value.integer.min) ||
0387             get_user(data->value.integer.max, &data32->value.integer.max) ||
0388             get_user(data->value.integer.step, &data32->value.integer.step))
0389             goto error;
0390         break;
0391     case SNDRV_CTL_ELEM_TYPE_INTEGER64:
0392         if (copy_from_user(&data->value.integer64,
0393                    &data32->value.integer64,
0394                    sizeof(data->value.integer64)))
0395             goto error;
0396         break;
0397     case SNDRV_CTL_ELEM_TYPE_ENUMERATED:
0398         if (copy_from_user(&data->value.enumerated,
0399                    &data32->value.enumerated,
0400                    sizeof(data->value.enumerated)))
0401             goto error;
0402         data->value.enumerated.names_ptr =
0403             (uintptr_t)compat_ptr(data->value.enumerated.names_ptr);
0404         break;
0405     default:
0406         break;
0407     }
0408     err = snd_ctl_elem_add(file, data, replace);
0409  error:
0410     kfree(data);
0411     return err;
0412 }  
0413 
0414 enum {
0415     SNDRV_CTL_IOCTL_ELEM_LIST32 = _IOWR('U', 0x10, struct snd_ctl_elem_list32),
0416     SNDRV_CTL_IOCTL_ELEM_INFO32 = _IOWR('U', 0x11, struct snd_ctl_elem_info32),
0417     SNDRV_CTL_IOCTL_ELEM_READ32 = _IOWR('U', 0x12, struct snd_ctl_elem_value32),
0418     SNDRV_CTL_IOCTL_ELEM_WRITE32 = _IOWR('U', 0x13, struct snd_ctl_elem_value32),
0419     SNDRV_CTL_IOCTL_ELEM_ADD32 = _IOWR('U', 0x17, struct snd_ctl_elem_info32),
0420     SNDRV_CTL_IOCTL_ELEM_REPLACE32 = _IOWR('U', 0x18, struct snd_ctl_elem_info32),
0421 #ifdef CONFIG_X86_X32_ABI
0422     SNDRV_CTL_IOCTL_ELEM_READ_X32 = _IOWR('U', 0x12, struct snd_ctl_elem_value_x32),
0423     SNDRV_CTL_IOCTL_ELEM_WRITE_X32 = _IOWR('U', 0x13, struct snd_ctl_elem_value_x32),
0424 #endif /* CONFIG_X86_X32_ABI */
0425 };
0426 
0427 static inline long snd_ctl_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg)
0428 {
0429     struct snd_ctl_file *ctl;
0430     struct snd_kctl_ioctl *p;
0431     void __user *argp = compat_ptr(arg);
0432     int err;
0433 
0434     ctl = file->private_data;
0435     if (snd_BUG_ON(!ctl || !ctl->card))
0436         return -ENXIO;
0437 
0438     switch (cmd) {
0439     case SNDRV_CTL_IOCTL_PVERSION:
0440     case SNDRV_CTL_IOCTL_CARD_INFO:
0441     case SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS:
0442     case SNDRV_CTL_IOCTL_POWER:
0443     case SNDRV_CTL_IOCTL_POWER_STATE:
0444     case SNDRV_CTL_IOCTL_ELEM_LOCK:
0445     case SNDRV_CTL_IOCTL_ELEM_UNLOCK:
0446     case SNDRV_CTL_IOCTL_ELEM_REMOVE:
0447     case SNDRV_CTL_IOCTL_TLV_READ:
0448     case SNDRV_CTL_IOCTL_TLV_WRITE:
0449     case SNDRV_CTL_IOCTL_TLV_COMMAND:
0450         return snd_ctl_ioctl(file, cmd, (unsigned long)argp);
0451     case SNDRV_CTL_IOCTL_ELEM_LIST32:
0452         return snd_ctl_elem_list_compat(ctl->card, argp);
0453     case SNDRV_CTL_IOCTL_ELEM_INFO32:
0454         return snd_ctl_elem_info_compat(ctl, argp);
0455     case SNDRV_CTL_IOCTL_ELEM_READ32:
0456         return snd_ctl_elem_read_user_compat(ctl->card, argp);
0457     case SNDRV_CTL_IOCTL_ELEM_WRITE32:
0458         return snd_ctl_elem_write_user_compat(ctl, argp);
0459     case SNDRV_CTL_IOCTL_ELEM_ADD32:
0460         return snd_ctl_elem_add_compat(ctl, argp, 0);
0461     case SNDRV_CTL_IOCTL_ELEM_REPLACE32:
0462         return snd_ctl_elem_add_compat(ctl, argp, 1);
0463 #ifdef CONFIG_X86_X32_ABI
0464     case SNDRV_CTL_IOCTL_ELEM_READ_X32:
0465         return snd_ctl_elem_read_user_x32(ctl->card, argp);
0466     case SNDRV_CTL_IOCTL_ELEM_WRITE_X32:
0467         return snd_ctl_elem_write_user_x32(ctl, argp);
0468 #endif /* CONFIG_X86_X32_ABI */
0469     }
0470 
0471     down_read(&snd_ioctl_rwsem);
0472     list_for_each_entry(p, &snd_control_compat_ioctls, list) {
0473         if (p->fioctl) {
0474             err = p->fioctl(ctl->card, ctl, cmd, arg);
0475             if (err != -ENOIOCTLCMD) {
0476                 up_read(&snd_ioctl_rwsem);
0477                 return err;
0478             }
0479         }
0480     }
0481     up_read(&snd_ioctl_rwsem);
0482     return -ENOIOCTLCMD;
0483 }