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
