summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIan Abbott <abbotti@mev.co.uk>2015-11-18 17:55:08 +0000
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2015-12-21 15:58:54 -0800
commit35a7475dc818320915e89ed0217872ff1ab66ec2 (patch)
treeac14634755e673dee2339ecb6d79cc27007a8878
parent591c5f8a599a58c7c3773027010e537fc1d7a7d5 (diff)
downloadlinux-35a7475dc818320915e89ed0217872ff1ab66ec2.tar.bz2
staging: comedi: allow buffer wraparound in comedi_write()
`comedi_write()` copies data from the user buffer to the acquisition data buffer, which is cyclic, using a single call to `copy_from_user()`. It currently avoids having to deal with wraparound of the cyclic buffer by limiting the amount it copies (and the amount returned to the user). Change it to deal with the wraparound using two calls to `copy_from_user()` if necessary. Signed-off-by: Ian Abbott <abbotti@mev.co.uk> Reviewed-by: H Hartley Sweeten <hsweeten@visionengravers.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/staging/comedi/comedi_fops.c14
1 files changed, 9 insertions, 5 deletions
diff --git a/drivers/staging/comedi/comedi_fops.c b/drivers/staging/comedi/comedi_fops.c
index 8c784c483c3e..4dd42890c641 100644
--- a/drivers/staging/comedi/comedi_fops.c
+++ b/drivers/staging/comedi/comedi_fops.c
@@ -2346,6 +2346,7 @@ static ssize_t comedi_write(struct file *file, const char __user *buf,
add_wait_queue(&async->wait_head, &wait);
while (count == 0 && !retval) {
unsigned runflags;
+ unsigned int wp, n1, n2;
set_current_state(TASK_INTERRUPTIBLE);
@@ -2360,9 +2361,6 @@ static ssize_t comedi_write(struct file *file, const char __user *buf,
/* Allocate all free buffer space. */
comedi_buf_write_alloc(s, async->prealloc_bufsz);
m = comedi_buf_write_n_allocated(s);
- /* Avoid buffer wraparound. */
- if (async->buf_write_ptr + m > async->prealloc_bufsz)
- m = async->prealloc_bufsz - async->buf_write_ptr;
n = min_t(size_t, m, nbytes);
if (n == 0) {
@@ -2388,8 +2386,14 @@ static ssize_t comedi_write(struct file *file, const char __user *buf,
continue;
}
- m = copy_from_user(async->prealloc_buf + async->buf_write_ptr,
- buf, n);
+ wp = async->buf_write_ptr;
+ n1 = min(n, async->prealloc_bufsz - wp);
+ n2 = n - n1;
+ m = copy_from_user(async->prealloc_buf + wp, buf, n1);
+ if (m)
+ m += n2;
+ else if (n2)
+ m = copy_from_user(async->prealloc_buf, buf + n1, n2);
if (m) {
n -= m;
retval = -EFAULT;