Skip to content

Commit 9f9bfc8

Browse files
Zhang Cenjhovold
authored andcommitted
USB: serial: cypress_m8: validate interrupt packet headers
cypress_read_int_callback() parses the interrupt-in buffer according to the selected Cypress packet format. Format 1 has a two-byte status/count header and format 2 has a one-byte combined status/count header. The usb-serial core sizes the interrupt-in buffer from the endpoint descriptor's wMaxPacketSize, and successful interrupt transfers can complete short when URB_SHORT_NOT_OK is not set. Check that the completed packet contains the selected header before reading it. Malformed short reports are ignored and the interrupt URB is resubmitted through the existing retry path, preventing out-of-bounds header-byte reads. KASAN report as below: KASAN slab-out-of-bounds in cypress_read_int_callback+0x240/0x7f0 Read of size 1 Call trace: cypress_read_int_callback() (drivers/usb/serial/cypress_m8.c:1009) __usb_hcd_giveback_urb() dummy_timer() Fixes: 3416eaa ("USB: cypress_m8: Packet format is separate from characteristic size") Assisted-by: Codex:gpt-5.5 Signed-off-by: Zhang Cen <rollkingzzc@gmail.com> Fixes: 3416eaa ("USB: cypress_m8: Packet format is separate from characteristic size") Cc: stable@vger.kernel.org # 2.6.26 [ johan: use constants in header length sanity checks ] Signed-off-by: Johan Hovold <johan@kernel.org>
1 parent 438061e commit 9f9bfc8

1 file changed

Lines changed: 11 additions & 1 deletion

File tree

drivers/usb/serial/cypress_m8.c

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1025,8 +1025,8 @@ static void cypress_read_int_callback(struct urb *urb)
10251025
char tty_flag = TTY_NORMAL;
10261026
int bytes = 0;
10271027
int result;
1028-
int i = 0;
10291028
int status = urb->status;
1029+
int i;
10301030

10311031
switch (status) {
10321032
case 0: /* success */
@@ -1064,22 +1064,32 @@ static void cypress_read_int_callback(struct urb *urb)
10641064

10651065
spin_lock_irqsave(&priv->lock, flags);
10661066
result = urb->actual_length;
1067+
i = 0;
10671068
switch (priv->pkt_fmt) {
10681069
default:
10691070
case packet_format_1:
10701071
/* This is for the CY7C64013... */
1072+
if (result < 2)
1073+
break;
10711074
priv->current_status = data[0] & 0xF8;
10721075
bytes = data[1] + 2;
10731076
i = 2;
10741077
break;
10751078
case packet_format_2:
10761079
/* This is for the CY7C63743... */
1080+
if (result < 1)
1081+
break;
10771082
priv->current_status = data[0] & 0xF8;
10781083
bytes = (data[0] & 0x07) + 1;
10791084
i = 1;
10801085
break;
10811086
}
10821087
spin_unlock_irqrestore(&priv->lock, flags);
1088+
if (i == 0) {
1089+
dev_dbg(dev, "%s - short packet received: %d bytes\n",
1090+
__func__, result);
1091+
goto continue_read;
1092+
}
10831093
if (result < bytes) {
10841094
dev_dbg(dev,
10851095
"%s - wrong packet size - received %d bytes but packet said %d bytes\n",

0 commit comments

Comments
 (0)