Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 1d7d4c0

Browse files
AlanSterngregkh
authored andcommitted
USB: Fix "slab-out-of-bounds Write" bug in usb_hcd_poll_rh_status
When the USB core code for getting root-hub status reports was originally written, it was assumed that the hub driver would be its only caller. But this isn't true now; user programs can use usbfs to communicate with root hubs and get status reports. When they do this, they may use a transfer_buffer that is smaller than the data returned by the HCD, which will lead to a buffer overflow error when usb_hcd_poll_rh_status() tries to store the status data. This was discovered by syzbot: BUG: KASAN: slab-out-of-bounds in memcpy include/linux/fortify-string.h:225 [inline] BUG: KASAN: slab-out-of-bounds in usb_hcd_poll_rh_status+0x5f4/0x780 drivers/usb/core/hcd.c:776 Write of size 2 at addr ffff88801da403c0 by task syz-executor133/4062 This patch fixes the bug by reducing the amount of status data if it won't fit in the transfer_buffer. If some data gets discarded then the URB's completion status is set to -EOVERFLOW rather than 0, to let the user know what happened. Reported-and-tested-by: [email protected] Signed-off-by: Alan Stern <[email protected]> Cc: <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent fa0ef93 commit 1d7d4c0

File tree

1 file changed

+8
-1
lines changed

1 file changed

+8
-1
lines changed

drivers/usb/core/hcd.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -753,6 +753,7 @@ void usb_hcd_poll_rh_status(struct usb_hcd *hcd)
753753
{
754754
struct urb *urb;
755755
int length;
756+
int status;
756757
unsigned long flags;
757758
char buffer[6]; /* Any root hubs with > 31 ports? */
758759

@@ -770,11 +771,17 @@ void usb_hcd_poll_rh_status(struct usb_hcd *hcd)
770771
if (urb) {
771772
clear_bit(HCD_FLAG_POLL_PENDING, &hcd->flags);
772773
hcd->status_urb = NULL;
774+
if (urb->transfer_buffer_length >= length) {
775+
status = 0;
776+
} else {
777+
status = -EOVERFLOW;
778+
length = urb->transfer_buffer_length;
779+
}
773780
urb->actual_length = length;
774781
memcpy(urb->transfer_buffer, buffer, length);
775782

776783
usb_hcd_unlink_urb_from_ep(hcd, urb);
777-
usb_hcd_giveback_urb(hcd, urb, 0);
784+
usb_hcd_giveback_urb(hcd, urb, status);
778785
} else {
779786
length = 0;
780787
set_bit(HCD_FLAG_POLL_PENDING, &hcd->flags);

0 commit comments

Comments
 (0)