luci-base: further hash calculation signedness bugfixes
authorJo-Philipp Wich <jo@mein.io>
Mon, 19 Nov 2018 12:28:52 +0000 (13:28 +0100)
committerJo-Philipp Wich <jo@mein.io>
Mon, 19 Nov 2018 12:31:43 +0000 (13:31 +0100)
 - cbi.js: make sure to treat single bytes as signed char when
   handling end cases

 - template_lmo.c: make sure to treat single bytes as signed
   char when handling end cases, avoids hash miscalculations
   on ARM

Signed-off-by: Jo-Philipp Wich <jo@mein.io>
modules/luci-base/htdocs/luci-static/resources/cbi.js
modules/luci-base/src/template_lmo.c

index 0e959068129a540496c641b99dc24393b7c41470..1607b9af653d48b97848a49b78dca202a64e2cfb 100644 (file)
@@ -15,6 +15,15 @@ var cbi_d = [];
 var cbi_t = [];
 var cbi_strings = { path: {}, label: {} };
 
+function s8(bytes, off) {
+       var n = bytes[off];
+       return (n > 0x7F) ? (n - 256) >>> 0 : n;
+}
+
+function u16(bytes, off) {
+       return ((bytes[off + 1] << 8) + bytes[off]) >>> 0;
+}
+
 function sfh(s) {
        if (s === null || s.length === 0)
                return null;
@@ -48,8 +57,8 @@ function sfh(s) {
            off = 0, tmp;
 
        while (len--) {
-               hash += ((bytes[off + 1] << 8) + bytes[off]) >>> 0;
-               tmp   = ((((bytes[off + 3] << 8) + bytes[off + 2]) << 11) ^ hash) >>> 0;
+               hash += u16(bytes, off);
+               tmp   = ((u16(bytes, off + 2) << 11) ^ hash) >>> 0;
                hash  = ((hash << 16) ^ tmp) >>> 0;
                hash += hash >>> 11;
                off  += 4;
@@ -57,20 +66,20 @@ function sfh(s) {
 
        switch ((bytes.length & 3) >>> 0) {
        case 3:
-               hash += ((bytes[off + 1] << 8) + bytes[off]) >>> 0;
+               hash += u16(bytes, off);
                hash  = (hash ^ (hash << 16)) >>> 0;
-               hash  = (hash ^ (bytes[off + 2] << 18)) >>> 0;
+               hash  = (hash ^ (s8(bytes, off + 2) << 18)) >>> 0;
                hash += hash >>> 11;
                break;
 
        case 2:
-               hash += ((bytes[off + 1] << 8) + bytes[off]) >>> 0;
+               hash += u16(bytes, off);
                hash  = (hash ^ (hash << 11)) >>> 0;
                hash += hash >>> 17;
                break;
 
        case 1:
-               hash += bytes[off];
+               hash += s8(bytes, off);
                hash  = (hash ^ (hash << 10)) >>> 0;
                hash += hash >>> 1;
                break;
index cd4c609a743f36f42be8853cd0a43e42c61610bc..f7a118c9bbd41a4e8bde6b6dcca740a78787abc7 100644 (file)
@@ -46,14 +46,14 @@ uint32_t sfh_hash(const char *data, int len)
        switch (rem) {
                case 3: hash += sfh_get16(data);
                        hash ^= hash << 16;
-                       hash ^= data[sizeof(uint16_t)] << 18;
+                       hash ^= (signed char)data[sizeof(uint16_t)] << 18;
                        hash += hash >> 11;
                        break;
                case 2: hash += sfh_get16(data);
                        hash ^= hash << 11;
                        hash += hash >> 17;
                        break;
-               case 1: hash += *data;
+               case 1: hash += (signed char)*data;
                        hash ^= hash << 10;
                        hash += hash >> 1;
        }