Hi Esteban,

On 21/08/2026 09:07, Esteban Alba via B4 Relay wrote:
> From: Esteban Alba <[email protected]>
> 
> net_ip6_handler() checks the received length only against IP6_HDR_SIZE and
> then uses length fields from the packet without checking them. The checksum
> is computed over payload_len, but the UDP handler length comes from
> udp_len. A sender can keep payload_len correct so the checksum still
> validates and set udp_len larger than the frame. A handler that trusts that
> length then reads or writes past the receive buffer. The DHCPv6 client
> copies the declared number of bytes and can be made to write past the
> packet buffer from a single link-local ADVERTISE.
> 
> Validate payload_len against the received length and trim len to it before
> protocol dispatch. Validate the ICMPv6 and UDP header sizes before either
> header is dereferenced, and validate udp_len before reading udp_xsum or
> calling the UDP handler.
> 
> Fixes: 1feb697830ce ("net: ipv6: Add implementation of main IPv6 functions")
> Suggested-by: Jerome Forissier <[email protected]>
> Signed-off-by: Esteban Alba <[email protected]>
> ---
> Validate the IPv6 payload length against the received frame before protocol
> dispatch, then validate the ICMPv6 and UDP transport header sizes and
> udp_len before either header is dereferenced or the UDP handler is called.
> ---
> Changes in v2:
> - Move payload_len reconciliation before protocol dispatch.
> - Validate ICMPv6 and UDP header sizes before dereferencing their headers.
> - Validate udp_len before reading udp_xsum or dispatching to the UDP handler.
> - Link to v1: 
> https://patch.msgid.link/[email protected]
> 
> To: [email protected]
> Cc: Ramon Fried <[email protected]>
> Cc: Jerome Forissier <[email protected]>
> Cc: Tom Rini <[email protected]>
> Cc: Viacheslav Mitrofanov <[email protected]>
> Cc: Simon Glass <[email protected]>
> ---
>  net/net6.c | 18 ++++++++++++++++--
>  1 file changed, 16 insertions(+), 2 deletions(-)
> 
> diff --git a/net/net6.c b/net/net6.c
> index 4cff98df15..e1a455748e 100644
> --- a/net/net6.c
> +++ b/net/net6.c
> @@ -392,11 +392,19 @@ int net_ip6_handler(struct ethernet_hdr *et, struct 
> ip6_hdr *ip6, int len)
>       if (ip6->version != 6)
>               return -EINVAL;
>  
> +     hlen = ntohs(ip6->payload_len);
> +
> +     if (len < IP6_HDR_SIZE + hlen)
> +             return -EINVAL;
> +     len = IP6_HDR_SIZE + hlen;
> +
>       switch (ip6->nexthdr) {
>       case PROT_ICMPV6:
> +             if (hlen < sizeof(struct icmp6hdr))
> +                     return -EINVAL;
> +
>               icmp = (struct icmp6hdr *)(((uchar *)ip6) + IP6_HDR_SIZE);
>               csum = icmp->icmp6_cksum;
> -             hlen = ntohs(ip6->payload_len);
>               icmp->icmp6_cksum = 0;
>               /* checksum */
>               csum_p = csum_partial((u8 *)icmp, hlen, 0);
> @@ -421,9 +429,15 @@ int net_ip6_handler(struct ethernet_hdr *et, struct 
> ip6_hdr *ip6, int len)
>               }
>               break;
>       case IPPROTO_UDP:
> +             if (hlen < UDP_HDR_SIZE)
> +                     return -EINVAL;
> +
>               udp = (struct udp_hdr *)(((uchar *)ip6) + IP6_HDR_SIZE);
> +             if (ntohs(udp->udp_len) < UDP_HDR_SIZE ||
> +                 ntohs(udp->udp_len) > hlen)
> +                     return -EINVAL;
> +
>               csum = udp->udp_xsum;
> -             hlen = ntohs(ip6->payload_len);
>               udp->udp_xsum = 0;
>               /* checksum */
>               csum_p = csum_partial((u8 *)udp, hlen, 0);
> 
> ---
> base-commit: ece349ade2973e220f524ce59e59711cc919263f
> change-id: 20260807-net6-len-validation-cd71efd96a7f
> 
> Best regards,
> --  
> Esteban Alba <[email protected]>

Reviewed-by: Jerome Forissier <[email protected]>

Thanks,
-- 
Jerome

Reply via email to