diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2015-04-04 00:19:32 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2015-04-11 22:29:43 -0400 |
commit | 1c65d98672e09a0cb28e1e9ae49e9d96355f522f (patch) | |
tree | fee8829694480137eacc54987c49d8c845a084ef | |
parent | 4961772560d2f19695c73ece943716033ad62ac2 (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.c | 39 |
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 | ||
3036 | static ssize_t snd_pcm_aio_read(struct kiocb *iocb, const struct iovec *iov, | 3036 | static 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 | ||
3072 | static ssize_t snd_pcm_aio_write(struct kiocb *iocb, const struct iovec *iov, | 3072 | static 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, |