From: Roy Marples Date: Wed, 16 Oct 2019 13:56:21 +0000 (+0100) Subject: DHCP: Fix strict aliasing of checksumming the pseudo header X-Git-Tag: v8.1.1~2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=ec9fe8039fedacd6eaa7cbdfebab7838826ef030;p=thirdparty%2Fdhcpcd.git DHCP: Fix strict aliasing of checksumming the pseudo header in_cksum relies on accessing the data by uint16_t blocks. Because the underlying object we send to in_cksum is struct ip, we need to use union to allow access by uint16_t so strict aliasing rules are not broken. --- diff --git a/src/dhcp.c b/src/dhcp.c index c989843b..356b7708 100644 --- a/src/dhcp.c +++ b/src/dhcp.c @@ -3313,13 +3313,15 @@ checksums_valid(void *packet, struct in_addr *from, unsigned int flags) { struct ip *ip = packet; - struct ip pseudo_ip = { - .ip_p = IPPROTO_UDP, - .ip_src = ip->ip_src, - .ip_dst = ip->ip_dst + union pip { + struct ip ip; + uint16_t w[sizeof(struct ip)]; + } pip = { + .ip.ip_p = IPPROTO_UDP, + .ip.ip_src = ip->ip_src, + .ip.ip_dst = ip->ip_dst, }; size_t ip_hlen; - uint16_t udp_len, uh_sum; struct udphdr udp; char *udpp, *uh_sump; uint32_t csum; @@ -3341,22 +3343,23 @@ checksums_valid(void *packet, /* UDP checksum is based on a pseudo IP header alongside * the UDP header and payload. */ - udp_len = ntohs(udp.uh_ulen); - uh_sum = udp.uh_sum; + pip.ip.ip_len = udp.uh_ulen; + csum = 0; /* Need to zero the UDP sum in the packet for the checksum to work. */ uh_sump = udpp + offsetof(struct udphdr, uh_sum); memset(uh_sump, 0, sizeof(udp.uh_sum)); - pseudo_ip.ip_len = udp.uh_ulen; - csum = 0; - in_cksum(&pseudo_ip, sizeof(pseudo_ip), &csum); - csum = in_cksum(udpp, udp_len, &csum); + /* Checksum psuedo header and then UDP + payload. */ + in_cksum(pip.w, sizeof(pip.w), &csum); + csum = in_cksum(udpp, ntohs(udp.uh_ulen), &csum); +#if 0 /* Not needed, just here for completeness. */ /* Put the checksum back. */ - memcpy(uh_sump, &uh_sum, sizeof(udp.uh_sum)); + memcpy(uh_sump, &udp.uh_sum, sizeof(udp.uh_sum)); +#endif - return csum == uh_sum; + return csum == udp.uh_sum; } static void