Skip to content
Snippets Groups Projects
Commit 614530bc authored by Romain Geissler's avatar Romain Geissler Committed by Paul Moore
Browse files

hash: fix strict aliasing UB in MurMur hash implementation


This was spotted when trying to upgrade the libseccomp fedora package to
version 2.6.0 in fedora rawhide. It comes with gcc 15 and LTO enabled by
default. When running the test 61-sim-transactions we get plenty of such
errors in valgrind:

==265507== Use of uninitialised value of size 8
==265507==    at 0x4096AD: _hsh_add (gen_bpf.c:599)
==265507==    by 0x40A557: UnknownInlinedFun (gen_bpf.c:2016)
==265507==    by 0x40A557: gen_bpf_generate (gen_bpf.c:2341)
==265507==    by 0x400CDE: UnknownInlinedFun (db.c:2685)
==265507==    by 0x400CDE: UnknownInlinedFun (db.c:2682)
==265507==    by 0x400CDE: UnknownInlinedFun (api.c:756)
==265507==    by 0x400CDE: UnknownInlinedFun (util.c:162)
==265507==    by 0x400CDE: UnknownInlinedFun (util.c:153)
==265507==    by 0x400CDE: main (61-sim-transactions.c:128)
==265507==  Uninitialised value was created by a stack allocation
==265507==    at 0x409590: _hsh_add (gen_bpf.c:573)

Investigating this a bit, it seems that because of LTO the MurMur hash
implementation is being inlined in _hsh_add. The two buffers data and
blocks to point at the same underlying data, but via incompatible type,
which is a strict aliasing violation. Instead, remove the getblock32
function and inline the copy with memcpy.

This is reproducible on a "fedora:rawhide" container (gcc 15) and using:
export CFLAGS='-O2 -flto=auto -ffat-lto-objects -g'

Signed-off-by: default avatarRomain Geissler <romain.geissler@amadeus.com>
Reviewed-by: default avatarSam James <sam@gentoo.org>
Acked-by: default avatarTom Hromatka <tom.hromatka@oracle.com>
[PM: subject line tweak]
Signed-off-by: default avatarPaul Moore <paul@paul-moore.com>
parent 600b1685
No related branches found
No related tags found
No related merge requests found
......@@ -12,15 +12,11 @@
*/
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
#include "hash.h"
static inline uint32_t getblock32(const uint32_t *p, int i)
{
return p[i];
}
static inline uint32_t rotl32(uint32_t x, int8_t r)
{
return (x << r) | (x >> (32 - r));
......@@ -41,7 +37,6 @@ static inline uint32_t fmix32(uint32_t h)
uint32_t hash(const void *key, size_t length)
{
const uint8_t *data = (const uint8_t *)key;
const uint32_t *blocks;
const uint8_t *tail;
const int nblocks = length / 4;
const uint32_t c1 = 0xcc9e2d51;
......@@ -54,9 +49,8 @@ uint32_t hash(const void *key, size_t length)
uint32_t h1 = 0;
/* body */
blocks = (const uint32_t *)(data + nblocks * 4);
for(i = -nblocks; i; i++) {
k1 = getblock32(blocks, i);
memcpy(&k1, data + (nblocks + i) * sizeof(uint32_t), sizeof(uint32_t));
k1 *= c1;
k1 = rotl32(k1, 15);
......@@ -68,7 +62,7 @@ uint32_t hash(const void *key, size_t length)
}
/* tail */
tail = (const uint8_t *)(data + nblocks * 4);
tail = data + nblocks * sizeof(uint32_t);
switch(length & 3) {
case 3:
k2 ^= tail[2] << 16;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment