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>
This commit is contained in:
		
					parent
					
						
							
								4961772560
							
						
					
				
			
			
				commit
				
					
						1c65d98672
					
				
			
		
					 1 changed files with 20 additions and 19 deletions
				
			
		| 
						 | 
					@ -3033,9 +3033,7 @@ static ssize_t snd_pcm_write(struct file *file, const char __user *buf,
 | 
				
			||||||
	return result;
 | 
						return result;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static ssize_t snd_pcm_aio_read(struct kiocb *iocb, const struct iovec *iov,
 | 
					static ssize_t snd_pcm_readv(struct kiocb *iocb, struct iov_iter *to)
 | 
				
			||||||
			     unsigned long nr_segs, loff_t pos)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct snd_pcm_file *pcm_file;
 | 
						struct snd_pcm_file *pcm_file;
 | 
				
			||||||
	struct snd_pcm_substream *substream;
 | 
						struct snd_pcm_substream *substream;
 | 
				
			||||||
| 
						 | 
					@ -3052,16 +3050,18 @@ static ssize_t snd_pcm_aio_read(struct kiocb *iocb, const struct iovec *iov,
 | 
				
			||||||
	runtime = substream->runtime;
 | 
						runtime = substream->runtime;
 | 
				
			||||||
	if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
 | 
						if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
 | 
				
			||||||
		return -EBADFD;
 | 
							return -EBADFD;
 | 
				
			||||||
	if (nr_segs > 1024 || nr_segs != runtime->channels)
 | 
						if (!iter_is_iovec(to))
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	if (!frame_aligned(runtime, iov->iov_len))
 | 
						if (to->nr_segs > 1024 || to->nr_segs != runtime->channels)
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	frames = bytes_to_samples(runtime, iov->iov_len);
 | 
						if (!frame_aligned(runtime, to->iov->iov_len))
 | 
				
			||||||
	bufs = kmalloc(sizeof(void *) * nr_segs, GFP_KERNEL);
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
						frames = bytes_to_samples(runtime, to->iov->iov_len);
 | 
				
			||||||
 | 
						bufs = kmalloc(sizeof(void *) * to->nr_segs, GFP_KERNEL);
 | 
				
			||||||
	if (bufs == NULL)
 | 
						if (bufs == NULL)
 | 
				
			||||||
		return -ENOMEM;
 | 
							return -ENOMEM;
 | 
				
			||||||
	for (i = 0; i < nr_segs; ++i)
 | 
						for (i = 0; i < to->nr_segs; ++i)
 | 
				
			||||||
		bufs[i] = iov[i].iov_base;
 | 
							bufs[i] = to->iov[i].iov_base;
 | 
				
			||||||
	result = snd_pcm_lib_readv(substream, bufs, frames);
 | 
						result = snd_pcm_lib_readv(substream, bufs, frames);
 | 
				
			||||||
	if (result > 0)
 | 
						if (result > 0)
 | 
				
			||||||
		result = frames_to_bytes(runtime, result);
 | 
							result = frames_to_bytes(runtime, result);
 | 
				
			||||||
| 
						 | 
					@ -3069,8 +3069,7 @@ static ssize_t snd_pcm_aio_read(struct kiocb *iocb, const struct iovec *iov,
 | 
				
			||||||
	return result;
 | 
						return result;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static ssize_t snd_pcm_aio_write(struct kiocb *iocb, const struct iovec *iov,
 | 
					static ssize_t snd_pcm_writev(struct kiocb *iocb, struct iov_iter *from)
 | 
				
			||||||
			      unsigned long nr_segs, loff_t pos)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct snd_pcm_file *pcm_file;
 | 
						struct snd_pcm_file *pcm_file;
 | 
				
			||||||
	struct snd_pcm_substream *substream;
 | 
						struct snd_pcm_substream *substream;
 | 
				
			||||||
| 
						 | 
					@ -3087,15 +3086,17 @@ static ssize_t snd_pcm_aio_write(struct kiocb *iocb, const struct iovec *iov,
 | 
				
			||||||
	runtime = substream->runtime;
 | 
						runtime = substream->runtime;
 | 
				
			||||||
	if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
 | 
						if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
 | 
				
			||||||
		return -EBADFD;
 | 
							return -EBADFD;
 | 
				
			||||||
	if (nr_segs > 128 || nr_segs != runtime->channels ||
 | 
						if (!iter_is_iovec(from))
 | 
				
			||||||
	    !frame_aligned(runtime, iov->iov_len))
 | 
					 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	frames = bytes_to_samples(runtime, iov->iov_len);
 | 
						if (from->nr_segs > 128 || from->nr_segs != runtime->channels ||
 | 
				
			||||||
	bufs = kmalloc(sizeof(void *) * nr_segs, GFP_KERNEL);
 | 
						    !frame_aligned(runtime, from->iov->iov_len))
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
						frames = bytes_to_samples(runtime, from->iov->iov_len);
 | 
				
			||||||
 | 
						bufs = kmalloc(sizeof(void *) * from->nr_segs, GFP_KERNEL);
 | 
				
			||||||
	if (bufs == NULL)
 | 
						if (bufs == NULL)
 | 
				
			||||||
		return -ENOMEM;
 | 
							return -ENOMEM;
 | 
				
			||||||
	for (i = 0; i < nr_segs; ++i)
 | 
						for (i = 0; i < from->nr_segs; ++i)
 | 
				
			||||||
		bufs[i] = iov[i].iov_base;
 | 
							bufs[i] = from->iov[i].iov_base;
 | 
				
			||||||
	result = snd_pcm_lib_writev(substream, bufs, frames);
 | 
						result = snd_pcm_lib_writev(substream, bufs, frames);
 | 
				
			||||||
	if (result > 0)
 | 
						if (result > 0)
 | 
				
			||||||
		result = frames_to_bytes(runtime, result);
 | 
							result = frames_to_bytes(runtime, result);
 | 
				
			||||||
| 
						 | 
					@ -3633,7 +3634,7 @@ const struct file_operations snd_pcm_f_ops[2] = {
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		.owner =		THIS_MODULE,
 | 
							.owner =		THIS_MODULE,
 | 
				
			||||||
		.write =		snd_pcm_write,
 | 
							.write =		snd_pcm_write,
 | 
				
			||||||
		.aio_write =		snd_pcm_aio_write,
 | 
							.write_iter =		snd_pcm_writev,
 | 
				
			||||||
		.open =			snd_pcm_playback_open,
 | 
							.open =			snd_pcm_playback_open,
 | 
				
			||||||
		.release =		snd_pcm_release,
 | 
							.release =		snd_pcm_release,
 | 
				
			||||||
		.llseek =		no_llseek,
 | 
							.llseek =		no_llseek,
 | 
				
			||||||
| 
						 | 
					@ -3647,7 +3648,7 @@ const struct file_operations snd_pcm_f_ops[2] = {
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		.owner =		THIS_MODULE,
 | 
							.owner =		THIS_MODULE,
 | 
				
			||||||
		.read =			snd_pcm_read,
 | 
							.read =			snd_pcm_read,
 | 
				
			||||||
		.aio_read =		snd_pcm_aio_read,
 | 
							.read_iter =		snd_pcm_readv,
 | 
				
			||||||
		.open =			snd_pcm_capture_open,
 | 
							.open =			snd_pcm_capture_open,
 | 
				
			||||||
		.release =		snd_pcm_release,
 | 
							.release =		snd_pcm_release,
 | 
				
			||||||
		.llseek =		no_llseek,
 | 
							.llseek =		no_llseek,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue