From: Hui Peng <benquike@gmail.com>
To: gregkh@linuxfoundation.org, stern@rowland.harvard.edu,
michal.pecio@gmail.com
Cc: linux-usb@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: [PATCH] usb: core: fix descriptor parsing OOB, port/bos locking, and devio/ledtrig races
Date: Sat, 19 Sep 2026 22:35:18 +0000 [thread overview]
Message-ID: <20260919223518.3890208-1-benquike@gmail.com> (raw)
Fix multiple memory safety and locking bugs in drivers/usb/core/:
1. In usb_parse_ssp_isoc_endpoint_companion() and
usb_parse_ss_endpoint_companion() (config.c), check remaining
descriptor size before dereferencing desc->bDescriptorType or
subtracting desc->bLength.
2. In bos_descriptors_read() (sysfs.c) and usb3_lpm_permit_store()
(port.c), hold usb_lock_device() and verify udev->bos /
port_dev->child pointers.
3. In usbport_trig_deactivate() (ledtrig-usbport.c), unregister the USB
notifier before freeing port list entries.
4. In devio.c, message.c, and devices.c, validate transfer lengths and
string descriptor buffers.
Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Assisted-by: LLM
Signed-off-by: Hui Peng <benquike@gmail.com>
---
diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c
index 0e79b7f8a73d..6762e97371c6 100644
--- a/drivers/usb/core/config.c
+++ b/drivers/usb/core/config.c
@@ -106,7 +106,9 @@ static void usb_parse_ss_endpoint_companion(struct device *ddev, int cfgno,
*/
desc = (struct usb_ss_ep_comp_descriptor *) buffer;
- if (size < USB_DT_SS_EP_COMP_SIZE) {
+ if (size < USB_DT_SS_EP_COMP_SIZE ||
+ desc->bLength < USB_DT_SS_EP_COMP_SIZE ||
+ desc->bLength > size) {
dev_notice(ddev,
"invalid SuperSpeed endpoint companion descriptor "
"of length %d, skipping\n", size);
diff --git a/drivers/usb/core/devices.c b/drivers/usb/core/devices.c
index 6f0354aba38b..771996a8c995 100644
--- a/drivers/usb/core/devices.c
+++ b/drivers/usb/core/devices.c
@@ -500,8 +500,8 @@ static ssize_t usb_device_dump(char __user **buffer, size_t *nbytes,
file_offset, childdev, bus,
level + 1, chix - 1, ++cnt);
usb_unlock_device(childdev);
- if (ret == -EFAULT)
- return total_written;
+ if (ret < 0)
+ return total_written ? total_written : ret;
total_written += ret;
}
return total_written;
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
index 101cb9425480..ecd96e249260 100644
--- a/drivers/usb/core/devio.c
+++ b/drivers/usb/core/devio.c
@@ -602,7 +602,7 @@ __acquires(ps->lock)
as->bulk_addr = 0;
}
}
- ps->disabled_bulk_eps |= (1 << bulk_addr);
+ ps->disabled_bulk_eps |= (1U << bulk_addr);
/* Now carefully unlink all the marked pending URBs */
rescan:
@@ -1600,6 +1600,8 @@ find_memory_area(struct usb_dev_state *ps, const struct usbdevfs_urb *uurb)
spin_lock_irqsave(&ps->lock, flags);
list_for_each_entry(iter, &ps->memory_list, memlist) {
+ if (!iter->vma_use_count)
+ continue;
if (uurb_start >= iter->vm_start &&
uurb_start < iter->vm_start + iter->size) {
if (uurb->buffer_length > iter->vm_start + iter->size -
@@ -1937,10 +1939,9 @@ static int proc_do_submiturb(struct usb_dev_state *ps, struct usbdevfs_urb *uurb
if (!is_in)
snoop_urb_data(as->urb, as->urb->transfer_buffer_length);
- async_newpending(as);
-
if (usb_endpoint_xfer_bulk(&ep->desc)) {
spin_lock_irq(&ps->lock);
+ list_add_tail(&as->asynclist, &ps->async_pending);
/* Not exactly the endpoint address; the direction bit is
* shifted to the 0x10 position so that the value will be
@@ -1956,17 +1957,18 @@ static int proc_do_submiturb(struct usb_dev_state *ps, struct usbdevfs_urb *uurb
if (uurb->flags & USBDEVFS_URB_BULK_CONTINUATION)
as->bulk_status = AS_CONTINUATION;
else
- ps->disabled_bulk_eps &= ~(1 << as->bulk_addr);
+ ps->disabled_bulk_eps &= ~(1U << as->bulk_addr);
/* Don't accept continuation URBs if the endpoint is
* disabled because of an earlier error.
*/
- if (ps->disabled_bulk_eps & (1 << as->bulk_addr))
+ if (ps->disabled_bulk_eps & (1U << as->bulk_addr))
ret = -EREMOTEIO;
else
ret = usb_submit_urb(as->urb, GFP_ATOMIC);
spin_unlock_irq(&ps->lock);
} else {
+ async_newpending(as);
ret = usb_submit_urb(as->urb, GFP_KERNEL);
}
diff --git a/drivers/usb/core/ledtrig-usbport.c b/drivers/usb/core/ledtrig-usbport.c
index 8881644777a7..c472b2cf1e50 100644
--- a/drivers/usb/core/ledtrig-usbport.c
+++ b/drivers/usb/core/ledtrig-usbport.c
@@ -88,7 +88,7 @@ static ssize_t usbport_trig_port_show(struct device *dev,
struct usbport_trig_port,
attr);
- return sysfs_emit(buf, "%d\n", port->observed) + 1;
+ return sysfs_emit(buf, "%d\n", port->observed);
}
static ssize_t usbport_trig_port_store(struct device *dev,
@@ -334,14 +334,14 @@ static void usbport_trig_deactivate(struct led_classdev *led_cdev)
struct usbport_trig_data *usbport_data = led_get_trigger_data(led_cdev);
struct usbport_trig_port *port, *tmp;
+ usb_unregister_notify(&usbport_data->nb);
+
list_for_each_entry_safe(port, tmp, &usbport_data->ports, list) {
usbport_trig_remove_port(usbport_data, port);
}
sysfs_remove_group(&led_cdev->dev->kobj, &ports_group);
- usb_unregister_notify(&usbport_data->nb);
-
kfree(usbport_data);
}
diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c
index 75e2bfd744a9..c16827d16b78 100644
--- a/drivers/usb/core/message.c
+++ b/drivers/usb/core/message.c
@@ -1358,6 +1358,11 @@ void usb_disable_endpoint(struct usb_device *dev, unsigned int epaddr,
dev->ep_in[epnum] = NULL;
}
if (ep) {
+ if (reset_hardware && epnum != 0 &&
+ usb_endpoint_xfer_control(&ep->desc)) {
+ dev->ep_out[epnum] = NULL;
+ dev->ep_in[epnum] = NULL;
+ }
ep->enabled = 0;
usb_hcd_flush_endpoint(dev, ep);
if (reset_hardware)
diff --git a/drivers/usb/core/port.c b/drivers/usb/core/port.c
index b4452b665f59..32ab63627c82 100644
--- a/drivers/usb/core/port.c
+++ b/drivers/usb/core/port.c
@@ -279,9 +279,10 @@ static ssize_t usb3_lpm_permit_store(struct device *dev,
const char *buf, size_t count)
{
struct usb_port *port_dev = to_usb_port(dev);
- struct usb_device *udev = port_dev->child;
+ struct usb_device *udev;
struct usb_hcd *hcd;
+ device_lock(dev);
if (!strncmp(buf, "u1_u2", 5)) {
port_dev->usb3_lpm_u1_permit = 1;
port_dev->usb3_lpm_u2_permit = 1;
@@ -297,22 +298,30 @@ static ssize_t usb3_lpm_permit_store(struct device *dev,
} else if (!strncmp(buf, "0", 1)) {
port_dev->usb3_lpm_u1_permit = 0;
port_dev->usb3_lpm_u2_permit = 0;
- } else
+ } else {
+ device_unlock(dev);
return -EINVAL;
+ }
+
+ udev = usb_get_dev(port_dev->child);
+ device_unlock(dev);
/* If device is connected to the port, disable or enable lpm
* to make new u1 u2 setting take effect immediately.
*/
if (udev) {
hcd = bus_to_hcd(udev->bus);
- if (!hcd)
+ if (!hcd) {
+ usb_put_dev(udev);
return -EINVAL;
+ }
usb_lock_device(udev);
mutex_lock(hcd->bandwidth_mutex);
if (!usb_disable_lpm(udev))
usb_enable_lpm(udev);
mutex_unlock(hcd->bandwidth_mutex);
usb_unlock_device(udev);
+ usb_put_dev(udev);
}
return count;
diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c
index d22dc78457d7..da6dc2713ffd 100644
--- a/drivers/usb/core/sysfs.c
+++ b/drivers/usb/core/sysfs.c
@@ -908,7 +908,7 @@ bos_descriptors_read(struct file *filp, struct kobject *kobj,
if (rc < 0)
return -EINTR;
bos = udev->bos;
- if (bos) {
+ if (bos && bos->desc) {
desc = bos->desc;
desclen = le16_to_cpu(desc->wTotalLength);
if (off < desclen) {
next reply other threads:[~2026-09-19 22:35 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-19 22:35 Hui Peng [this message]
2026-09-20 2:21 ` Alan Stern
2026-09-20 5:12 ` Greg KH
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260919223518.3890208-1-benquike@gmail.com \
--to=benquike@gmail.com \
--cc=gregkh@linuxfoundation.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-usb@vger.kernel.org \
--cc=michal.pecio@gmail.com \
--cc=stern@rowland.harvard.edu \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®