From: Maciej S. Szmigiero <mail@maciej.szmigiero.name>
Date: Tue, 16 Apr 2019 13:00:50 +0000 (+0200)
Subject: Fix strict aliasing violation in inet_checksum()
X-Git-Tag: release-1.1pre18~27
X-Git-Url: https://tinc-vpn.org/git/browse?a=commitdiff_plain;h=f3ba50ed3d14749b7c1ef100d2a49ac30d3b3853;p=tinc

Fix strict aliasing violation in inet_checksum()

inet_checksum() accesses packet data as an array of uint16_t, but the
packet data can be for example of "anonymous struct pseudo" type from
route_ipv6_unreachable().
This type isn't a compatible type with uint16_t so a strict aliasing
violation occurs and causes the checksum to be computed incorrectly.

Fix this by using the memcpy() idiom to read the packet data as an array of
uint16_t in inet_checksum() (this should be understood by compilers and
optimized accordingly, so no actual copy occurs).
---

diff --git a/src/route.c b/src/route.c
index 2e8d94ac..2fa61751 100644
--- a/src/route.c
+++ b/src/route.c
@@ -64,16 +64,18 @@ static timeout_t age_subnets_timeout;
 /* RFC 1071 */
 
 static uint16_t inet_checksum(void *data, int len, uint16_t prevsum) {
-	uint16_t *p = data;
+	uint16_t word;
 	uint32_t checksum = prevsum ^ 0xFFFF;
 
 	while(len >= 2) {
-		checksum += *p++;
+		memcpy(&word, data, sizeof(word));
+		checksum += word;
+		data += 2;
 		len -= 2;
 	}
 
 	if(len) {
-		checksum += *(uint8_t *)p;
+		checksum += *(uint8_t *)data;
 	}
 
 	while(checksum >> 16) {