0001
0002
0003
0004
0005
0006
0007
0008
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 } ;
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
0030 if (copy_from_user(&data, data32, 4 * sizeof(u32)))
0031 return -EFAULT;
0032
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
0040 if (copy_to_user(data32, &data, 4 * sizeof(u32)))
0041 return -EFAULT;
0042 return 0;
0043 }
0044
0045
0046
0047
0048
0049
0050 struct snd_ctl_elem_info32 {
0051 struct snd_ctl_elem_id id;
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
0091 if (copy_from_user(&data->id, &data32->id, sizeof(data->id)))
0092 goto error;
0093
0094
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
0103 err = -EFAULT;
0104
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
0140 struct snd_ctl_elem_value32 {
0141 struct snd_ctl_elem_id id;
0142 unsigned int indirect;
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
0155 struct snd_ctl_elem_value_x32 {
0156 struct snd_ctl_elem_id id;
0157 unsigned int indirect;
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
0166
0167
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
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
0363
0364
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 \
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
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
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 }