diff options
author | Martin Schwenke <martin@meltin.net> | 2018-08-13 12:18:51 +1000 |
---|---|---|
committer | Amitay Isaacs <amitay@samba.org> | 2018-08-24 10:59:20 +0200 |
commit | 48335725deecdbdb24a9176cf31e9611c9deda49 (patch) | |
tree | 7f188c03b8acd4dbcddab4e98e9be677fb4811be /ctdb | |
parent | 0f3f63f2d80b023eab9da0db14d65a9069f9e2c4 (diff) | |
download | samba-48335725deecdbdb24a9176cf31e9611c9deda49.tar.gz |
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 <amitay@gmail.com>
Signed-off-by: Martin Schwenke <martin@meltin.net>
Reviewed-by: Amitay Isaacs <amitay@gmail.com>
Diffstat (limited to 'ctdb')
-rw-r--r-- | ctdb/common/system_socket.c | 12 |
1 files changed, 8 insertions, 4 deletions
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); |