https://github.com/seccomp/libseccomp/pull/459 From e6904da422e68031b0237c1e005fc5e98c12e2cf Mon Sep 17 00:00:00 2001 From: Romain Geissler Date: Tue, 18 Feb 2025 22:29:05 +0000 Subject: [PATCH] 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 way we call getblock32 with the explicit cast to const uint32_t* is a strict aliasing violation. This is reproducible on a "fedora:rawhide" container (gcc 15) and using: export CFLAGS='-O2 -flto=auto -ffat-lto-objects -g' Signed-off-by: Romain Geissler --- src/hash.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/hash.c b/src/hash.c index 4435900f..301abfc9 100644 --- a/src/hash.c +++ b/src/hash.c @@ -12,15 +12,11 @@ */ #include +#include #include #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)); @@ -56,7 +52,7 @@ uint32_t hash(const void *key, size_t length) /* body */ blocks = (const uint32_t *)(data + nblocks * 4); for(i = -nblocks; i; i++) { - k1 = getblock32(blocks, i); + memcpy(&k1, &blocks[i], sizeof(uint32_t)); k1 *= c1; k1 = rotl32(k1, 15);