The sync check in asix_rx_fixup_internal() validates:
rx->remaining + sizeof(u32) <= skb->len
then reads at:
offset = ((rx->remaining + 1) & 0xfffe);
rx->header = get_unaligned_le32(skb->data + offset);
When rx->remaining is odd, the alignment rounding makes offset larger
than rx->remaining. For example with rx->remaining=3 and skb->len=7:
check passes (3+4<=7) but offset becomes ((3+1)&0xfffe)=4, and the
4-byte read at offset 4 needs 8 bytes total, causing a 1-byte
heap OOB read.
Fix the bounds check to use the actual aligned offset that will be
used for the read.
Fixes: 3f30b158eba5 ("asix: On RX avoid creating bad Ethernet frames")
Cc: stable@vger.kernel.org
Assisted-by: Claude (Anthropic)
Signed-off-by: Aamir Ahmed <redacted>
---
drivers/net/usb/asix_common.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/usb/asix_common.c b/drivers/net/usb/asix_common.c
index 4f03f4e57655d..c50646ea35c7e 100644
--- a/drivers/net/usb/asix_common.c
+++ b/drivers/net/usb/asix_common.c
@@ -148,7 +148,7 @@ int asix_rx_fixup_internal(struct usbnet *dev, struct sk_buff *skb,
* Also avoid unnecessarily discarding a good current netdev socket
* buffer.
*/
- if (rx->remaining && (rx->remaining + sizeof(u32) <= skb->len)) {
+ if (rx->remaining && (((rx->remaining + 1) & 0xfffe) + sizeof(u32) <= skb->len)) {
offset = ((rx->remaining + 1) & 0xfffe);
rx->header = get_unaligned_le32(skb->data + offset);
offset = 0;--
2.43.0