asix_rx_fixup_internal() runs its parsing loop while two bytes remain, but the branch that starts a new frame reads a four-byte Data header. Only a two-byte tail is special-cased, via split_head, so a three-byte tail reaches that read and leaves offset at skb->len + 1. The clamp below it then takes the unsigned difference skb->len - offset, which wraps, so copy_length becomes the full length the device asked for: skb_put_data() copies from one byte past the received data and usbnet_skb_return() passes the frame to the stack, before the trailing skb->len != offset check can report it. Reject a Data header that does not fit and reset the parser state, as the other malformed-header paths do. Only a device emitting an odd skb->len can get there - every asix rx_urb_size is even and offset always advances by an even number of bytes - so this is net-next material rather than a stable backport. Fixes: 8b5b6f5413e9 ("net: asix: handle packets crossing URB boundaries") Assisted-by: LLM Signed-off-by: Aamir Ahmed --- v2: - guard the header read inside the loop, not the pre-loop predicate - rewrite the changelog around the unsigned underflow - target net-next, drop Cc: stable, repoint Fixes at 8b5b6f5413e9 - add Assisted-by: LLM v1: https://lore.kernel.org/netdev/AS8P251MB00014BB4591CE6011152DB4FC8B22@AS8P251MB0001.EURP251.PROD.OUTLOOK.COM/ Built with W=1 (asix_common.o) on x86_64; no warnings. I have no asix hardware, so this is not runtime-tested. drivers/net/usb/asix_common.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/net/usb/asix_common.c b/drivers/net/usb/asix_common.c index 4f03f4e57655..8c5f863efe7d 100644 --- a/drivers/net/usb/asix_common.c +++ b/drivers/net/usb/asix_common.c @@ -179,6 +179,13 @@ int asix_rx_fixup_internal(struct usbnet *dev, struct sk_buff *skb, rx->split_head = false; offset += sizeof(u16); } else { + if (offset + sizeof(u32) > skb->len) { + netdev_err(dev->net, "asix_rx_fixup() Short Data header, offset %d, len %d\n", + offset, skb->len); + reset_asix_rx_fixup_info(rx); + return 0; + } + rx->header = get_unaligned_le32(skb->data + offset); offset += sizeof(u32); base-commit: c297ed90fbba72d32b7759aae362b36d15b2db1f -- 2.43.0