/* * xfern ioctl nees to copy (up to) 128 pointers on stack. * although we may pass the copied pointers through f_op->ioctl, but the ioctl * handler there expands again the same 128 pointers on stack, so it is better * to handle the function (calling pcm_readv/writev) directly in this handler. */ static int snd_pcm_ioctl_xfern_compat(struct snd_pcm_substream *substream, int dir, struct snd_xfern32 __user *data32) { compat_caddr_t buf; compat_caddr_t __user *bufptr; u32 frames; void __user **bufs; int err, ch, i; if (! substream->runtime) return -ENOTTY; if (substream->stream != dir) return -EINVAL; if ((ch = substream->runtime->channels) > 128) return -EINVAL; if (get_user(buf, &data32->bufs) || get_user(frames, &data32->frames)) return -EFAULT; bufptr = compat_ptr(buf); bufs = kmalloc(sizeof(void __user *) * ch, GFP_KERNEL); if (bufs == NULL) return -ENOMEM; for (i = 0; i < ch; i++) { u32 ptr; if (get_user(ptr, bufptr)) { kfree(bufs); return -EFAULT; } bufs[i] = compat_ptr(ptr); bufptr++; } if (dir == SNDRV_PCM_STREAM_PLAYBACK) err = snd_pcm_lib_writev(substream, bufs, frames); else err = snd_pcm_lib_readv(substream, bufs, frames); if (err >= 0) { if (put_user(err, &data32->result)) err = -EFAULT; } kfree(bufs); return err; }
/* * xfern ioctl nees to copy (up to) 128 pointers on stack. * although we may pass the copied pointers through f_op->ioctl, but the ioctl * handler there expands again the same 128 pointers on stack, so it is better * to handle the function (calling pcm_readv/writev) directly in this handler. */ static int _snd_ioctl32_xfern(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *file, unsigned int native_ctl) { snd_pcm_file_t *pcm_file; snd_pcm_substream_t *substream; struct sndrv_xfern32 __user *srcptr = compat_ptr(arg); struct sndrv_xfern32 data32; void __user **bufs; int err = 0, ch, i; u32 __user *bufptr; if (sanity_check_pcm(file)) return -ENOTTY; if (! (pcm_file = file->private_data)) return -ENOTTY; if (! (substream = pcm_file->substream)) return -ENOTTY; if (! substream->runtime) return -ENOTTY; /* check validty of the command */ switch (native_ctl) { case SNDRV_PCM_IOCTL_WRITEN_FRAMES: if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK) return -EINVAL; if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) return -EBADFD; break; case SNDRV_PCM_IOCTL_READN_FRAMES: if (substream->stream != SNDRV_PCM_STREAM_CAPTURE) return -EINVAL; break; } if ((ch = substream->runtime->channels) > 128) return -EINVAL; if (copy_from_user(&data32, (void __user *)arg, sizeof(data32))) return -EFAULT; bufptr = compat_ptr(data32.bufs); bufs = kmalloc(sizeof(void __user *) * ch, GFP_KERNEL); if (bufs == NULL) return -ENOMEM; for (i = 0; i < ch; i++) { u32 ptr; if (get_user(ptr, bufptr)) { kfree(bufs); return -EFAULT; } bufs[ch] = compat_ptr(ptr); bufptr++; } switch (native_ctl) { case SNDRV_PCM_IOCTL_WRITEN_FRAMES: err = snd_pcm_lib_writev(substream, bufs, data32.frames); break; case SNDRV_PCM_IOCTL_READN_FRAMES: err = snd_pcm_lib_readv(substream, bufs, data32.frames); break; } if (err >= 0) { if (put_user(err, &srcptr->result)) err = -EFAULT; } kfree(bufs); return err; }