summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJiale Yao <yaojiale02@163.com>2026-07-26 00:27:51 +0800
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2026-09-02 14:28:36 +0200
commit6b8cf5422c7e96ed5b22a8368eff663f3f98b8ec (patch)
tree229a77a4e8928d3fdaa49bd614768b91a29bbccc
parent3f06f3f5b16212f180764654a9398ff5f7a855c8 (diff)
downloadlinux-6b8cf5422c7e96ed5b22a8368eff663f3f98b8ec.tar.gz
linux-6b8cf5422c7e96ed5b22a8368eff663f3f98b8ec.zip
USB: serial: option: fix slab OOB read in interrupt URB callback
commit 885d802f544ca7bfa8f3984d94233cce715bb6b3 upstream. The interrupt URB buffer is allocated in setup_port_interrupt_in() based on the endpoint's wMaxPacketSize: buffer_size = usb_endpoint_maxp(epd); port->interrupt_in_buffer = kmalloc(buffer_size, GFP_KERNEL); When a USB device declares wMaxPacketSize = 8 on its interrupt IN endpoint, the buffer is allocated from kmalloc-8 cache (exactly 8 bytes). If the device sends a short packet (actual_length < wMaxPacketSize), the URB completes with status == 0 and the callback proceeds to read: data[sizeof(struct usb_ctrlrequest)] which evaluates to data[8], accessing 1 byte beyond the allocated 8-byte buffer. This results in a slab out-of-bounds read. Fix this by adding the missing bounds check: first verify that the actual length is large enough to contain the struct usb_ctrlrequest header before accessing req_pkt->bRequestType and req_pkt->bRequest, and then verify that there is an additional byte for the modem signal state before reading data[sizeof(struct usb_ctrlrequest)] inside the conditional. Use sizeof(*req_pkt) instead of sizeof(struct usb_ctrlrequest) for consistency. Assisted-by: Claude:deepseek-v4-pro Signed-off-by: Jiale Yao <yaojiale02@163.com> Fixes: 58cfe9113e48 ("[PATCH] USB: add Option Card driver") Cc: stable@vger.kernel.org # v2.6.12 [ johan: use dev_err(); split signals declaration and initialisation ] Signed-off-by: Johan Hovold <johan@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/usb/serial/option.c20
1 files changed, 17 insertions, 3 deletions
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
index 500472b34855..dd018abda6c3 100644
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -2691,12 +2691,26 @@ static void option_instat_callback(struct urb *urb)
dev_dbg(dev, "%s: NULL req_pkt\n", __func__);
return;
}
+
+ if (urb->actual_length < sizeof(*req_pkt)) {
+ dev_err(dev, "%s: short packet: %u bytes\n", __func__,
+ urb->actual_length);
+ return;
+ }
+
if ((req_pkt->bRequestType == 0xA1) &&
(req_pkt->bRequest == 0x20)) {
+ unsigned char signals;
int old_dcd_state;
- unsigned char signals = *((unsigned char *)
- urb->transfer_buffer +
- sizeof(struct usb_ctrlrequest));
+
+ if (urb->actual_length < sizeof(*req_pkt) + 1) {
+ dev_err(dev, "%s: short interrupt transfer: %u bytes\n",
+ __func__, urb->actual_length);
+ return;
+ }
+
+ signals = *((unsigned char *)urb->transfer_buffer +
+ sizeof(*req_pkt));
dev_dbg(dev, "%s: signal x%x\n", __func__, signals);