From d0b2f91bede3bd5e3d24dd6803e56eee959c1797 Mon Sep 17 00:00:00 2001 From: André Fabian Silva Delgado Date: Thu, 20 Oct 2016 00:10:27 -0300 Subject: Linux-libre 4.8.2-gnu --- drivers/usb/gadget/function/f_eem.c | 12 +- drivers/usb/gadget/function/f_fs.c | 192 ++++++++++++++++++++++----- drivers/usb/gadget/function/f_mass_storage.c | 22 +-- drivers/usb/gadget/function/f_rndis.c | 3 + drivers/usb/gadget/function/rndis.c | 6 + drivers/usb/gadget/function/u_ether.c | 3 +- drivers/usb/gadget/function/u_serial.c | 10 +- drivers/usb/gadget/function/uvc_configfs.c | 2 +- drivers/usb/gadget/function/uvc_queue.c | 2 +- 9 files changed, 185 insertions(+), 67 deletions(-) (limited to 'drivers/usb/gadget/function') diff --git a/drivers/usb/gadget/function/f_eem.c b/drivers/usb/gadget/function/f_eem.c index d58bfc32b..007ec6e4a 100644 --- a/drivers/usb/gadget/function/f_eem.c +++ b/drivers/usb/gadget/function/f_eem.c @@ -341,11 +341,15 @@ static struct sk_buff *eem_wrap(struct gether *port, struct sk_buff *skb) { struct sk_buff *skb2 = NULL; struct usb_ep *in = port->in_ep; - int padlen = 0; - u16 len = skb->len; + int headroom, tailroom, padlen = 0; + u16 len; - int headroom = skb_headroom(skb); - int tailroom = skb_tailroom(skb); + if (!skb) + return NULL; + + len = skb->len; + headroom = skb_headroom(skb); + tailroom = skb_tailroom(skb); /* When (len + EEM_HLEN + ETH_FCS_LEN) % in->maxpacket) is 0, * stick two bytes of zero-length EEM packet on the end. diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c index cc33d2667..5c8429f23 100644 --- a/drivers/usb/gadget/function/f_fs.c +++ b/drivers/usb/gadget/function/f_fs.c @@ -130,6 +130,12 @@ struct ffs_epfile { struct dentry *dentry; + /* + * Buffer for holding data from partial reads which may happen since + * we’re rounding user read requests to a multiple of a max packet size. + */ + struct ffs_buffer *read_buffer; /* P: epfile->mutex */ + char name[5]; unsigned char in; /* P: ffs->eps_lock */ @@ -138,6 +144,12 @@ struct ffs_epfile { unsigned char _pad; }; +struct ffs_buffer { + size_t length; + char *data; + char storage[]; +}; + /* ffs_io_data structure ***************************************************/ struct ffs_io_data { @@ -640,6 +652,49 @@ static void ffs_epfile_io_complete(struct usb_ep *_ep, struct usb_request *req) } } +static ssize_t ffs_copy_to_iter(void *data, int data_len, struct iov_iter *iter) +{ + ssize_t ret = copy_to_iter(data, data_len, iter); + if (likely(ret == data_len)) + return ret; + + if (unlikely(iov_iter_count(iter))) + return -EFAULT; + + /* + * Dear user space developer! + * + * TL;DR: To stop getting below error message in your kernel log, change + * user space code using functionfs to align read buffers to a max + * packet size. + * + * Some UDCs (e.g. dwc3) require request sizes to be a multiple of a max + * packet size. When unaligned buffer is passed to functionfs, it + * internally uses a larger, aligned buffer so that such UDCs are happy. + * + * Unfortunately, this means that host may send more data than was + * requested in read(2) system call. f_fs doesn’t know what to do with + * that excess data so it simply drops it. + * + * Was the buffer aligned in the first place, no such problem would + * happen. + * + * Data may be dropped only in AIO reads. Synchronous reads are handled + * by splitting a request into multiple parts. This splitting may still + * be a problem though so it’s likely best to align the buffer + * regardless of it being AIO or not.. + * + * This only affects OUT endpoints, i.e. reading data with a read(2), + * aio_read(2) etc. system calls. Writing data to an IN endpoint is not + * affected. + */ + pr_err("functionfs read size %d > requested size %zd, dropping excess data. " + "Align read buffer size to max packet size to avoid the problem.\n", + data_len, ret); + + return ret; +} + static void ffs_user_copy_worker(struct work_struct *work) { struct ffs_io_data *io_data = container_of(work, struct ffs_io_data, @@ -650,9 +705,7 @@ static void ffs_user_copy_worker(struct work_struct *work) if (io_data->read && ret > 0) { use_mm(io_data->mm); - ret = copy_to_iter(io_data->buf, ret, &io_data->data); - if (ret != io_data->req->actual && iov_iter_count(&io_data->data)) - ret = -EFAULT; + ret = ffs_copy_to_iter(io_data->buf, ret, &io_data->data); unuse_mm(io_data->mm); } @@ -680,6 +733,58 @@ static void ffs_epfile_async_io_complete(struct usb_ep *_ep, schedule_work(&io_data->work); } +/* Assumes epfile->mutex is held. */ +static ssize_t __ffs_epfile_read_buffered(struct ffs_epfile *epfile, + struct iov_iter *iter) +{ + struct ffs_buffer *buf = epfile->read_buffer; + ssize_t ret; + if (!buf) + return 0; + + ret = copy_to_iter(buf->data, buf->length, iter); + if (buf->length == ret) { + kfree(buf); + epfile->read_buffer = NULL; + } else if (unlikely(iov_iter_count(iter))) { + ret = -EFAULT; + } else { + buf->length -= ret; + buf->data += ret; + } + return ret; +} + +/* Assumes epfile->mutex is held. */ +static ssize_t __ffs_epfile_read_data(struct ffs_epfile *epfile, + void *data, int data_len, + struct iov_iter *iter) +{ + struct ffs_buffer *buf; + + ssize_t ret = copy_to_iter(data, data_len, iter); + if (likely(data_len == ret)) + return ret; + + if (unlikely(iov_iter_count(iter))) + return -EFAULT; + + /* See ffs_copy_to_iter for more context. */ + pr_warn("functionfs read size %d > requested size %zd, splitting request into multiple reads.", + data_len, ret); + + data_len -= ret; + buf = kmalloc(sizeof(*buf) + data_len, GFP_KERNEL); + if (!buf) + return -ENOMEM; + buf->length = data_len; + buf->data = buf->storage; + memcpy(buf->storage, data + ret, data_len); + epfile->read_buffer = buf; + + return ret; +} + static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data) { struct ffs_epfile *epfile = file->private_data; @@ -709,21 +814,40 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data) if (halt && epfile->isoc) return -EINVAL; + /* We will be using request and read_buffer */ + ret = ffs_mutex_lock(&epfile->mutex, file->f_flags & O_NONBLOCK); + if (unlikely(ret)) + goto error; + /* Allocate & copy */ if (!halt) { + struct usb_gadget *gadget; + + /* + * Do we have buffered data from previous partial read? Check + * that for synchronous case only because we do not have + * facility to ‘wake up’ a pending asynchronous read and push + * buffered data to it which we would need to make things behave + * consistently. + */ + if (!io_data->aio && io_data->read) { + ret = __ffs_epfile_read_buffered(epfile, &io_data->data); + if (ret) + goto error_mutex; + } + /* * if we _do_ wait above, the epfile->ffs->gadget might be NULL * before the waiting completes, so do not assign to 'gadget' * earlier */ - struct usb_gadget *gadget = epfile->ffs->gadget; - size_t copied; + gadget = epfile->ffs->gadget; spin_lock_irq(&epfile->ffs->eps_lock); /* In the meantime, endpoint got disabled or changed. */ if (epfile->ep != ep) { - spin_unlock_irq(&epfile->ffs->eps_lock); - return -ESHUTDOWN; + ret = -ESHUTDOWN; + goto error_lock; } data_len = iov_iter_count(&io_data->data); /* @@ -735,22 +859,17 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data) spin_unlock_irq(&epfile->ffs->eps_lock); data = kmalloc(data_len, GFP_KERNEL); - if (unlikely(!data)) - return -ENOMEM; - if (!io_data->read) { - copied = copy_from_iter(data, data_len, &io_data->data); - if (copied != data_len) { - ret = -EFAULT; - goto error; - } + if (unlikely(!data)) { + ret = -ENOMEM; + goto error_mutex; + } + if (!io_data->read && + copy_from_iter(data, data_len, &io_data->data) != data_len) { + ret = -EFAULT; + goto error_mutex; } } - /* We will be using request */ - ret = ffs_mutex_lock(&epfile->mutex, file->f_flags & O_NONBLOCK); - if (unlikely(ret)) - goto error; - spin_lock_irq(&epfile->ffs->eps_lock); if (epfile->ep != ep) { @@ -803,18 +922,13 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data) interrupted = ep->status < 0; } - /* - * XXX We may end up silently droping data here. Since data_len - * (i.e. req->length) may be bigger than len (after being - * rounded up to maxpacketsize), we may end up with more data - * then user space has space for. - */ - ret = interrupted ? -EINTR : ep->status; - if (io_data->read && ret > 0) { - ret = copy_to_iter(data, ret, &io_data->data); - if (!ret) - ret = -EFAULT; - } + if (interrupted) + ret = -EINTR; + else if (io_data->read && ep->status > 0) + ret = __ffs_epfile_read_data(epfile, data, ep->status, + &io_data->data); + else + ret = ep->status; goto error_mutex; } else if (!(req = usb_ep_alloc_request(ep->ep, GFP_KERNEL))) { ret = -ENOMEM; @@ -980,6 +1094,8 @@ ffs_epfile_release(struct inode *inode, struct file *file) ENTER(); + kfree(epfile->read_buffer); + epfile->read_buffer = NULL; ffs_data_closed(epfile->ffs); return 0; @@ -1605,19 +1721,24 @@ static void ffs_func_eps_disable(struct ffs_function *func) unsigned count = func->ffs->eps_count; unsigned long flags; - spin_lock_irqsave(&func->ffs->eps_lock, flags); do { + if (epfile) + mutex_lock(&epfile->mutex); + spin_lock_irqsave(&func->ffs->eps_lock, flags); /* pending requests get nuked */ if (likely(ep->ep)) usb_ep_disable(ep->ep); ++ep; + spin_unlock_irqrestore(&func->ffs->eps_lock, flags); if (epfile) { epfile->ep = NULL; + kfree(epfile->read_buffer); + epfile->read_buffer = NULL; + mutex_unlock(&epfile->mutex); ++epfile; } } while (--count); - spin_unlock_irqrestore(&func->ffs->eps_lock, flags); } static int ffs_func_eps_enable(struct ffs_function *func) @@ -2227,8 +2348,8 @@ static int __ffs_data_got_strings(struct ffs_data *ffs, { u32 str_count, needed_count, lang_count; struct usb_gadget_strings **stringtabs, *t; - struct usb_string *strings, *s; const char *data = _data; + struct usb_string *s; ENTER(); @@ -2286,7 +2407,6 @@ static int __ffs_data_got_strings(struct ffs_data *ffs, stringtabs = vla_ptr(vlabuf, d, stringtabs); t = vla_ptr(vlabuf, d, stringtab); s = vla_ptr(vlabuf, d, strings); - strings = s; } /* For each language */ diff --git a/drivers/usb/gadget/function/f_mass_storage.c b/drivers/usb/gadget/function/f_mass_storage.c index 5c6d4d7ca..2505117e8 100644 --- a/drivers/usb/gadget/function/f_mass_storage.c +++ b/drivers/usb/gadget/function/f_mass_storage.c @@ -2655,18 +2655,6 @@ void fsg_common_put(struct fsg_common *common) } EXPORT_SYMBOL_GPL(fsg_common_put); -/* check if fsg_num_buffers is within a valid range */ -static inline int fsg_num_buffers_validate(unsigned int fsg_num_buffers) -{ -#define FSG_MAX_NUM_BUFFERS 32 - - if (fsg_num_buffers >= 2 && fsg_num_buffers <= FSG_MAX_NUM_BUFFERS) - return 0; - pr_err("fsg_num_buffers %u is out of range (%d to %d)\n", - fsg_num_buffers, 2, FSG_MAX_NUM_BUFFERS); - return -EINVAL; -} - static struct fsg_common *fsg_common_setup(struct fsg_common *common) { if (!common) { @@ -2709,11 +2697,7 @@ static void _fsg_common_free_buffers(struct fsg_buffhd *buffhds, unsigned n) int fsg_common_set_num_buffers(struct fsg_common *common, unsigned int n) { struct fsg_buffhd *bh, *buffhds; - int i, rc; - - rc = fsg_num_buffers_validate(n); - if (rc != 0) - return rc; + int i; buffhds = kcalloc(n, sizeof(*buffhds), GFP_KERNEL); if (!buffhds) @@ -3401,10 +3385,6 @@ static ssize_t fsg_opts_num_buffers_store(struct config_item *item, if (ret) goto end; - ret = fsg_num_buffers_validate(num); - if (ret) - goto end; - fsg_common_set_num_buffers(opts->common, num); ret = len; diff --git a/drivers/usb/gadget/function/f_rndis.c b/drivers/usb/gadget/function/f_rndis.c index c8005823b..16562e461 100644 --- a/drivers/usb/gadget/function/f_rndis.c +++ b/drivers/usb/gadget/function/f_rndis.c @@ -374,6 +374,9 @@ static struct sk_buff *rndis_add_header(struct gether *port, { struct sk_buff *skb2; + if (!skb) + return NULL; + skb2 = skb_realloc_headroom(skb, sizeof(struct rndis_packet_msg_type)); rndis_add_hdr(skb2); diff --git a/drivers/usb/gadget/function/rndis.c b/drivers/usb/gadget/function/rndis.c index 943c21aaf..ab6ac1b74 100644 --- a/drivers/usb/gadget/function/rndis.c +++ b/drivers/usb/gadget/function/rndis.c @@ -680,6 +680,12 @@ static int rndis_reset_response(struct rndis_params *params, { rndis_reset_cmplt_type *resp; rndis_resp_t *r; + u8 *xbuf; + u32 length; + + /* drain the response queue */ + while ((xbuf = rndis_get_next_response(params, &length))) + rndis_free_response(params, xbuf); r = rndis_add_response(params, sizeof(rndis_reset_cmplt_type)); if (!r) diff --git a/drivers/usb/gadget/function/u_ether.c b/drivers/usb/gadget/function/u_ether.c index a3f7e7c55..5f562c1ec 100644 --- a/drivers/usb/gadget/function/u_ether.c +++ b/drivers/usb/gadget/function/u_ether.c @@ -556,7 +556,8 @@ static netdev_tx_t eth_start_xmit(struct sk_buff *skb, /* Multi frame CDC protocols may store the frame for * later which is not a dropped frame. */ - if (dev->port_usb->supports_multi_frame) + if (dev->port_usb && + dev->port_usb->supports_multi_frame) goto multiframe; goto drop; } diff --git a/drivers/usb/gadget/function/u_serial.c b/drivers/usb/gadget/function/u_serial.c index 99c486264..a91fe6476 100644 --- a/drivers/usb/gadget/function/u_serial.c +++ b/drivers/usb/gadget/function/u_serial.c @@ -375,10 +375,15 @@ __acquires(&port->port_lock) */ { struct list_head *pool = &port->write_pool; - struct usb_ep *in = port->port_usb->in; + struct usb_ep *in; int status = 0; bool do_tty_wake = false; + if (!port->port_usb) + return status; + + in = port->port_usb->in; + while (!port->write_busy && !list_empty(pool)) { struct usb_request *req; int len; @@ -907,7 +912,6 @@ static int gs_write(struct tty_struct *tty, const unsigned char *buf, int count) { struct gs_port *port = tty->driver_data; unsigned long flags; - int status; pr_vdebug("gs_write: ttyGS%d (%p) writing %d bytes\n", port->port_num, tty, count); @@ -917,7 +921,7 @@ static int gs_write(struct tty_struct *tty, const unsigned char *buf, int count) count = gs_buf_put(&port->port_write_buf, buf, count); /* treat count == 0 as flush_chars() */ if (port->port_usb) - status = gs_start_tx(port); + gs_start_tx(port); spin_unlock_irqrestore(&port->port_lock, flags); return count; diff --git a/drivers/usb/gadget/function/uvc_configfs.c b/drivers/usb/gadget/function/uvc_configfs.c index 66753ba7a..31125a4a2 100644 --- a/drivers/usb/gadget/function/uvc_configfs.c +++ b/drivers/usb/gadget/function/uvc_configfs.c @@ -2023,7 +2023,7 @@ static int uvcg_streaming_class_allow_link(struct config_item *src, if (!data) { kfree(*class_array); *class_array = NULL; - ret = PTR_ERR(data); + ret = -ENOMEM; goto unlock; } cl_arr = *class_array; diff --git a/drivers/usb/gadget/function/uvc_queue.c b/drivers/usb/gadget/function/uvc_queue.c index 912694f3d..6377e9fee 100644 --- a/drivers/usb/gadget/function/uvc_queue.c +++ b/drivers/usb/gadget/function/uvc_queue.c @@ -43,7 +43,7 @@ static int uvc_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, unsigned int *nplanes, - unsigned int sizes[], void *alloc_ctxs[]) + unsigned int sizes[], struct device *alloc_devs[]) { struct uvc_video_queue *queue = vb2_get_drv_priv(vq); struct uvc_video *video = container_of(queue, struct uvc_video, queue); -- cgit v1.2.3-54-g00ecf