summaryrefslogtreecommitdiff
path: root/ctdb
diff options
context:
space:
mode:
authorMartin Schwenke <martin@meltin.net>2018-08-13 12:18:51 +1000
committerAmitay Isaacs <amitay@samba.org>2018-08-24 10:59:20 +0200
commit48335725deecdbdb24a9176cf31e9611c9deda49 (patch)
tree7f188c03b8acd4dbcddab4e98e9be677fb4811be /ctdb
parent0f3f63f2d80b023eab9da0db14d65a9069f9e2c4 (diff)
downloadsamba-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.c12
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);