From 444387baae751a93258e475e4c2bc5a41592a5e2 Mon Sep 17 00:00:00 2001 From: szg6 <2198251661@qq.com> Date: Fri, 20 Dec 2024 14:52:08 +0800 Subject: [PATCH] Enhanced the check for out-of-bounds access to the metadata array Signed-off-by: szg6 <2198251661@qq.com> --- drivers/net/usb/ax88179_178a.c | 115 +++++++++++++++++---------------- 1 file changed, 59 insertions(+), 56 deletions(-) diff --git a/drivers/net/usb/ax88179_178a.c b/drivers/net/usb/ax88179_178a.c index 38cb863ccb91..32fd1409a940 100644 --- a/drivers/net/usb/ax88179_178a.c +++ b/drivers/net/usb/ax88179_178a.c @@ -1508,78 +1508,81 @@ static int ax88179_rx_fixup(struct usbnet *dev, struct sk_buff *skb) */ if (skb->len < 4) - return 0; - skb_trim(skb, skb->len - 4); - rx_hdr = get_unaligned_le32(skb_tail_pointer(skb)); - pkt_cnt = (u16)rx_hdr; - hdr_off = (u16)(rx_hdr >> 16); + return 0; - if (pkt_cnt == 0) - return 0; + skb_trim(skb, skb->len - 4); // Trim last 4 bytes to get rx_hdr + rx_hdr = get_unaligned_le32(skb_tail_pointer(skb)); + pkt_cnt = (u16)rx_hdr; + hdr_off = (u16)(rx_hdr >> 16); - /* Make sure that the bounds of the metadata array are inside the SKB - * (and in front of the counter at the end). - */ - if (pkt_cnt * 4 + hdr_off > skb->len) - return 0; - pkt_hdr = (u32 *)(skb->data + hdr_off); + if (pkt_cnt == 0) + return 0; - /* Packets must not overlap the metadata array */ - skb_trim(skb, hdr_off); + /* Make sure that the bounds of the metadata array are inside the SKB + * (and in front of the counter at the end). + */ + if (pkt_cnt * 4 + hdr_off > skb->len) + return 0; - for (; pkt_cnt > 0; pkt_cnt--, pkt_hdr++) { - u16 pkt_len_plus_padd; - u16 pkt_len; + pkt_hdr = (u32 *)(skb->data + hdr_off); - le32_to_cpus(pkt_hdr); - pkt_len = (*pkt_hdr >> 16) & 0x1fff; - pkt_len_plus_padd = (pkt_len + 7) & 0xfff8; + /* Ensure that the packets do not overlap the metadata array */ + skb_trim(skb, hdr_off); - /* Skip dummy header used for alignment - */ - if (pkt_len == 0) - continue; + for (; pkt_cnt > 0; pkt_cnt--, pkt_hdr++) { + u16 pkt_len_plus_padd; + u16 pkt_len; - if (pkt_len_plus_padd > skb->len) - return 0; + le32_to_cpus(pkt_hdr); + pkt_len = (*pkt_hdr >> 16) & 0x1fff; + pkt_len_plus_padd = (pkt_len + 7) & 0xfff8; - /* Check CRC or runt packet */ - if ((*pkt_hdr & (AX_RXHDR_CRC_ERR | AX_RXHDR_DROP_ERR)) || - pkt_len < 2 + ETH_HLEN) { - dev->net->stats.rx_errors++; - skb_pull(skb, pkt_len_plus_padd); - continue; - } + /* Skip dummy header used for alignment */ + if (pkt_len == 0) + continue; - /* last packet */ - if (pkt_len_plus_padd == skb->len) { - skb_trim(skb, pkt_len); + /* Ensure the packet size doesn't exceed the SKB's remaining length */ + if (pkt_len_plus_padd > skb->len) + return 0; - /* Skip IP alignment pseudo header */ - skb_pull(skb, 2); + /* Check CRC or runt packet */ + if ((*pkt_hdr & (AX_RXHDR_CRC_ERR | AX_RXHDR_DROP_ERR)) || + pkt_len < 2 + ETH_HLEN) { + dev->net->stats.rx_errors++; + skb_pull(skb, pkt_len_plus_padd); // Skip invalid packet + continue; + } - skb->truesize = SKB_TRUESIZE(pkt_len_plus_padd); - ax88179_rx_checksum(skb, pkt_hdr); - return 1; - } + /* Handle the last packet */ + if (pkt_len_plus_padd == skb->len) { + skb_trim(skb, pkt_len); - ax_skb = skb_clone(skb, GFP_ATOMIC); - if (!ax_skb) - return 0; - skb_trim(ax_skb, pkt_len); + /* Skip IP alignment pseudo header */ + skb_pull(skb, 2); - /* Skip IP alignment pseudo header */ - skb_pull(ax_skb, 2); + skb->truesize = SKB_TRUESIZE(pkt_len_plus_padd); + ax88179_rx_checksum(skb, pkt_hdr); + return 1; + } - skb->truesize = pkt_len_plus_padd + - SKB_DATA_ALIGN(sizeof(struct sk_buff)); - ax88179_rx_checksum(ax_skb, pkt_hdr); - usbnet_skb_return(dev, ax_skb); + /* Clone the skb for further processing */ + ax_skb = skb_clone(skb, GFP_ATOMIC); + if (!ax_skb) + return 0; - skb_pull(skb, pkt_len_plus_padd); - } + skb_trim(ax_skb, pkt_len); - return 0; + /* Skip IP alignment pseudo header */ + skb_pull(ax_skb, 2); + + skb->truesize = pkt_len_plus_padd + SKB_DATA_ALIGN(sizeof(struct sk_buff)); + ax88179_rx_checksum(ax_skb, pkt_hdr); + usbnet_skb_return(dev, ax_skb); + + skb_pull(skb, pkt_len_plus_padd); // Remove the processed packet from skb + } + + return 0; } static struct sk_buff * -- Gitee