From ad57410d231da1fff3f53ff42ebcdc6d388e21d1 Mon Sep 17 00:00:00 2001 From: Ray Hung Date: Thu, 4 Aug 2022 19:08:36 +0800 Subject: usb: gadget: rndis: use %u instead of %d to print u32 values The driver uses the %d format to print u32 values. The correct format is %u. Fix it. Signed-off-by: Ray Hung Link: https://lore.kernel.org/r/20220804110836.138614-1-tw.rayhung@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/function/rndis.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/usb/gadget/function') diff --git a/drivers/usb/gadget/function/rndis.c b/drivers/usb/gadget/function/rndis.c index 713efd9aefde..10ba339bcea4 100644 --- a/drivers/usb/gadget/function/rndis.c +++ b/drivers/usb/gadget/function/rndis.c @@ -1105,7 +1105,7 @@ static int rndis_proc_show(struct seq_file *m, void *v) "used : %s\n" "state : %s\n" "medium : 0x%08X\n" - "speed : %d\n" + "speed : %u\n" "cable : %s\n" "vendor ID : 0x%08X\n" "vendor : %s\n", -- cgit v1.2.3 From c4c2fac94dd04d982676278123affdeb11c32a72 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 10 Aug 2022 14:36:56 +0200 Subject: USB: gadget: f_mass_storage: get rid of DEVICE_ATTR() usage The last holdout in the drivers/usb/* tree using DEVICE_ATTR() is the f_mass_storage driver, so move it to use DEVICE_ATTR_RW() instead. The mode is overridden in the is_visible callback to set it properly depending on if this is a cdrom or removable device. Cc: Felipe Balbi Cc: Alan Stern Cc: Maxim Devaev Cc: Wesley Cheng Cc: Neal Liu Cc: Roger Quadros Cc: Nikita Yushchenko Cc: Cai Huoqing Link: https://lore.kernel.org/r/20220810123656.3637104-1-gregkh@linuxfoundation.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/function/f_mass_storage.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'drivers/usb/gadget/function') diff --git a/drivers/usb/gadget/function/f_mass_storage.c b/drivers/usb/gadget/function/f_mass_storage.c index 925e99f9775c..3abf7f586e2a 100644 --- a/drivers/usb/gadget/function/f_mass_storage.c +++ b/drivers/usb/gadget/function/f_mass_storage.c @@ -2662,11 +2662,16 @@ static ssize_t forced_eject_store(struct device *dev, } static DEVICE_ATTR_RW(nofua); -/* mode wil be set in fsg_lun_attr_is_visible() */ -static DEVICE_ATTR(ro, 0, ro_show, ro_store); -static DEVICE_ATTR(file, 0, file_show, file_store); static DEVICE_ATTR_WO(forced_eject); +/* + * Mode of the ro and file attribute files will be overridden in + * fsg_lun_dev_is_visible() depending on if this is a cdrom, or if it is a + * removable device. + */ +static DEVICE_ATTR_RW(ro); +static DEVICE_ATTR_RW(file); + /****************************** FSG COMMON ******************************/ static void fsg_lun_release(struct device *dev) -- cgit v1.2.3 From b7db5733a5ace9acc1f3104c9050c5aa1363f13b Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 18 Aug 2022 23:01:15 +0200 Subject: usb: move from strlcpy with unused retval to strscpy Follow the advice of the below link and prefer 'strscpy' in this subsystem. Conversion is 1:1 because the return value is not used. Generated by a coccinelle script. Link: https://lore.kernel.org/r/CAHk-=wgfRnXz0W3D37d01q3JFkr_i_uTL=V6A6G1oUZcprmknw@mail.gmail.com/ Reviewed-by: Richard Leitner Reviewed-by: Laurent Pinchart Acked-by: Shuah Khan Signed-off-by: Wolfram Sang Link: https://lore.kernel.org/r/20220818210116.7517-1-wsa+renesas@sang-engineering.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/atm/usbatm.c | 2 +- drivers/usb/core/devio.c | 2 +- drivers/usb/gadget/function/f_fs.c | 2 +- drivers/usb/gadget/function/f_uvc.c | 2 +- drivers/usb/gadget/function/u_ether.c | 8 ++++---- drivers/usb/gadget/function/uvc_v4l2.c | 6 +++--- drivers/usb/gadget/udc/omap_udc.c | 2 +- drivers/usb/misc/usb251xb.c | 6 +++--- drivers/usb/storage/onetouch.c | 2 +- drivers/usb/typec/tcpm/fusb302.c | 2 +- drivers/usb/usbip/stub_main.c | 2 +- 11 files changed, 18 insertions(+), 18 deletions(-) (limited to 'drivers/usb/gadget/function') diff --git a/drivers/usb/atm/usbatm.c b/drivers/usb/atm/usbatm.c index 362217189ef3..1cdb8758ae01 100644 --- a/drivers/usb/atm/usbatm.c +++ b/drivers/usb/atm/usbatm.c @@ -1026,7 +1026,7 @@ int usbatm_usb_probe(struct usb_interface *intf, const struct usb_device_id *id, /* public fields */ instance->driver = driver; - strlcpy(instance->driver_name, driver->driver_name, + strscpy(instance->driver_name, driver->driver_name, sizeof(instance->driver_name)); instance->usb_dev = usb_dev; diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index b5b85bf80329..837f3e57f580 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -1434,7 +1434,7 @@ static int proc_getdriver(struct usb_dev_state *ps, void __user *arg) if (!intf || !intf->dev.driver) ret = -ENODATA; else { - strlcpy(gd.driver, intf->dev.driver->name, + strscpy(gd.driver, intf->dev.driver->name, sizeof(gd.driver)); ret = (copy_to_user(arg, &gd, sizeof(gd)) ? -EFAULT : 0); } diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c index e0fa4b186ec6..98dc2291e9a1 100644 --- a/drivers/usb/gadget/function/f_fs.c +++ b/drivers/usb/gadget/function/f_fs.c @@ -3700,7 +3700,7 @@ int ffs_name_dev(struct ffs_dev *dev, const char *name) existing = _ffs_do_find_dev(name); if (!existing) - strlcpy(dev->name, name, ARRAY_SIZE(dev->name)); + strscpy(dev->name, name, ARRAY_SIZE(dev->name)); else if (existing != dev) ret = -EBUSY; diff --git a/drivers/usb/gadget/function/f_uvc.c b/drivers/usb/gadget/function/f_uvc.c index 71669e0e4d00..f4f6cf75930b 100644 --- a/drivers/usb/gadget/function/f_uvc.c +++ b/drivers/usb/gadget/function/f_uvc.c @@ -430,7 +430,7 @@ uvc_register_video(struct uvc_device *uvc) uvc->vdev.vfl_dir = VFL_DIR_TX; uvc->vdev.lock = &uvc->video.mutex; uvc->vdev.device_caps = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING; - strlcpy(uvc->vdev.name, cdev->gadget->name, sizeof(uvc->vdev.name)); + strscpy(uvc->vdev.name, cdev->gadget->name, sizeof(uvc->vdev.name)); video_set_drvdata(&uvc->vdev, uvc); diff --git a/drivers/usb/gadget/function/u_ether.c b/drivers/usb/gadget/function/u_ether.c index 7887def05dc2..e06022873df1 100644 --- a/drivers/usb/gadget/function/u_ether.c +++ b/drivers/usb/gadget/function/u_ether.c @@ -144,10 +144,10 @@ static void eth_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *p) { struct eth_dev *dev = netdev_priv(net); - strlcpy(p->driver, "g_ether", sizeof(p->driver)); - strlcpy(p->version, UETH__VERSION, sizeof(p->version)); - strlcpy(p->fw_version, dev->gadget->name, sizeof(p->fw_version)); - strlcpy(p->bus_info, dev_name(&dev->gadget->dev), sizeof(p->bus_info)); + strscpy(p->driver, "g_ether", sizeof(p->driver)); + strscpy(p->version, UETH__VERSION, sizeof(p->version)); + strscpy(p->fw_version, dev->gadget->name, sizeof(p->fw_version)); + strscpy(p->bus_info, dev_name(&dev->gadget->dev), sizeof(p->bus_info)); } /* REVISIT can also support: diff --git a/drivers/usb/gadget/function/uvc_v4l2.c b/drivers/usb/gadget/function/uvc_v4l2.c index fd8f73bb726d..511f106f9843 100644 --- a/drivers/usb/gadget/function/uvc_v4l2.c +++ b/drivers/usb/gadget/function/uvc_v4l2.c @@ -67,9 +67,9 @@ uvc_v4l2_querycap(struct file *file, void *fh, struct v4l2_capability *cap) struct uvc_device *uvc = video_get_drvdata(vdev); struct usb_composite_dev *cdev = uvc->func.config->cdev; - strlcpy(cap->driver, "g_uvc", sizeof(cap->driver)); - strlcpy(cap->card, cdev->gadget->name, sizeof(cap->card)); - strlcpy(cap->bus_info, dev_name(&cdev->gadget->dev), + strscpy(cap->driver, "g_uvc", sizeof(cap->driver)); + strscpy(cap->card, cdev->gadget->name, sizeof(cap->card)); + strscpy(cap->bus_info, dev_name(&cdev->gadget->dev), sizeof(cap->bus_info)); return 0; } diff --git a/drivers/usb/gadget/udc/omap_udc.c b/drivers/usb/gadget/udc/omap_udc.c index 61cabb9de6ae..b0567c63d754 100644 --- a/drivers/usb/gadget/udc/omap_udc.c +++ b/drivers/usb/gadget/udc/omap_udc.c @@ -2558,7 +2558,7 @@ omap_ep_setup(char *name, u8 addr, u8 type, /* set up driver data structures */ BUG_ON(strlen(name) >= sizeof ep->name); - strlcpy(ep->name, name, sizeof ep->name); + strscpy(ep->name, name, sizeof(ep->name)); INIT_LIST_HEAD(&ep->queue); INIT_LIST_HEAD(&ep->iso); ep->bEndpointAddress = addr; diff --git a/drivers/usb/misc/usb251xb.c b/drivers/usb/misc/usb251xb.c index 04c4e3fed094..87035ac09834 100644 --- a/drivers/usb/misc/usb251xb.c +++ b/drivers/usb/misc/usb251xb.c @@ -547,7 +547,7 @@ static int usb251xb_get_ofdata(struct usb251xb *hub, hub->boost_up = USB251XB_DEF_BOOST_UP; cproperty_char = of_get_property(np, "manufacturer", NULL); - strlcpy(str, cproperty_char ? : USB251XB_DEF_MANUFACTURER_STRING, + strscpy(str, cproperty_char ? : USB251XB_DEF_MANUFACTURER_STRING, sizeof(str)); hub->manufacturer_len = strlen(str) & 0xFF; memset(hub->manufacturer, 0, USB251XB_STRING_BUFSIZE); @@ -557,7 +557,7 @@ static int usb251xb_get_ofdata(struct usb251xb *hub, USB251XB_STRING_BUFSIZE); cproperty_char = of_get_property(np, "product", NULL); - strlcpy(str, cproperty_char ? : data->product_str, sizeof(str)); + strscpy(str, cproperty_char ? : data->product_str, sizeof(str)); hub->product_len = strlen(str) & 0xFF; memset(hub->product, 0, USB251XB_STRING_BUFSIZE); len = min_t(size_t, USB251XB_STRING_BUFSIZE / 2, strlen(str)); @@ -566,7 +566,7 @@ static int usb251xb_get_ofdata(struct usb251xb *hub, USB251XB_STRING_BUFSIZE); cproperty_char = of_get_property(np, "serial", NULL); - strlcpy(str, cproperty_char ? : USB251XB_DEF_SERIAL_STRING, + strscpy(str, cproperty_char ? : USB251XB_DEF_SERIAL_STRING, sizeof(str)); hub->serial_len = strlen(str) & 0xFF; memset(hub->serial, 0, USB251XB_STRING_BUFSIZE); diff --git a/drivers/usb/storage/onetouch.c b/drivers/usb/storage/onetouch.c index 1db2eefeea22..01f3c2779ccf 100644 --- a/drivers/usb/storage/onetouch.c +++ b/drivers/usb/storage/onetouch.c @@ -201,7 +201,7 @@ static int onetouch_connect_input(struct us_data *ss) onetouch->dev = input_dev; if (udev->manufacturer) - strlcpy(onetouch->name, udev->manufacturer, + strscpy(onetouch->name, udev->manufacturer, sizeof(onetouch->name)); if (udev->product) { if (udev->manufacturer) diff --git a/drivers/usb/typec/tcpm/fusb302.c b/drivers/usb/typec/tcpm/fusb302.c index 96c55eaf3f80..ab89c014606e 100644 --- a/drivers/usb/typec/tcpm/fusb302.c +++ b/drivers/usb/typec/tcpm/fusb302.c @@ -151,7 +151,7 @@ static void _fusb302_log(struct fusb302_chip *chip, const char *fmt, if (fusb302_log_full(chip)) { chip->logbuffer_head = max(chip->logbuffer_head - 1, 0); - strlcpy(tmpbuffer, "overflow", sizeof(tmpbuffer)); + strscpy(tmpbuffer, "overflow", sizeof(tmpbuffer)); } if (chip->logbuffer_head < 0 || diff --git a/drivers/usb/usbip/stub_main.c b/drivers/usb/usbip/stub_main.c index 77a5b3f8736a..e8c3131a8543 100644 --- a/drivers/usb/usbip/stub_main.c +++ b/drivers/usb/usbip/stub_main.c @@ -100,7 +100,7 @@ static int add_match_busid(char *busid) for (i = 0; i < MAX_BUSID; i++) { spin_lock(&busid_table[i].busid_lock); if (!busid_table[i].name[0]) { - strlcpy(busid_table[i].name, busid, BUSID_SIZE); + strscpy(busid_table[i].name, busid, BUSID_SIZE); if ((busid_table[i].status != STUB_BUSID_ALLOC) && (busid_table[i].status != STUB_BUSID_REMOV)) busid_table[i].status = STUB_BUSID_ADDED; -- cgit v1.2.3 From f1e8a41c6cd590a4deb23c37c547932395a99053 Mon Sep 17 00:00:00 2001 From: Maciej Żenczykowski Date: Sun, 21 Aug 2022 07:57:45 -0700 Subject: usb: gadget: f_ncm: noop - remove INIT_NDP{16,32}_OPTS macros MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit these are only used in one place, a few lines lower Cc: Brooke Basile Cc: "Bryan O'Donoghue" Cc: Felipe Balbi Cc: Greg Kroah-Hartman Cc: Lorenzo Colitti Signed-off-by: Maciej Żenczykowski Link: https://lore.kernel.org/r/20220821145745.122587-1-zenczykowski@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/function/f_ncm.c | 60 +++++++++++++++++-------------------- 1 file changed, 28 insertions(+), 32 deletions(-) (limited to 'drivers/usb/gadget/function') diff --git a/drivers/usb/gadget/function/f_ncm.c b/drivers/usb/gadget/function/f_ncm.c index dc8f078f918c..c36bcfa0e9b4 100644 --- a/drivers/usb/gadget/function/f_ncm.c +++ b/drivers/usb/gadget/function/f_ncm.c @@ -450,39 +450,35 @@ struct ndp_parser_opts { unsigned next_ndp_index; }; -#define INIT_NDP16_OPTS { \ - .nth_sign = USB_CDC_NCM_NTH16_SIGN, \ - .ndp_sign = USB_CDC_NCM_NDP16_NOCRC_SIGN, \ - .nth_size = sizeof(struct usb_cdc_ncm_nth16), \ - .ndp_size = sizeof(struct usb_cdc_ncm_ndp16), \ - .dpe_size = sizeof(struct usb_cdc_ncm_dpe16), \ - .ndplen_align = 4, \ - .dgram_item_len = 1, \ - .block_length = 1, \ - .ndp_index = 1, \ - .reserved1 = 0, \ - .reserved2 = 0, \ - .next_ndp_index = 1, \ - } - - -#define INIT_NDP32_OPTS { \ - .nth_sign = USB_CDC_NCM_NTH32_SIGN, \ - .ndp_sign = USB_CDC_NCM_NDP32_NOCRC_SIGN, \ - .nth_size = sizeof(struct usb_cdc_ncm_nth32), \ - .ndp_size = sizeof(struct usb_cdc_ncm_ndp32), \ - .dpe_size = sizeof(struct usb_cdc_ncm_dpe32), \ - .ndplen_align = 8, \ - .dgram_item_len = 2, \ - .block_length = 2, \ - .ndp_index = 2, \ - .reserved1 = 1, \ - .reserved2 = 2, \ - .next_ndp_index = 2, \ - } +static const struct ndp_parser_opts ndp16_opts = { + .nth_sign = USB_CDC_NCM_NTH16_SIGN, + .ndp_sign = USB_CDC_NCM_NDP16_NOCRC_SIGN, + .nth_size = sizeof(struct usb_cdc_ncm_nth16), + .ndp_size = sizeof(struct usb_cdc_ncm_ndp16), + .dpe_size = sizeof(struct usb_cdc_ncm_dpe16), + .ndplen_align = 4, + .dgram_item_len = 1, + .block_length = 1, + .ndp_index = 1, + .reserved1 = 0, + .reserved2 = 0, + .next_ndp_index = 1, +}; -static const struct ndp_parser_opts ndp16_opts = INIT_NDP16_OPTS; -static const struct ndp_parser_opts ndp32_opts = INIT_NDP32_OPTS; +static const struct ndp_parser_opts ndp32_opts = { + .nth_sign = USB_CDC_NCM_NTH32_SIGN, + .ndp_sign = USB_CDC_NCM_NDP32_NOCRC_SIGN, + .nth_size = sizeof(struct usb_cdc_ncm_nth32), + .ndp_size = sizeof(struct usb_cdc_ncm_ndp32), + .dpe_size = sizeof(struct usb_cdc_ncm_dpe32), + .ndplen_align = 8, + .dgram_item_len = 2, + .block_length = 2, + .ndp_index = 2, + .reserved1 = 1, + .reserved2 = 2, + .next_ndp_index = 2, +}; static inline void put_ncm(__le16 **p, unsigned size, unsigned val) { -- cgit v1.2.3 From 4348f2e3ab3358898bfe93387ced7f3e1e3a6186 Mon Sep 17 00:00:00 2001 From: Sergey Shtylyov Date: Tue, 23 Aug 2022 23:53:26 +0300 Subject: usb: gadget: function: rndis: limit # of RNDIS instances to 1000 As follows from #define NAME_TEMPLATE, the procfs code in the RNDIS driver expects the # of instances to be 3-digit decimal, while the driver calls ida_simple_get() passing 0 as the 'end' argument which results in actual max instance # of INT_MAX. Limit the maximum # of RNDIS instances to 1000 which is still a lot! :-) Found by Linux Verification Center (linuxtesting.org) with the SVACE static analysis tool. Signed-off-by: Sergey Shtylyov Link: https://lore.kernel.org/r/a8180973-3ded-3644-585a-169589a37642@omp.ru Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/function/rndis.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/usb/gadget/function') diff --git a/drivers/usb/gadget/function/rndis.c b/drivers/usb/gadget/function/rndis.c index 10ba339bcea4..29bf8664bf58 100644 --- a/drivers/usb/gadget/function/rndis.c +++ b/drivers/usb/gadget/function/rndis.c @@ -869,7 +869,7 @@ EXPORT_SYMBOL_GPL(rndis_msg_parser); static inline int rndis_get_nr(void) { - return ida_simple_get(&rndis_ida, 0, 0, GFP_KERNEL); + return ida_simple_get(&rndis_ida, 0, 1000, GFP_KERNEL); } static inline void rndis_put_nr(int nr) -- cgit v1.2.3 From f57004b9d96755cd6a243b51c267be4016b4563c Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 1 Sep 2022 17:59:42 +0300 Subject: usb: gadget: f_fs: stricter integer overflow checks This from static analysis. The vla_item() takes a size and adds it to the total. It has a built in integer overflow check so if it encounters an integer overflow anywhere then it records the total as SIZE_MAX. However there is an issue here because the "lang_count*(needed_count+1)" multiplication can overflow. Technically the "lang_count + 1" addition could overflow too, but that would be detected and is harmless. Fix both using the new size_add() and size_mul() functions. Fixes: e6f3862fa1ec ("usb: gadget: FunctionFS: Remove VLAIS usage from gadget code") Signed-off-by: Dan Carpenter Link: https://lore.kernel.org/r/YxDI3lMYomE7WCjn@kili Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/function/f_fs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/usb/gadget/function') diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c index 98dc2291e9a1..73dc10a77cde 100644 --- a/drivers/usb/gadget/function/f_fs.c +++ b/drivers/usb/gadget/function/f_fs.c @@ -2645,10 +2645,10 @@ static int __ffs_data_got_strings(struct ffs_data *ffs, unsigned i = 0; vla_group(d); vla_item(d, struct usb_gadget_strings *, stringtabs, - lang_count + 1); + size_add(lang_count, 1)); vla_item(d, struct usb_gadget_strings, stringtab, lang_count); vla_item(d, struct usb_string, strings, - lang_count*(needed_count+1)); + size_mul(lang_count, (needed_count + 1))); char *vlabuf = kmalloc(vla_group_size(d), GFP_KERNEL); -- cgit v1.2.3 From 9b91a65230784a9ef644b8bdbb82a79ba4ae9456 Mon Sep 17 00:00:00 2001 From: Michael Grzeschik Date: Wed, 7 Sep 2022 23:58:18 +0200 Subject: usb: gadget: uvc: increase worker prio to WQ_HIGHPRI This patch is changing the simple workqueue in the gadget driver to be allocated as async_wq with a higher priority. The pump worker, that is filling the usb requests, will have a higher priority and will not be scheduled away so often while the video stream is handled. This will lead to fewer streaming underruns. Signed-off-by: Michael Grzeschik Link: https://lore.kernel.org/r/20220907215818.2670097-1-m.grzeschik@pengutronix.de Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/function/f_uvc.c | 4 ++++ drivers/usb/gadget/function/uvc.h | 1 + drivers/usb/gadget/function/uvc_v4l2.c | 2 +- drivers/usb/gadget/function/uvc_video.c | 9 +++++++-- 4 files changed, 13 insertions(+), 3 deletions(-) (limited to 'drivers/usb/gadget/function') diff --git a/drivers/usb/gadget/function/f_uvc.c b/drivers/usb/gadget/function/f_uvc.c index f4f6cf75930b..09961f4ca981 100644 --- a/drivers/usb/gadget/function/f_uvc.c +++ b/drivers/usb/gadget/function/f_uvc.c @@ -897,10 +897,14 @@ static void uvc_function_unbind(struct usb_configuration *c, { struct usb_composite_dev *cdev = c->cdev; struct uvc_device *uvc = to_uvc(f); + struct uvc_video *video = &uvc->video; long wait_ret = 1; uvcg_info(f, "%s()\n", __func__); + if (video->async_wq) + destroy_workqueue(video->async_wq); + /* * If we know we're connected via v4l2, then there should be a cleanup * of the device from userspace either via UVC_EVENT_DISCONNECT or diff --git a/drivers/usb/gadget/function/uvc.h b/drivers/usb/gadget/function/uvc.h index 58e383afdd44..1a31e6c6a5ff 100644 --- a/drivers/usb/gadget/function/uvc.h +++ b/drivers/usb/gadget/function/uvc.h @@ -88,6 +88,7 @@ struct uvc_video { struct usb_ep *ep; struct work_struct pump; + struct workqueue_struct *async_wq; /* Frame parameters */ u8 bpp; diff --git a/drivers/usb/gadget/function/uvc_v4l2.c b/drivers/usb/gadget/function/uvc_v4l2.c index 511f106f9843..d6dbf9b763b2 100644 --- a/drivers/usb/gadget/function/uvc_v4l2.c +++ b/drivers/usb/gadget/function/uvc_v4l2.c @@ -170,7 +170,7 @@ uvc_v4l2_qbuf(struct file *file, void *fh, struct v4l2_buffer *b) return ret; if (uvc->state == UVC_STATE_STREAMING) - schedule_work(&video->pump); + queue_work(video->async_wq, &video->pump); return ret; } diff --git a/drivers/usb/gadget/function/uvc_video.c b/drivers/usb/gadget/function/uvc_video.c index c00ce0e91f5d..bb037fcc90e6 100644 --- a/drivers/usb/gadget/function/uvc_video.c +++ b/drivers/usb/gadget/function/uvc_video.c @@ -277,7 +277,7 @@ uvc_video_complete(struct usb_ep *ep, struct usb_request *req) spin_unlock_irqrestore(&video->req_lock, flags); if (uvc->state == UVC_STATE_STREAMING) - schedule_work(&video->pump); + queue_work(video->async_wq, &video->pump); } static int @@ -485,7 +485,7 @@ int uvcg_video_enable(struct uvc_video *video, int enable) video->req_int_count = 0; - schedule_work(&video->pump); + queue_work(video->async_wq, &video->pump); return ret; } @@ -499,6 +499,11 @@ int uvcg_video_init(struct uvc_video *video, struct uvc_device *uvc) spin_lock_init(&video->req_lock); INIT_WORK(&video->pump, uvcg_video_pump); + /* Allocate a work queue for asynchronous video pump handler. */ + video->async_wq = alloc_workqueue("uvcgadget", WQ_UNBOUND | WQ_HIGHPRI, 0); + if (!video->async_wq) + return -EINVAL; + video->uvc = uvc; video->fcc = V4L2_PIX_FMT_YUYV; video->bpp = 16; -- cgit v1.2.3 From 24b7ba2f88e04800b54d462f376512e8c41b8a3c Mon Sep 17 00:00:00 2001 From: Albert Briscoe Date: Sun, 11 Sep 2022 15:37:55 -0700 Subject: usb: gadget: function: fix dangling pnp_string in f_printer.c When opts->pnp_string is changed with configfs, new memory is allocated for the string. It does not, however, update dev->pnp_string, even though the memory is freed. When rquesting the string, the host then gets old or corrupted data rather than the new string. The ieee 1284 id string should be allowed to change while the device is connected. The bug was introduced in commit fdc01cc286be ("usb: gadget: printer: Remove pnp_string static buffer"), which changed opts->pnp_string from a char[] to a char*. This patch changes dev->pnp_string from a char* to a char** pointing to opts->pnp_string. Fixes: fdc01cc286be ("usb: gadget: printer: Remove pnp_string static buffer") Signed-off-by: Albert Briscoe Link: https://lore.kernel.org/r/20220911223753.20417-1-albertsbriscoe@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/function/f_printer.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/usb/gadget/function') diff --git a/drivers/usb/gadget/function/f_printer.c b/drivers/usb/gadget/function/f_printer.c index abec5c58f525..a881c69b1f2b 100644 --- a/drivers/usb/gadget/function/f_printer.c +++ b/drivers/usb/gadget/function/f_printer.c @@ -89,7 +89,7 @@ struct printer_dev { u8 printer_cdev_open; wait_queue_head_t wait; unsigned q_len; - char *pnp_string; /* We don't own memory! */ + char **pnp_string; /* We don't own memory! */ struct usb_function function; }; @@ -1000,16 +1000,16 @@ static int printer_func_setup(struct usb_function *f, if ((wIndex>>8) != dev->interface) break; - if (!dev->pnp_string) { + if (!*dev->pnp_string) { value = 0; break; } - value = strlen(dev->pnp_string); + value = strlen(*dev->pnp_string); buf[0] = (value >> 8) & 0xFF; buf[1] = value & 0xFF; - memcpy(buf + 2, dev->pnp_string, value); + memcpy(buf + 2, *dev->pnp_string, value); DBG(dev, "1284 PNP String: %x %s\n", value, - dev->pnp_string); + *dev->pnp_string); break; case GET_PORT_STATUS: /* Get Port Status */ @@ -1475,7 +1475,7 @@ static struct usb_function *gprinter_alloc(struct usb_function_instance *fi) kref_init(&dev->kref); ++opts->refcnt; dev->minor = opts->minor; - dev->pnp_string = opts->pnp_string; + dev->pnp_string = &opts->pnp_string; dev->q_len = opts->q_len; mutex_unlock(&opts->lock); -- cgit v1.2.3 From 7489ec86bcb3830d3bd161365da425fd28d6382f Mon Sep 17 00:00:00 2001 From: Xiu Jianfeng Date: Sat, 17 Sep 2022 16:44:13 +0800 Subject: usb: gadget: add _init/__exit annotations to module init/exit funcs Add missing _init/__exit annotations to module init/exit funcs. Signed-off-by: Xiu Jianfeng Link: https://lore.kernel.org/r/20220917084413.23957-1-xiujianfeng@huawei.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/function/f_tcm.c | 4 ++-- drivers/usb/gadget/function/u_serial.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/usb/gadget/function') diff --git a/drivers/usb/gadget/function/f_tcm.c b/drivers/usb/gadget/function/f_tcm.c index 8e17ac831be0..658e2e21fdd0 100644 --- a/drivers/usb/gadget/function/f_tcm.c +++ b/drivers/usb/gadget/function/f_tcm.c @@ -2306,7 +2306,7 @@ static struct usb_function *tcm_alloc(struct usb_function_instance *fi) DECLARE_USB_FUNCTION(tcm, tcm_alloc_inst, tcm_alloc); -static int tcm_init(void) +static int __init tcm_init(void) { int ret; @@ -2322,7 +2322,7 @@ static int tcm_init(void) } module_init(tcm_init); -static void tcm_exit(void) +static void __exit tcm_exit(void) { target_unregister_template(&usbg_ops); usb_function_unregister(&tcmusb_func); diff --git a/drivers/usb/gadget/function/u_serial.c b/drivers/usb/gadget/function/u_serial.c index 6f68cbeeee7c..7538279f9817 100644 --- a/drivers/usb/gadget/function/u_serial.c +++ b/drivers/usb/gadget/function/u_serial.c @@ -1443,7 +1443,7 @@ void gserial_resume(struct gserial *gser) } EXPORT_SYMBOL_GPL(gserial_resume); -static int userial_init(void) +static int __init userial_init(void) { struct tty_driver *driver; unsigned i; @@ -1496,7 +1496,7 @@ fail: } module_init(userial_init); -static void userial_cleanup(void) +static void __exit userial_cleanup(void) { tty_unregister_driver(gs_tty_driver); tty_driver_kref_put(gs_tty_driver); -- cgit v1.2.3 From 588b9e85609bcb2f84a2be83591480aa943943b6 Mon Sep 17 00:00:00 2001 From: Michael Grzeschik Date: Sat, 10 Sep 2022 00:13:34 +0200 Subject: usb: gadget: uvc: add v4l2 enumeration api calls This patch adds support to the v4l2 VIDIOCs for enum_format, enum_framesizes and enum_frameintervals. This way, the userspace application can use these VIDIOCS to query the via configfs exported frame capabilities. With thes callbacks the userspace doesn't have to bring its own configfs parser. Signed-off-by: Michael Grzeschik Link: https://lore.kernel.org/r/20220909221335.15033-4-m.grzeschik@pengutronix.de Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/function/f_uvc.c | 30 ++++++ drivers/usb/gadget/function/uvc.h | 2 + drivers/usb/gadget/function/uvc_v4l2.c | 176 +++++++++++++++++++++++++++++++++ 3 files changed, 208 insertions(+) (limited to 'drivers/usb/gadget/function') diff --git a/drivers/usb/gadget/function/f_uvc.c b/drivers/usb/gadget/function/f_uvc.c index 09961f4ca981..e6948cf8def3 100644 --- a/drivers/usb/gadget/function/f_uvc.c +++ b/drivers/usb/gadget/function/f_uvc.c @@ -888,6 +888,7 @@ static void uvc_free(struct usb_function *f) struct uvc_device *uvc = to_uvc(f); struct f_uvc_opts *opts = container_of(f->fi, struct f_uvc_opts, func_inst); + config_item_put(&uvc->header->item); --opts->refcnt; kfree(uvc); } @@ -945,6 +946,7 @@ static struct usb_function *uvc_alloc(struct usb_function_instance *fi) struct uvc_device *uvc; struct f_uvc_opts *opts; struct uvc_descriptor_header **strm_cls; + struct config_item *streaming, *header, *h; uvc = kzalloc(sizeof(*uvc), GFP_KERNEL); if (uvc == NULL) @@ -977,6 +979,29 @@ static struct usb_function *uvc_alloc(struct usb_function_instance *fi) uvc->desc.fs_streaming = opts->fs_streaming; uvc->desc.hs_streaming = opts->hs_streaming; uvc->desc.ss_streaming = opts->ss_streaming; + + streaming = config_group_find_item(&opts->func_inst.group, "streaming"); + if (!streaming) + goto err_config; + + header = config_group_find_item(to_config_group(streaming), "header"); + config_item_put(streaming); + if (!header) + goto err_config; + + h = config_group_find_item(to_config_group(header), "h"); + config_item_put(header); + if (!h) + goto err_config; + + uvc->header = to_uvcg_streaming_header(h); + config_item_put(h); + if (!uvc->header->linked) { + mutex_unlock(&opts->lock); + kfree(uvc); + return ERR_PTR(-EBUSY); + } + ++opts->refcnt; mutex_unlock(&opts->lock); @@ -992,6 +1017,11 @@ static struct usb_function *uvc_alloc(struct usb_function_instance *fi) uvc->func.bind_deactivated = true; return &uvc->func; + +err_config: + mutex_unlock(&opts->lock); + kfree(uvc); + return ERR_PTR(-ENOENT); } DECLARE_USB_FUNCTION_INIT(uvc, uvc_alloc_inst, uvc_alloc); diff --git a/drivers/usb/gadget/function/uvc.h b/drivers/usb/gadget/function/uvc.h index 1a31e6c6a5ff..40226b1f7e14 100644 --- a/drivers/usb/gadget/function/uvc.h +++ b/drivers/usb/gadget/function/uvc.h @@ -134,6 +134,8 @@ struct uvc_device { bool func_connected; wait_queue_head_t func_connected_queue; + struct uvcg_streaming_header *header; + /* Descriptors */ struct { const struct uvc_descriptor_header * const *fs_control; diff --git a/drivers/usb/gadget/function/uvc_v4l2.c b/drivers/usb/gadget/function/uvc_v4l2.c index d6dbf9b763b2..417655e4a83d 100644 --- a/drivers/usb/gadget/function/uvc_v4l2.c +++ b/drivers/usb/gadget/function/uvc_v4l2.c @@ -18,12 +18,92 @@ #include #include #include +#include #include "f_uvc.h" #include "uvc.h" #include "uvc_queue.h" #include "uvc_video.h" #include "uvc_v4l2.h" +#include "uvc_configfs.h" + +static struct uvc_format_desc *to_uvc_format(struct uvcg_format *uformat) +{ + char guid[16] = UVC_GUID_FORMAT_MJPEG; + struct uvc_format_desc *format; + struct uvcg_uncompressed *unc; + + if (uformat->type == UVCG_UNCOMPRESSED) { + unc = to_uvcg_uncompressed(&uformat->group.cg_item); + if (!unc) + return ERR_PTR(-EINVAL); + + memcpy(guid, unc->desc.guidFormat, sizeof(guid)); + } + + format = uvc_format_by_guid(guid); + if (!format) + return ERR_PTR(-EINVAL); + + return format; +} + +static struct uvcg_format *find_format_by_index(struct uvc_device *uvc, int index) +{ + struct uvcg_format_ptr *format; + struct uvcg_format *uformat = NULL; + int i = 1; + + list_for_each_entry(format, &uvc->header->formats, entry) { + if (index == i) { + uformat = format->fmt; + break; + } + i++; + } + + return uformat; +} + +static struct uvcg_frame *find_frame_by_index(struct uvc_device *uvc, + struct uvcg_format *uformat, + int index) +{ + struct uvcg_format_ptr *format; + struct uvcg_frame_ptr *frame; + struct uvcg_frame *uframe = NULL; + + list_for_each_entry(format, &uvc->header->formats, entry) { + if (format->fmt->type != uformat->type) + continue; + list_for_each_entry(frame, &format->fmt->frames, entry) { + if (index == frame->frm->frame.b_frame_index) { + uframe = frame->frm; + break; + } + } + } + + return uframe; +} + +static struct uvcg_format *find_format_by_pix(struct uvc_device *uvc, + u32 pixelformat) +{ + struct uvcg_format_ptr *format; + struct uvcg_format *uformat = NULL; + + list_for_each_entry(format, &uvc->header->formats, entry) { + struct uvc_format_desc *fmtdesc = to_uvc_format(format->fmt); + + if (fmtdesc->fcc == pixelformat) { + uformat = format->fmt; + break; + } + } + + return uformat; +} /* -------------------------------------------------------------------------- * Requests handling @@ -134,6 +214,99 @@ uvc_v4l2_set_format(struct file *file, void *fh, struct v4l2_format *fmt) return 0; } +static int +uvc_v4l2_enum_frameintervals(struct file *file, void *fh, + struct v4l2_frmivalenum *fival) +{ + struct video_device *vdev = video_devdata(file); + struct uvc_device *uvc = video_get_drvdata(vdev); + struct uvcg_format *uformat = NULL; + struct uvcg_frame *uframe = NULL; + struct uvcg_frame_ptr *frame; + + uformat = find_format_by_pix(uvc, fival->pixel_format); + if (!uformat) + return -EINVAL; + + list_for_each_entry(frame, &uformat->frames, entry) { + if (frame->frm->frame.w_width == fival->width && + frame->frm->frame.w_height == fival->height) { + uframe = frame->frm; + break; + } + } + if (!uframe) + return -EINVAL; + + if (fival->index >= uframe->frame.b_frame_interval_type) + return -EINVAL; + + fival->discrete.numerator = + uframe->dw_frame_interval[fival->index]; + + /* TODO: handle V4L2_FRMIVAL_TYPE_STEPWISE */ + fival->type = V4L2_FRMIVAL_TYPE_DISCRETE; + fival->discrete.denominator = 10000000; + v4l2_simplify_fraction(&fival->discrete.numerator, + &fival->discrete.denominator, 8, 333); + + return 0; +} + +static int +uvc_v4l2_enum_framesizes(struct file *file, void *fh, + struct v4l2_frmsizeenum *fsize) +{ + struct video_device *vdev = video_devdata(file); + struct uvc_device *uvc = video_get_drvdata(vdev); + struct uvcg_format *uformat = NULL; + struct uvcg_frame *uframe = NULL; + + uformat = find_format_by_pix(uvc, fsize->pixel_format); + if (!uformat) + return -EINVAL; + + if (fsize->index >= uformat->num_frames) + return -EINVAL; + + uframe = find_frame_by_index(uvc, uformat, fsize->index + 1); + if (!uframe) + return -EINVAL; + + fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; + fsize->discrete.width = uframe->frame.w_width; + fsize->discrete.height = uframe->frame.w_height; + + return 0; +} + +static int +uvc_v4l2_enum_format(struct file *file, void *fh, struct v4l2_fmtdesc *f) +{ + struct video_device *vdev = video_devdata(file); + struct uvc_device *uvc = video_get_drvdata(vdev); + struct uvc_format_desc *fmtdesc; + struct uvcg_format *uformat; + + if (f->index >= uvc->header->num_fmt) + return -EINVAL; + + uformat = find_format_by_index(uvc, f->index + 1); + if (!uformat) + return -EINVAL; + + if (uformat->type != UVCG_UNCOMPRESSED) + f->flags |= V4L2_FMT_FLAG_COMPRESSED; + + fmtdesc = to_uvc_format(uformat); + f->pixelformat = fmtdesc->fcc; + + strscpy(f->description, fmtdesc->name, sizeof(f->description)); + f->description[strlen(fmtdesc->name) - 1] = 0; + + return 0; +} + static int uvc_v4l2_reqbufs(struct file *file, void *fh, struct v4l2_requestbuffers *b) { @@ -300,6 +473,9 @@ const struct v4l2_ioctl_ops uvc_v4l2_ioctl_ops = { .vidioc_querycap = uvc_v4l2_querycap, .vidioc_g_fmt_vid_out = uvc_v4l2_get_format, .vidioc_s_fmt_vid_out = uvc_v4l2_set_format, + .vidioc_enum_frameintervals = uvc_v4l2_enum_frameintervals, + .vidioc_enum_framesizes = uvc_v4l2_enum_framesizes, + .vidioc_enum_fmt_vid_out = uvc_v4l2_enum_format, .vidioc_reqbufs = uvc_v4l2_reqbufs, .vidioc_querybuf = uvc_v4l2_querybuf, .vidioc_qbuf = uvc_v4l2_qbuf, -- cgit v1.2.3 From e219a712bc06dc68ecccb3085cb91438bee2466a Mon Sep 17 00:00:00 2001 From: Michael Grzeschik Date: Sat, 10 Sep 2022 00:13:35 +0200 Subject: usb: gadget: uvc: add v4l2 try_format api call This patch adds the uvc_v4l2_try_format api call to validate the setting of v4l2_format. It will fallback to the nearest allowed framesize. Signed-off-by: Michael Grzeschik Link: https://lore.kernel.org/r/20220909221335.15033-5-m.grzeschik@pengutronix.de Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/function/uvc_v4l2.c | 110 +++++++++++++++++++++++++++++++++ 1 file changed, 110 insertions(+) (limited to 'drivers/usb/gadget/function') diff --git a/drivers/usb/gadget/function/uvc_v4l2.c b/drivers/usb/gadget/function/uvc_v4l2.c index 417655e4a83d..c4ed48d6b8a4 100644 --- a/drivers/usb/gadget/function/uvc_v4l2.c +++ b/drivers/usb/gadget/function/uvc_v4l2.c @@ -48,6 +48,31 @@ static struct uvc_format_desc *to_uvc_format(struct uvcg_format *uformat) return format; } +static int uvc_v4l2_get_bytesperline(struct uvcg_format *uformat, + struct uvcg_frame *uframe) +{ + struct uvcg_uncompressed *u; + + if (uformat->type == UVCG_UNCOMPRESSED) { + u = to_uvcg_uncompressed(&uformat->group.cg_item); + if (!u) + return 0; + + return u->desc.bBitsPerPixel * uframe->frame.w_width / 8; + } + + return 0; +} + +static int uvc_get_frame_size(struct uvcg_format *uformat, + struct uvcg_frame *uframe) +{ + unsigned int bpl = uvc_v4l2_get_bytesperline(uformat, uframe); + + return bpl ? bpl * uframe->frame.w_height : + uframe->frame.dw_max_video_frame_buffer_size; +} + static struct uvcg_format *find_format_by_index(struct uvc_device *uvc, int index) { struct uvcg_format_ptr *format; @@ -105,6 +130,50 @@ static struct uvcg_format *find_format_by_pix(struct uvc_device *uvc, return uformat; } +static struct uvcg_frame *find_closest_frame_by_size(struct uvc_device *uvc, + struct uvcg_format *uformat, + u16 rw, u16 rh) +{ + struct uvc_video *video = &uvc->video; + struct uvcg_format_ptr *format; + struct uvcg_frame_ptr *frame; + struct uvcg_frame *uframe = NULL; + unsigned int d, maxd; + + /* Find the closest image size. The distance between image sizes is + * the size in pixels of the non-overlapping regions between the + * requested size and the frame-specified size. + */ + maxd = (unsigned int)-1; + + list_for_each_entry(format, &uvc->header->formats, entry) { + if (format->fmt->type != uformat->type) + continue; + + list_for_each_entry(frame, &format->fmt->frames, entry) { + u16 w, h; + + w = frame->frm->frame.w_width; + h = frame->frm->frame.w_height; + + d = min(w, rw) * min(h, rh); + d = w*h + rw*rh - 2*d; + if (d < maxd) { + maxd = d; + uframe = frame->frm; + } + + if (maxd == 0) + break; + } + } + + if (!uframe) + uvcg_dbg(&video->uvc->func, "Unsupported size %ux%u\n", rw, rh); + + return uframe; +} + /* -------------------------------------------------------------------------- * Requests handling */ @@ -214,6 +283,46 @@ uvc_v4l2_set_format(struct file *file, void *fh, struct v4l2_format *fmt) return 0; } +static int +uvc_v4l2_try_format(struct file *file, void *fh, struct v4l2_format *fmt) +{ + struct video_device *vdev = video_devdata(file); + struct uvc_device *uvc = video_get_drvdata(vdev); + struct uvc_video *video = &uvc->video; + struct uvcg_format *uformat; + struct uvcg_frame *uframe; + u8 *fcc; + + if (fmt->type != video->queue.queue.type) + return -EINVAL; + + fcc = (u8 *)&fmt->fmt.pix.pixelformat; + uvcg_dbg(&uvc->func, "Trying format 0x%08x (%c%c%c%c): %ux%u\n", + fmt->fmt.pix.pixelformat, + fcc[0], fcc[1], fcc[2], fcc[3], + fmt->fmt.pix.width, fmt->fmt.pix.height); + + uformat = find_format_by_pix(uvc, fmt->fmt.pix.pixelformat); + if (!uformat) + return -EINVAL; + + uframe = find_closest_frame_by_size(uvc, uformat, + fmt->fmt.pix.width, fmt->fmt.pix.height); + if (!uframe) + return -EINVAL; + + fmt->fmt.pix.width = uframe->frame.w_width; + fmt->fmt.pix.height = uframe->frame.w_height; + fmt->fmt.pix.field = V4L2_FIELD_NONE; + fmt->fmt.pix.bytesperline = uvc_v4l2_get_bytesperline(uformat, uframe); + fmt->fmt.pix.sizeimage = uvc_get_frame_size(uformat, uframe); + fmt->fmt.pix.pixelformat = to_uvc_format(uformat)->fcc; + fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB; + fmt->fmt.pix.priv = 0; + + return 0; +} + static int uvc_v4l2_enum_frameintervals(struct file *file, void *fh, struct v4l2_frmivalenum *fival) @@ -471,6 +580,7 @@ uvc_v4l2_ioctl_default(struct file *file, void *fh, bool valid_prio, const struct v4l2_ioctl_ops uvc_v4l2_ioctl_ops = { .vidioc_querycap = uvc_v4l2_querycap, + .vidioc_try_fmt_vid_out = uvc_v4l2_try_format, .vidioc_g_fmt_vid_out = uvc_v4l2_get_format, .vidioc_s_fmt_vid_out = uvc_v4l2_set_format, .vidioc_enum_frameintervals = uvc_v4l2_enum_frameintervals, -- cgit v1.2.3 From a15e17acce5aaae54243f55a7349c2225450b9bc Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Wed, 28 Sep 2022 13:19:21 -0700 Subject: usb: gadget: uvc: Fix argument to sizeof() in uvc_register_video() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When building s390 allmodconfig after commit 9b91a6523078 ("usb: gadget: uvc: increase worker prio to WQ_HIGHPRI"), the following error occurs: In file included from ../include/linux/string.h:253, from ../include/linux/bitmap.h:11, from ../include/linux/cpumask.h:12, from ../include/linux/smp.h:13, from ../include/linux/lockdep.h:14, from ../include/linux/rcupdate.h:29, from ../include/linux/rculist.h:11, from ../include/linux/pid.h:5, from ../include/linux/sched.h:14, from ../include/linux/ratelimit.h:6, from ../include/linux/dev_printk.h:16, from ../include/linux/device.h:15, from ../drivers/usb/gadget/function/f_uvc.c:9: In function ‘fortify_memset_chk’, inlined from ‘uvc_register_video’ at ../drivers/usb/gadget/function/f_uvc.c:424:2: ../include/linux/fortify-string.h:301:25: error: call to ‘__write_overflow_field’ declared with attribute warning: detected write beyond size of field (1st parameter); maybe use struct_group()? [-Werror=attribute-warning] 301 | __write_overflow_field(p_size_field, size); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ This points to the memset() in uvc_register_video(). It is clear that the argument to sizeof() is incorrect, as uvc->vdev (a 'struct video_device') is being zeroed out but the size of uvc->video (a 'struct uvc_video') is being used as the third arugment to memset(). pahole shows that prior to commit 9b91a6523078 ("usb: gadget: uvc: increase worker prio to WQ_HIGHPRI"), 'struct video_device' and 'struct ucv_video' had the same size, meaning that the argument to sizeof() is incorrect semantically but there is no visible issue: $ pahole -s build/drivers/usb/gadget/function/f_uvc.o | grep -E "(uvc_video|video_device)\s+" video_device 1400 4 uvc_video 1400 3 After that change, uvc_video becomes slightly larger, meaning that the memset() will overwrite by 8 bytes: $ pahole -s build/drivers/usb/gadget/function/f_uvc.o | grep -E "(uvc_video|video_device)\s+" video_device 1400 4 uvc_video 1408 3 Fix the arugment to sizeof() so that there is no overwrite. Cc: stable@vger.kernel.org Fixes: e4ce9ed835bc ("usb: gadget: uvc: ensure the vdev is unset") Signed-off-by: Nathan Chancellor Reviewed-by: Laurent Pinchart Reviewed-by: Kees Cook Link: https://lore.kernel.org/r/20220928201921.3152163-1-nathan@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/function/f_uvc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/usb/gadget/function') diff --git a/drivers/usb/gadget/function/f_uvc.c b/drivers/usb/gadget/function/f_uvc.c index e6948cf8def3..836601227155 100644 --- a/drivers/usb/gadget/function/f_uvc.c +++ b/drivers/usb/gadget/function/f_uvc.c @@ -421,7 +421,7 @@ uvc_register_video(struct uvc_device *uvc) int ret; /* TODO reference counting. */ - memset(&uvc->vdev, 0, sizeof(uvc->video)); + memset(&uvc->vdev, 0, sizeof(uvc->vdev)); uvc->vdev.v4l2_dev = &uvc->v4l2_dev; uvc->vdev.v4l2_dev->dev = &cdev->gadget->dev; uvc->vdev.fops = &uvc_v4l2_fops; -- cgit v1.2.3 From 3180d827c807d8d6e5d6ba4f2e08eed9efa083af Mon Sep 17 00:00:00 2001 From: Michael Grzeschik Date: Fri, 30 Sep 2022 14:28:39 +0200 Subject: usb: gadget: uvc: don't put item still in use With the patch "588b9e85609b (usb: gadget: uvc: add v4l2 enumeration api calls)" the driver is keeping a list of configfs entries currently configured. The list is used in uvc_v4l2 on runtime. The driver now is giving back the list item just after it was referenced with config_item_put. It also calls config_item_put on uvc_free, which is the only and right place to give back the reference. This patch fixes the issue by removing the extra config_item_put in uvc_alloc. Fixes: 588b9e85609b (usb: gadget: uvc: add v4l2 enumeration api calls) Signed-off-by: Michael Grzeschik Link: https://lore.kernel.org/r/20220930122839.1747279-1-m.grzeschik@pengutronix.de Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/function/f_uvc.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/usb/gadget/function') diff --git a/drivers/usb/gadget/function/f_uvc.c b/drivers/usb/gadget/function/f_uvc.c index 836601227155..6e196e06181e 100644 --- a/drivers/usb/gadget/function/f_uvc.c +++ b/drivers/usb/gadget/function/f_uvc.c @@ -995,7 +995,6 @@ static struct usb_function *uvc_alloc(struct usb_function_instance *fi) goto err_config; uvc->header = to_uvcg_streaming_header(h); - config_item_put(h); if (!uvc->header->linked) { mutex_unlock(&opts->lock); kfree(uvc); -- cgit v1.2.3