aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2015-04-04 00:19:32 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2015-04-11 22:29:43 -0400
commit1c65d98672e09a0cb28e1e9ae49e9d96355f522f (patch)
treefee8829694480137eacc54987c49d8c845a084ef
parent4961772560d2f19695c73ece943716033ad62ac2 (diff)
pcm: another weird API abuse
readv() and writev() should _not_ ignore all but the first ->iov_len, among other things. Really weird abuse of those syscalls - it expects a vector element per channel, with identical lengths (it actually assumes them to be identical - no checking is done). readv() and writev() are really bad match for that. Unfortunately, userland API is userland API and we can't do anything about them. Converted to ->read_iter/->write_iter. Please, _please_ don't do anything of that kind when designing new interfaces. Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
-rw-r--r--sound/core/pcm_native.c39
1 files changed, 20 insertions, 19 deletions
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index a69ebc79bc50..8e43610ec9b5 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -3033,9 +3033,7 @@ static ssize_t snd_pcm_write(struct file *file, const char __user *buf,
3033 return result; 3033 return result;
3034} 3034}
3035 3035
3036static ssize_t snd_pcm_aio_read(struct kiocb *iocb, const struct iovec *iov, 3036static ssize_t snd_pcm_readv(struct kiocb *iocb, struct iov_iter *to)
3037 unsigned long nr_segs, loff_t pos)
3038
3039{ 3037{
3040 struct snd_pcm_file *pcm_file; 3038 struct snd_pcm_file *pcm_file;
3041 struct snd_pcm_substream *substream; 3039 struct snd_pcm_substream *substream;
@@ -3052,16 +3050,18 @@ static ssize_t snd_pcm_aio_read(struct kiocb *iocb, const struct iovec *iov,
3052 runtime = substream->runtime; 3050 runtime = substream->runtime;
3053 if (runtime->status->state == SNDRV_PCM_STATE_OPEN) 3051 if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
3054 return -EBADFD; 3052 return -EBADFD;
3055 if (nr_segs > 1024 || nr_segs != runtime->channels) 3053 if (!iter_is_iovec(to))
3054 return -EINVAL;
3055 if (to->nr_segs > 1024 || to->nr_segs != runtime->channels)
3056 return -EINVAL; 3056 return -EINVAL;
3057 if (!frame_aligned(runtime, iov->iov_len)) 3057 if (!frame_aligned(runtime, to->iov->iov_len))
3058 return -EINVAL; 3058 return -EINVAL;
3059 frames = bytes_to_samples(runtime, iov->iov_len); 3059 frames = bytes_to_samples(runtime, to->iov->iov_len);
3060 bufs = kmalloc(sizeof(void *) * nr_segs, GFP_KERNEL); 3060 bufs = kmalloc(sizeof(void *) * to->nr_segs, GFP_KERNEL);
3061 if (bufs == NULL) 3061 if (bufs == NULL)
3062 return -ENOMEM; 3062 return -ENOMEM;
3063 for (i = 0; i < nr_segs; ++i) 3063 for (i = 0; i < to->nr_segs; ++i)
3064 bufs[i] = iov[i].iov_base; 3064 bufs[i] = to->iov[i].iov_base;
3065 result = snd_pcm_lib_readv(substream, bufs, frames); 3065 result = snd_pcm_lib_readv(substream, bufs, frames);
3066 if (result > 0) 3066 if (result > 0)
3067 result = frames_to_bytes(runtime, result); 3067 result = frames_to_bytes(runtime, result);
@@ -3069,8 +3069,7 @@ static ssize_t snd_pcm_aio_read(struct kiocb *iocb, const struct iovec *iov,
3069 return result; 3069 return result;
3070} 3070}
3071 3071
3072static ssize_t snd_pcm_aio_write(struct kiocb *iocb, const struct iovec *iov, 3072static ssize_t snd_pcm_writev(struct kiocb *iocb, struct iov_iter *from)
3073 unsigned long nr_segs, loff_t pos)
3074{ 3073{
3075 struct snd_pcm_file *pcm_file; 3074 struct snd_pcm_file *pcm_file;
3076 struct snd_pcm_substream *substream; 3075 struct snd_pcm_substream *substream;
@@ -3087,15 +3086,17 @@ static ssize_t snd_pcm_aio_write(struct kiocb *iocb, const struct iovec *iov,
3087 runtime = substream->runtime; 3086 runtime = substream->runtime;
3088 if (runtime->status->state == SNDRV_PCM_STATE_OPEN) 3087 if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
3089 return -EBADFD; 3088 return -EBADFD;
3090 if (nr_segs > 128 || nr_segs != runtime->channels || 3089 if (!iter_is_iovec(from))
3091 !frame_aligned(runtime, iov->iov_len)) 3090 return -EINVAL;
3091 if (from->nr_segs > 128 || from->nr_segs != runtime->channels ||
3092 !frame_aligned(runtime, from->iov->iov_len))
3092 return -EINVAL; 3093 return -EINVAL;
3093 frames = bytes_to_samples(runtime, iov->iov_len); 3094 frames = bytes_to_samples(runtime, from->iov->iov_len);
3094 bufs = kmalloc(sizeof(void *) * nr_segs, GFP_KERNEL); 3095 bufs = kmalloc(sizeof(void *) * from->nr_segs, GFP_KERNEL);
3095 if (bufs == NULL) 3096 if (bufs == NULL)
3096 return -ENOMEM; 3097 return -ENOMEM;
3097 for (i = 0; i < nr_segs; ++i) 3098 for (i = 0; i < from->nr_segs; ++i)
3098 bufs[i] = iov[i].iov_base; 3099 bufs[i] = from->iov[i].iov_base;
3099 result = snd_pcm_lib_writev(substream, bufs, frames); 3100 result = snd_pcm_lib_writev(substream, bufs, frames);
3100 if (result > 0) 3101 if (result > 0)
3101 result = frames_to_bytes(runtime, result); 3102 result = frames_to_bytes(runtime, result);
@@ -3633,7 +3634,7 @@ const struct file_operations snd_pcm_f_ops[2] = {
3633 { 3634 {
3634 .owner = THIS_MODULE, 3635 .owner = THIS_MODULE,
3635 .write = snd_pcm_write, 3636 .write = snd_pcm_write,
3636 .aio_write = snd_pcm_aio_write, 3637 .write_iter = snd_pcm_writev,
3637 .open = snd_pcm_playback_open, 3638 .open = snd_pcm_playback_open,
3638 .release = snd_pcm_release, 3639 .release = snd_pcm_release,
3639 .llseek = no_llseek, 3640 .llseek = no_llseek,
@@ -3647,7 +3648,7 @@ const struct file_operations snd_pcm_f_ops[2] = {
3647 { 3648 {
3648 .owner = THIS_MODULE, 3649 .owner = THIS_MODULE,
3649 .read = snd_pcm_read, 3650 .read = snd_pcm_read,
3650 .aio_read = snd_pcm_aio_read, 3651 .read_iter = snd_pcm_readv,
3651 .open = snd_pcm_capture_open, 3652 .open = snd_pcm_capture_open,
3652 .release = snd_pcm_release, 3653 .release = snd_pcm_release,
3653 .llseek = no_llseek, 3654 .llseek = no_llseek,