catc_rx_done() parses multi-packet USB transfers by iterating over the
received data. For each packet, it reads a 2-byte little-endian length
from the buffer, then copies that many bytes as the packet payload.
The bounds check "pkt_len > urb->actual_length" is insufficient:
1. It does not account for the 2-byte header offset, so the memcpy can
read 2 bytes beyond the received data.
2. For subsequent packets in the same URB, pkt_start advances through
the buffer but the check still compares against the total
urb->actual_length rather than the remaining bytes, allowing reads
well past the end.
Fix this by calculating the remaining bytes from the current pkt_start
position and checking both that enough bytes exist to read the header
and that the packet length plus header fits within the remaining data.
A malicious USB device can craft transfers that trigger the out-of-bounds
heap read.
Fixes: 1da177e4c3f41 ("Linux-2.6.12-rc2")
Cc: stable@vger.kernel.org
Signed-off-by: Aamir Ahmed <redacted>
Assisted-by: Claude (Anthropic)
---
drivers/net/usb/catc.c | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)
diff --git a/drivers/net/usb/catc.c b/drivers/net/usb/catc.c
index 96e82f94edcf8..e4f8b9a0caf19 100644
--- a/drivers/net/usb/catc.c
+++ b/drivers/net/usb/catc.c
@@ -234,8 +234,16 @@ static void catc_rx_done(struct urb *urb)
do {
if(!catc->is_f5u011) {
+ int remaining = urb->actual_length -
+ (pkt_start - (u8 *)urb->transfer_buffer);
+
+ if (remaining < pkt_offset) {
+ catc->netdev->stats.rx_length_errors++;
+ catc->netdev->stats.rx_errors++;
+ break;
+ }
pkt_len = le16_to_cpup((__le16*)pkt_start);
- if (pkt_len > urb->actual_length) {
+ if (pkt_len + pkt_offset > remaining) {
catc->netdev->stats.rx_length_errors++;
catc->netdev->stats.rx_errors++;
break;--
2.43.0