Commit 18d122c0 authored by Arnd Bergmann's avatar Arnd Bergmann Committed by Takashi Iwai

ALSA: compat_ioctl: avoid compat_alloc_user_space

Using compat_alloc_user_space() tends to add complexity
to the ioctl handling, so I am trying to remove it everywhere.

The two callers in sound/core can rewritten to just call
the same code that operates on a kernel pointer as the
native handler.
Signed-off-by: default avatarArnd Bergmann <arnd@arndb.de>
Link: https://lore.kernel.org/r/20200918095642.1446243-1-arnd@arndb.deSigned-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent 2b987515
...@@ -717,22 +717,19 @@ static int snd_ctl_card_info(struct snd_card *card, struct snd_ctl_file * ctl, ...@@ -717,22 +717,19 @@ static int snd_ctl_card_info(struct snd_card *card, struct snd_ctl_file * ctl,
} }
static int snd_ctl_elem_list(struct snd_card *card, static int snd_ctl_elem_list(struct snd_card *card,
struct snd_ctl_elem_list __user *_list) struct snd_ctl_elem_list *list)
{ {
struct snd_ctl_elem_list list;
struct snd_kcontrol *kctl; struct snd_kcontrol *kctl;
struct snd_ctl_elem_id id; struct snd_ctl_elem_id id;
unsigned int offset, space, jidx; unsigned int offset, space, jidx;
int err = 0; int err = 0;
if (copy_from_user(&list, _list, sizeof(list))) offset = list->offset;
return -EFAULT; space = list->space;
offset = list.offset;
space = list.space;
down_read(&card->controls_rwsem); down_read(&card->controls_rwsem);
list.count = card->controls_count; list->count = card->controls_count;
list.used = 0; list->used = 0;
if (space > 0) { if (space > 0) {
list_for_each_entry(kctl, &card->controls, list) { list_for_each_entry(kctl, &card->controls, list) {
if (offset >= kctl->count) { if (offset >= kctl->count) {
...@@ -741,12 +738,12 @@ static int snd_ctl_elem_list(struct snd_card *card, ...@@ -741,12 +738,12 @@ static int snd_ctl_elem_list(struct snd_card *card,
} }
for (jidx = offset; jidx < kctl->count; jidx++) { for (jidx = offset; jidx < kctl->count; jidx++) {
snd_ctl_build_ioff(&id, kctl, jidx); snd_ctl_build_ioff(&id, kctl, jidx);
if (copy_to_user(list.pids + list.used, &id, if (copy_to_user(list->pids + list->used, &id,
sizeof(id))) { sizeof(id))) {
err = -EFAULT; err = -EFAULT;
goto out; goto out;
} }
list.used++; list->used++;
if (!--space) if (!--space)
goto out; goto out;
} }
...@@ -755,11 +752,26 @@ static int snd_ctl_elem_list(struct snd_card *card, ...@@ -755,11 +752,26 @@ static int snd_ctl_elem_list(struct snd_card *card,
} }
out: out:
up_read(&card->controls_rwsem); up_read(&card->controls_rwsem);
if (!err && copy_to_user(_list, &list, sizeof(list)))
err = -EFAULT;
return err; return err;
} }
static int snd_ctl_elem_list_user(struct snd_card *card,
struct snd_ctl_elem_list __user *_list)
{
struct snd_ctl_elem_list list;
int err;
if (copy_from_user(&list, _list, sizeof(list)))
return -EFAULT;
err = snd_ctl_elem_list(card, &list);
if (err)
return err;
if (copy_to_user(_list, &list, sizeof(list)))
return -EFAULT;
return 0;
}
/* Check whether the given kctl info is valid */ /* Check whether the given kctl info is valid */
static int snd_ctl_check_elem_info(struct snd_card *card, static int snd_ctl_check_elem_info(struct snd_card *card,
const struct snd_ctl_elem_info *info) const struct snd_ctl_elem_info *info)
...@@ -1703,7 +1715,7 @@ static long snd_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg ...@@ -1703,7 +1715,7 @@ static long snd_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg
case SNDRV_CTL_IOCTL_CARD_INFO: case SNDRV_CTL_IOCTL_CARD_INFO:
return snd_ctl_card_info(card, ctl, cmd, argp); return snd_ctl_card_info(card, ctl, cmd, argp);
case SNDRV_CTL_IOCTL_ELEM_LIST: case SNDRV_CTL_IOCTL_ELEM_LIST:
return snd_ctl_elem_list(card, argp); return snd_ctl_elem_list_user(card, argp);
case SNDRV_CTL_IOCTL_ELEM_INFO: case SNDRV_CTL_IOCTL_ELEM_INFO:
return snd_ctl_elem_info_user(ctl, argp); return snd_ctl_elem_info_user(ctl, argp);
case SNDRV_CTL_IOCTL_ELEM_READ: case SNDRV_CTL_IOCTL_ELEM_READ:
......
...@@ -22,24 +22,22 @@ struct snd_ctl_elem_list32 { ...@@ -22,24 +22,22 @@ struct snd_ctl_elem_list32 {
static int snd_ctl_elem_list_compat(struct snd_card *card, static int snd_ctl_elem_list_compat(struct snd_card *card,
struct snd_ctl_elem_list32 __user *data32) struct snd_ctl_elem_list32 __user *data32)
{ {
struct snd_ctl_elem_list __user *data; struct snd_ctl_elem_list data = {};
compat_caddr_t ptr; compat_caddr_t ptr;
int err; int err;
data = compat_alloc_user_space(sizeof(*data));
/* offset, space, used, count */ /* offset, space, used, count */
if (copy_in_user(data, data32, 4 * sizeof(u32))) if (copy_from_user(&data, data32, 4 * sizeof(u32)))
return -EFAULT; return -EFAULT;
/* pids */ /* pids */
if (get_user(ptr, &data32->pids) || if (get_user(ptr, &data32->pids))
put_user(compat_ptr(ptr), &data->pids))
return -EFAULT; return -EFAULT;
err = snd_ctl_elem_list(card, data); data.pids = compat_ptr(ptr);
err = snd_ctl_elem_list(card, &data);
if (err < 0) if (err < 0)
return err; return err;
/* copy the result */ /* copy the result */
if (copy_in_user(data32, data, 4 * sizeof(u32))) if (copy_to_user(data32, &data, 4 * sizeof(u32)))
return -EFAULT; return -EFAULT;
return 0; return 0;
} }
......
...@@ -203,28 +203,35 @@ static int snd_hwdep_dsp_status(struct snd_hwdep *hw, ...@@ -203,28 +203,35 @@ static int snd_hwdep_dsp_status(struct snd_hwdep *hw,
} }
static int snd_hwdep_dsp_load(struct snd_hwdep *hw, static int snd_hwdep_dsp_load(struct snd_hwdep *hw,
struct snd_hwdep_dsp_image __user *_info) struct snd_hwdep_dsp_image *info)
{ {
struct snd_hwdep_dsp_image info;
int err; int err;
if (! hw->ops.dsp_load) if (! hw->ops.dsp_load)
return -ENXIO; return -ENXIO;
memset(&info, 0, sizeof(info)); if (info->index >= 32)
if (copy_from_user(&info, _info, sizeof(info)))
return -EFAULT;
if (info.index >= 32)
return -EINVAL; return -EINVAL;
/* check whether the dsp was already loaded */ /* check whether the dsp was already loaded */
if (hw->dsp_loaded & (1u << info.index)) if (hw->dsp_loaded & (1u << info->index))
return -EBUSY; return -EBUSY;
err = hw->ops.dsp_load(hw, &info); err = hw->ops.dsp_load(hw, info);
if (err < 0) if (err < 0)
return err; return err;
hw->dsp_loaded |= (1u << info.index); hw->dsp_loaded |= (1u << info->index);
return 0; return 0;
} }
static int snd_hwdep_dsp_load_user(struct snd_hwdep *hw,
struct snd_hwdep_dsp_image __user *_info)
{
struct snd_hwdep_dsp_image info = {};
if (copy_from_user(&info, _info, sizeof(info)))
return -EFAULT;
return snd_hwdep_dsp_load(hw, &info);
}
static long snd_hwdep_ioctl(struct file * file, unsigned int cmd, static long snd_hwdep_ioctl(struct file * file, unsigned int cmd,
unsigned long arg) unsigned long arg)
{ {
...@@ -238,7 +245,7 @@ static long snd_hwdep_ioctl(struct file * file, unsigned int cmd, ...@@ -238,7 +245,7 @@ static long snd_hwdep_ioctl(struct file * file, unsigned int cmd,
case SNDRV_HWDEP_IOCTL_DSP_STATUS: case SNDRV_HWDEP_IOCTL_DSP_STATUS:
return snd_hwdep_dsp_status(hw, argp); return snd_hwdep_dsp_status(hw, argp);
case SNDRV_HWDEP_IOCTL_DSP_LOAD: case SNDRV_HWDEP_IOCTL_DSP_LOAD:
return snd_hwdep_dsp_load(hw, argp); return snd_hwdep_dsp_load_user(hw, argp);
} }
if (hw->ops.ioctl) if (hw->ops.ioctl)
return hw->ops.ioctl(hw, file, cmd, arg); return hw->ops.ioctl(hw, file, cmd, arg);
......
...@@ -19,26 +19,17 @@ struct snd_hwdep_dsp_image32 { ...@@ -19,26 +19,17 @@ struct snd_hwdep_dsp_image32 {
static int snd_hwdep_dsp_load_compat(struct snd_hwdep *hw, static int snd_hwdep_dsp_load_compat(struct snd_hwdep *hw,
struct snd_hwdep_dsp_image32 __user *src) struct snd_hwdep_dsp_image32 __user *src)
{ {
struct snd_hwdep_dsp_image __user *dst; struct snd_hwdep_dsp_image info = {};
compat_caddr_t ptr; compat_caddr_t ptr;
u32 val;
dst = compat_alloc_user_space(sizeof(*dst)); if (copy_from_user(&info, src, 4 + 64) ||
get_user(ptr, &src->image) ||
/* index and name */ get_user(info.length, &src->length) ||
if (copy_in_user(dst, src, 4 + 64)) get_user(info.driver_data, &src->driver_data))
return -EFAULT;
if (get_user(ptr, &src->image) ||
put_user(compat_ptr(ptr), &dst->image))
return -EFAULT;
if (get_user(val, &src->length) ||
put_user(val, &dst->length))
return -EFAULT;
if (get_user(val, &src->driver_data) ||
put_user(val, &dst->driver_data))
return -EFAULT; return -EFAULT;
info.image = compat_ptr(ptr);
return snd_hwdep_dsp_load(hw, dst); return snd_hwdep_dsp_load(hw, &info);
} }
enum { enum {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment