From: Maciej S. Szmigiero Date: Fri, 13 Sep 2019 09:53:25 +0000 (+0100) Subject: DHCP: Ensure we have enough data to checksum IP and UDP X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=c9fc5a5b7bd0ba2017698efd47fc6eebcbab59b0;p=thirdparty%2Fdhcpcd.git DHCP: Ensure we have enough data to checksum IP and UDP While here, only skip UDP checksum after we have verified we have enough data to be doubly sure. Fixes a regression introduced in dhcpcd-7.2.0 when we started to read from the UDP socket rather than just the BPF socket where these checks are already made. --- diff --git a/src/dhcp.c b/src/dhcp.c index ac523824..3d8e46bd 100644 --- a/src/dhcp.c +++ b/src/dhcp.c @@ -3250,7 +3250,7 @@ valid_udp_packet(void *packet, size_t plen, struct in_addr *from, .ip_dst = ip->ip_dst }; size_t ip_hlen; - uint16_t ip_len, uh_sum; + uint16_t ip_len, udp_len, uh_sum; struct udphdr *udp; uint32_t csum; @@ -3276,27 +3276,31 @@ valid_udp_packet(void *packet, size_t plen, struct in_addr *from, errno = ERANGE; return -1; } - /* Check we don't go beyond the payload */ + /* Check IP doesn't go beyond the payload */ if (ip_len > plen) { errno = ENOBUFS; return -1; } - if (flags & BPF_PARTIALCSUM) + /* Check UDP doesn't go beyond the payload */ + udp = (struct udphdr *)(void *)((char *)ip + ip_hlen); + udp_len = ntohs(udp->uh_ulen); + if (udp_len > plen - ip_hlen) { + errno = ENOBUFS; + return -1; + } + + if (udp->uh_sum == 0 || flags & BPF_PARTIALCSUM) return 0; /* UDP checksum is based on a pseudo IP header alongside * the UDP header and payload. */ - udp = (struct udphdr *)(void *)((char *)ip + ip_hlen); - if (udp->uh_sum == 0) - return 0; - uh_sum = udp->uh_sum; udp->uh_sum = 0; pseudo_ip.ip_len = udp->uh_ulen; csum = 0; in_cksum(&pseudo_ip, sizeof(pseudo_ip), &csum); - csum = in_cksum(udp, ntohs(udp->uh_ulen), &csum); + csum = in_cksum(udp, udp_len, &csum); if (csum != uh_sum) { errno = EINVAL; return -1;