Skip to content

Commit 060db7d

Browse files
Jiale Yaogregkh
authored andcommitted
USB: serial: option: fix slab OOB read in interrupt URB callback
commit 885d802 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: 58cfe91 ("[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>
1 parent 5a625fc commit 060db7d

1 file changed

Lines changed: 17 additions & 3 deletions

File tree

drivers/usb/serial/option.c

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2690,12 +2690,26 @@ static void option_instat_callback(struct urb *urb)
26902690
dev_dbg(dev, "%s: NULL req_pkt\n", __func__);
26912691
return;
26922692
}
2693+
2694+
if (urb->actual_length < sizeof(*req_pkt)) {
2695+
dev_err(dev, "%s: short packet: %u bytes\n", __func__,
2696+
urb->actual_length);
2697+
return;
2698+
}
2699+
26932700
if ((req_pkt->bRequestType == 0xA1) &&
26942701
(req_pkt->bRequest == 0x20)) {
2702+
unsigned char signals;
26952703
int old_dcd_state;
2696-
unsigned char signals = *((unsigned char *)
2697-
urb->transfer_buffer +
2698-
sizeof(struct usb_ctrlrequest));
2704+
2705+
if (urb->actual_length < sizeof(*req_pkt) + 1) {
2706+
dev_err(dev, "%s: short interrupt transfer: %u bytes\n",
2707+
__func__, urb->actual_length);
2708+
return;
2709+
}
2710+
2711+
signals = *((unsigned char *)urb->transfer_buffer +
2712+
sizeof(*req_pkt));
26992713

27002714
dev_dbg(dev, "%s: signal x%x\n", __func__, signals);
27012715

0 commit comments

Comments
 (0)