|
@@ -647,15 +647,26 @@ static void ffs_user_copy_worker(struct work_struct *work)
|
|
if (io_data->read && ret > 0) {
|
|
if (io_data->read && ret > 0) {
|
|
int i;
|
|
int i;
|
|
size_t pos = 0;
|
|
size_t pos = 0;
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * Since req->length may be bigger than io_data->len (after
|
|
|
|
+ * being rounded up to maxpacketsize), we may end up with more
|
|
|
|
+ * data then user space has space for.
|
|
|
|
+ */
|
|
|
|
+ ret = min_t(int, ret, io_data->len);
|
|
|
|
+
|
|
use_mm(io_data->mm);
|
|
use_mm(io_data->mm);
|
|
for (i = 0; i < io_data->nr_segs; i++) {
|
|
for (i = 0; i < io_data->nr_segs; i++) {
|
|
|
|
+ size_t len = min_t(size_t, ret - pos,
|
|
|
|
+ io_data->iovec[i].iov_len);
|
|
|
|
+ if (!len)
|
|
|
|
+ break;
|
|
if (unlikely(copy_to_user(io_data->iovec[i].iov_base,
|
|
if (unlikely(copy_to_user(io_data->iovec[i].iov_base,
|
|
- &io_data->buf[pos],
|
|
|
|
- io_data->iovec[i].iov_len))) {
|
|
|
|
|
|
+ &io_data->buf[pos], len))) {
|
|
ret = -EFAULT;
|
|
ret = -EFAULT;
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
- pos += io_data->iovec[i].iov_len;
|
|
|
|
|
|
+ pos += len;
|
|
}
|
|
}
|
|
unuse_mm(io_data->mm);
|
|
unuse_mm(io_data->mm);
|
|
}
|
|
}
|
|
@@ -687,7 +698,7 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data)
|
|
struct ffs_epfile *epfile = file->private_data;
|
|
struct ffs_epfile *epfile = file->private_data;
|
|
struct ffs_ep *ep;
|
|
struct ffs_ep *ep;
|
|
char *data = NULL;
|
|
char *data = NULL;
|
|
- ssize_t ret, data_len;
|
|
|
|
|
|
+ ssize_t ret, data_len = -EINVAL;
|
|
int halt;
|
|
int halt;
|
|
|
|
|
|
/* Are we still active? */
|
|
/* Are we still active? */
|
|
@@ -787,13 +798,30 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data)
|
|
/* Fire the request */
|
|
/* Fire the request */
|
|
struct usb_request *req;
|
|
struct usb_request *req;
|
|
|
|
|
|
|
|
+ /*
|
|
|
|
+ * Sanity Check: even though data_len can't be used
|
|
|
|
+ * uninitialized at the time I write this comment, some
|
|
|
|
+ * compilers complain about this situation.
|
|
|
|
+ * In order to keep the code clean from warnings, data_len is
|
|
|
|
+ * being initialized to -EINVAL during its declaration, which
|
|
|
|
+ * means we can't rely on compiler anymore to warn no future
|
|
|
|
+ * changes won't result in data_len being used uninitialized.
|
|
|
|
+ * For such reason, we're adding this redundant sanity check
|
|
|
|
+ * here.
|
|
|
|
+ */
|
|
|
|
+ if (unlikely(data_len == -EINVAL)) {
|
|
|
|
+ WARN(1, "%s: data_len == -EINVAL\n", __func__);
|
|
|
|
+ ret = -EINVAL;
|
|
|
|
+ goto error_lock;
|
|
|
|
+ }
|
|
|
|
+
|
|
if (io_data->aio) {
|
|
if (io_data->aio) {
|
|
req = usb_ep_alloc_request(ep->ep, GFP_KERNEL);
|
|
req = usb_ep_alloc_request(ep->ep, GFP_KERNEL);
|
|
if (unlikely(!req))
|
|
if (unlikely(!req))
|
|
goto error_lock;
|
|
goto error_lock;
|
|
|
|
|
|
req->buf = data;
|
|
req->buf = data;
|
|
- req->length = io_data->len;
|
|
|
|
|
|
+ req->length = data_len;
|
|
|
|
|
|
io_data->buf = data;
|
|
io_data->buf = data;
|
|
io_data->ep = ep->ep;
|
|
io_data->ep = ep->ep;
|
|
@@ -815,7 +843,7 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data)
|
|
|
|
|
|
req = ep->req;
|
|
req = ep->req;
|
|
req->buf = data;
|
|
req->buf = data;
|
|
- req->length = io_data->len;
|
|
|
|
|
|
+ req->length = data_len;
|
|
|
|
|
|
req->context = &done;
|
|
req->context = &done;
|
|
req->complete = ffs_epfile_io_complete;
|
|
req->complete = ffs_epfile_io_complete;
|