From 6ac2eb6eeeee86bb5ffaa98791da2b2de73b904f Mon Sep 17 00:00:00 2001 From: Martin Schwenke Date: Mon, 13 Aug 2018 12:18:51 +1000 Subject: [PATCH] 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 (cherry picked from commit 48335725deecdbdb24a9176cf31e9611c9deda49) --- ctdb/common/system_socket.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/ctdb/common/system_socket.c b/ctdb/common/system_socket.c index 62cc782a224..75286795d77 100644 --- a/ctdb/common/system_socket.c +++ b/ctdb/common/system_socket.c @@ -270,16 +270,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); -- 2.18.0