On Thu, Nov 12, 2026 at 04:23:27PM +0000, Joas Antonio dos Santos via B4 Relay wrote:
From: Joas Antonio dos Santos <redacted>
smsc75xx_rx_fixup() takes the frame length from the RX command word
supplied by the device and strips the FCS by using "size - 4" for the
allocation, skb_put() and memcpy() of each frame that is not the last
one in the URB. The length is only checked against an upper bound and
against skb->len, so a device can report a length field of 2..5, which
gives a size of 0..3 after RXW_PADDING is subtracted.
size is a u32, so "size - 4" then wraps to 0xfffffffc..0xffffffff.
__netdev_alloc_skb() adds NET_SKB_PAD to the unsigned length, which
wraps back to a small value and the allocation succeeds. skb_put()
adds the length to the 32-bit skb->tail and skb->len, which also wrap,
so the skb_over_panic() check does not fire. The following memcpy()
then tries to copy almost 4 GiB from the URB buffer into that small
allocation and writes far beyond it.
A malicious or malfunctioning USB device can use this to corrupt
kernel memory or crash the machine.
A frame that holds an FCS but less than an Ethernet header is not
valid either. usbnet drops it when it is the last frame in the URB,
but the other frames go straight to usbnet_skb_return(), where
eth_type_trans() reads an Ethernet header that was never copied into
the new skb.
Reject frames that are too short to hold an Ethernet header and an
FCS, which covers both cases with one check.
The driver does not set FLAG_RX_ASSEMBLE, so usbnet already counts
rx_errors when smsc75xx_rx_fixup() returns 0. Also count
rx_length_errors for these frames, as usbnet does for the short frames
it drops itself.
Found by LLM-assisted source review.
Fixes: 1b3b2d9e772b ("net: usb: smsc75xx: stop lying about skb->truesize")
Cc: <redacted>
Signed-off-by: Joas Antonio dos Santos <redacted>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Andrew