From a2c7d3e8b058a2013aa8da5986d1d11fa13d6fd7 Mon Sep 17 00:00:00 2001 From: Ambroz Bizjak Date: Fri, 3 Feb 2012 18:15:01 -0200 Subject: [PATCH] Fix unaligned memory access in hash function Use a function to properly get an unsigned short from memory that is possibly unaligned. Note that it implicitly fixes a small bug in the hash function that was introduced when modifying the eina code: the line "hash ^= key[2] << 18;" is supposed to be accessing the 3rd byte of the remainder of the input, but when 'it' was introduced, 'key' ('data' in eina code) was no longer incremented, so this ended up accessing the 3rd byte of the input from the beginning. This is fixed by iterating over 'key', like the eina code does. Before this patch depmod was failing on ARMv5 and possibly others that don't have unaligned access. They do not calculate correctly the dependencies as shown below: [root@alarm ~]# modinfo bridge filename: /lib/modules/2.6.39.4/kernel/net/bridge/bridge.ko version: 2.3 license: GPL srcversion: 6B583530AE2B39C7E2317BF depends: stp,llc vermagic: 2.6.39.4 preempt mod_unload ARMv5 [root@alarm ~]# depmod [root@alarm ~]# cat /lib/modules/2.6.39.4/modules.dep |grep bridge kernel/net/bridge/bridge.ko: [root@alarm ~]# See how modinfo properly lists the dependencies, but modules.dep which depmod generates does not contain them. As a result, most kernel modules fail to load because their dependencies are not loaded by modprobe. --- libkmod/libkmod-hash.c | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/libkmod/libkmod-hash.c b/libkmod/libkmod-hash.c index f58e9db..3a6c8bf 100644 --- a/libkmod/libkmod-hash.c +++ b/libkmod/libkmod-hash.c @@ -83,6 +83,15 @@ void hash_free(struct hash *hash) free(hash); } +struct unaligned_short { + unsigned short v; +} __attribute__((packed)); + +static inline unsigned short get16bits(const char *ptr) +{ + return ((struct unaligned_short *)ptr)->v; +} + static inline unsigned int hash_superfast(const char *key, unsigned int len) { /* Paul Hsieh (http://www.azillionmonkeys.com/qed/hash.html) @@ -90,36 +99,35 @@ static inline unsigned int hash_superfast(const char *key, unsigned int len) * EFL's eina and possible others. */ unsigned int tmp, hash = len, rem = len & 3; - const unsigned short *itr = (const unsigned short *)key; len /= 4; /* Main loop */ for (; len > 0; len--) { - hash += itr[0]; - tmp = (itr[1] << 11) ^ hash; + hash += get16bits(key); + tmp = (get16bits(key + 2) << 11) ^ hash; hash = (hash << 16) ^ tmp; - itr += 2; + key += 4; hash += hash >> 11; } /* Handle end cases */ switch (rem) { case 3: - hash += *itr; + hash += get16bits(key); hash ^= hash << 16; hash ^= key[2] << 18; hash += hash >> 11; break; case 2: - hash += *itr; + hash += get16bits(key); hash ^= hash << 11; hash += hash >> 17; break; case 1: - hash += *(const char *)itr; + hash += *key; hash ^= hash << 10; hash += hash >> 1; } -- 2.7.4