diff options
author | Jack Pham <jackp@codeaurora.org> | 2018-01-25 02:58:20 -0500 |
---|---|---|
committer | Felipe Balbi <felipe.balbi@linux.intel.com> | 2018-02-12 03:52:54 -0500 |
commit | 675272d092e4a5570bace92593776f7348daf4c5 (patch) | |
tree | 319e0dd41ec839dfe0dcc4185879060e6f9287d7 | |
parent | 6cf439e0d37463e42784271179c8a308fd7493c6 (diff) |
usb: gadget: f_fs: Use config_ep_by_speed()
In commit 2bfa0719ac2a ("usb: gadget: function: f_fs: pass
companion descriptor along") there is a pointer arithmetic
bug where the comp_desc is obtained as follows:
comp_desc = (struct usb_ss_ep_comp_descriptor *)(ds +
USB_DT_ENDPOINT_SIZE);
Since ds is a pointer to usb_endpoint_descriptor, adding
7 to it ends up going out of bounds (7 * sizeof(struct
usb_endpoint_descriptor), which is actually 7*9 bytes) past
the SS descriptor. As a result the maxburst value will be
read incorrectly, and the UDC driver will also get a garbage
comp_desc (assuming it uses it).
Since Felipe wrote, "Eventually, f_fs.c should be converted
to use config_ep_by_speed() like all other functions, though",
let's finally do it. This allows the other usb_ep fields to
be properly populated, such as maxpacket and mult. It also
eliminates the awkward speed-based descriptor lookup since
config_ep_by_speed() does that already using the ones found
in struct usb_function.
Fixes: 2bfa0719ac2a ("usb: gadget: function: f_fs: pass companion descriptor along")
Cc: stable@vger.kernel.org
Signed-off-by: Jack Pham <jackp@codeaurora.org>
Signed-off-by: Felipe Balbi <felipe.balbi@linux.intel.com>
-rw-r--r-- | drivers/usb/gadget/function/f_fs.c | 38 |
1 files changed, 7 insertions, 31 deletions
diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c index 49fc589fbf58..c2592d883f67 100644 --- a/drivers/usb/gadget/function/f_fs.c +++ b/drivers/usb/gadget/function/f_fs.c | |||
@@ -1855,44 +1855,20 @@ static int ffs_func_eps_enable(struct ffs_function *func) | |||
1855 | 1855 | ||
1856 | spin_lock_irqsave(&func->ffs->eps_lock, flags); | 1856 | spin_lock_irqsave(&func->ffs->eps_lock, flags); |
1857 | while(count--) { | 1857 | while(count--) { |
1858 | struct usb_endpoint_descriptor *ds; | ||
1859 | struct usb_ss_ep_comp_descriptor *comp_desc = NULL; | ||
1860 | int needs_comp_desc = false; | ||
1861 | int desc_idx; | ||
1862 | |||
1863 | if (ffs->gadget->speed == USB_SPEED_SUPER) { | ||
1864 | desc_idx = 2; | ||
1865 | needs_comp_desc = true; | ||
1866 | } else if (ffs->gadget->speed == USB_SPEED_HIGH) | ||
1867 | desc_idx = 1; | ||
1868 | else | ||
1869 | desc_idx = 0; | ||
1870 | |||
1871 | /* fall-back to lower speed if desc missing for current speed */ | ||
1872 | do { | ||
1873 | ds = ep->descs[desc_idx]; | ||
1874 | } while (!ds && --desc_idx >= 0); | ||
1875 | |||
1876 | if (!ds) { | ||
1877 | ret = -EINVAL; | ||
1878 | break; | ||
1879 | } | ||
1880 | |||
1881 | ep->ep->driver_data = ep; | 1858 | ep->ep->driver_data = ep; |
1882 | ep->ep->desc = ds; | ||
1883 | 1859 | ||
1884 | if (needs_comp_desc) { | 1860 | ret = config_ep_by_speed(func->gadget, &func->function, ep->ep); |
1885 | comp_desc = (struct usb_ss_ep_comp_descriptor *)(ds + | 1861 | if (ret) { |
1886 | USB_DT_ENDPOINT_SIZE); | 1862 | pr_err("%s: config_ep_by_speed(%s) returned %d\n", |
1887 | ep->ep->maxburst = comp_desc->bMaxBurst + 1; | 1863 | __func__, ep->ep->name, ret); |
1888 | ep->ep->comp_desc = comp_desc; | 1864 | break; |
1889 | } | 1865 | } |
1890 | 1866 | ||
1891 | ret = usb_ep_enable(ep->ep); | 1867 | ret = usb_ep_enable(ep->ep); |
1892 | if (likely(!ret)) { | 1868 | if (likely(!ret)) { |
1893 | epfile->ep = ep; | 1869 | epfile->ep = ep; |
1894 | epfile->in = usb_endpoint_dir_in(ds); | 1870 | epfile->in = usb_endpoint_dir_in(ep->ep->desc); |
1895 | epfile->isoc = usb_endpoint_xfer_isoc(ds); | 1871 | epfile->isoc = usb_endpoint_xfer_isoc(ep->ep->desc); |
1896 | } else { | 1872 | } else { |
1897 | break; | 1873 | break; |
1898 | } | 1874 | } |