[PATCH net-next v2] net: usb: asix: reject a truncated Data header in rx_fixup

From: Aamir Ahmed

Date: Mon Sep 14 2026 - 17:25:22 EST


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 <elb12345@xxxxxxxxxxxxx>
---
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@xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/

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