From: Martin Schwenke Date: Mon, 13 Aug 2018 02:18:51 +0000 (+1000) Subject: ctdb-common: Fix aliasing issue in IPv6 checksum X-Git-Tag: tdb-1.3.17~2032 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=48335725deecdbdb24a9176cf31e9611c9deda49;p=thirdparty%2Fsamba.git ctdb-common: Fix aliasing issue in IPv6 checksum Since commit 9c51b278b1700cd5f3e2addc19b7c711cc2ea10b the compiler has been able to inline the affected call to uint16_checksum(). Given that the data (phdr) is being accessed by an incompatible pointer (data) there is an aliasing problem when the call is inlined. This results in incorrect behaviour with -O2/-O3 when compiling with at least GCC 6, 7, and 8. Fix this by making the types compatible. Also fixes CID 1437604 (Reliance on integer endianness). This is a false positive because the uint16_checksum doesn't depend on the order of the input uint16_t items. https://bugzilla.samba.org/show_bug.cgi?id=13588 Pair-programmed-with: Amitay Isaacs Signed-off-by: Martin Schwenke Reviewed-by: Amitay Isaacs --- diff --git a/ctdb/common/system_socket.c b/ctdb/common/system_socket.c index 22776f73ea5..4a7a8c8c464 100644 --- a/ctdb/common/system_socket.c +++ b/ctdb/common/system_socket.c @@ -135,16 +135,20 @@ static uint16_t ip_checksum(uint16_t *data, size_t n, struct ip *ip) static uint16_t ip6_checksum(uint16_t *data, size_t n, struct ip6_hdr *ip6) { - uint32_t phdr[2]; + uint16_t phdr[3]; uint32_t sum = 0; uint16_t sum2; + uint32_t len; sum += uint16_checksum((uint16_t *)(void *)&ip6->ip6_src, 16); sum += uint16_checksum((uint16_t *)(void *)&ip6->ip6_dst, 16); - phdr[0] = htonl(n); - phdr[1] = htonl(ip6->ip6_nxt); - sum += uint16_checksum((uint16_t *)phdr, 8); + len = htonl(n); + phdr[0] = len & UINT16_MAX; + phdr[1] = (len >> 16) & UINT16_MAX; + /* ip6_nxt is only 8 bits, so fits comfortably into a uint16_t */ + phdr[2] = htons(ip6->ip6_nxt); + sum += uint16_checksum(phdr, sizeof(phdr)); sum += uint16_checksum(data, n);