Permalink
Browse files

Switch String::hash_str to use Siphash to defeat Hash DOS attempts

  • Loading branch information...
1 parent af17380 commit a9a40fc6a1256bcf6382631b710430105c5dd868 @evanphx evanphx committed Dec 4, 2012
Showing with 149 additions and 0 deletions.
  1. +26 −0 vm/builtin/string.cpp
  2. +1 −0 vm/builtin/string.hpp
  3. +2 −0 vm/environment.cpp
  4. +100 −0 vm/util/siphash.c
  5. +20 −0 vm/util/siphash.h
View
@@ -17,6 +17,8 @@
#include "builtin/tuple.hpp"
#include "util/murmur_hash3.hpp"
+#include "util/siphash.h"
+#include "util/random.h"
#include "configuration.hpp"
#include "vm.hpp"
@@ -43,6 +45,25 @@
namespace rubinius {
+ static uint64_t siphash_key = 0;
+
+ void String::init_hash() {
+ uint32_t seed[4];
+ random_seed(seed, 4);
+
+ // It's important to pull these out into locals so that the compiler
+ // promotes them to 64bits before we do the OR + XOR dance below,
+ // otherwise if it's easy for the compiler to not promote and for
+ // us to just lose the high bits.
+
+ uint64_t s1 = (uint64_t)seed[0];
+ uint64_t s2 = (uint64_t)seed[1];
+ uint64_t s3 = (uint64_t)seed[2];
+ uint64_t s4 = (uint64_t)seed[3];
+
+ siphash_key = (s1 | (s2 << 32)) ^ (s3 | (s4 << 32));
+ }
+
void String::init(STATE) {
GO(string).set(ontology::new_class(state, "String", G(object)));
G(string)->set_object_type(state, StringType);
@@ -639,6 +660,7 @@ namespace rubinius {
}
hashval String::hash_str(const unsigned char *bp, unsigned int sz, uint32_t seed) {
+#ifdef USE_MURMUR3
#ifdef IS_X8664
hashval hv[2];
MurmurHash3_x64_128(bp, sz, seed, hv);
@@ -647,6 +669,10 @@ namespace rubinius {
MurmurHash3_x86_32(bp, sz, seed, hv);
#endif
return hv[0] & FIXNUM_MAX;
+#else
+ uint64_t v = siphash24(siphash_key, seed, bp, sz);
+ return ((hashval)v) & FIXNUM_MAX;
+#endif
}
Symbol* String::to_sym(STATE) {
@@ -83,6 +83,7 @@ namespace rubinius {
/* interface */
+ static void init_hash();
static void init(STATE);
static String* create(STATE, Fixnum* size);
View
@@ -96,6 +96,8 @@ namespace rubinius {
#endif
#endif
+ String::init_hash();
+
VM::init_stack_size();
shared = new SharedState(this, config, config_parser);
View
@@ -0,0 +1,100 @@
+#include "siphash.h"
+
+
+static inline uint64_t rotl64(uint64_t u, int s)
+{
+ return (u << s) | (u >> (64 - s));
+}
+
+
+#define sipround() do { \
+ v0 += v1; \
+ v1 = rotl64(v1, 13); \
+ v1 ^= v0; \
+ v0 = rotl64(v0, 32); \
+ \
+ v2 += v3; \
+ v3 = rotl64(v3, 16); \
+ v3 ^= v2; \
+ \
+ v2 += v1; \
+ v1 = rotl64(v1, 17); \
+ v1 ^= v2; \
+ v2 = rotl64(v2, 32); \
+ \
+ v0 += v3; \
+ v3 = rotl64(v3, 21); \
+ v3 ^= v0; \
+ } while (0)
+
+
+#define sipcompress2(m) do { \
+ v3 ^= m; \
+ \
+ sipround(); \
+ sipround(); \
+ \
+ v0 ^= m; \
+ } while (0)
+
+
+static inline uint64_t get64le(void const* data, size_t ix)
+{
+ uint8_t const* p = (uint8_t const*)data + ix * 8;
+
+ return (uint64_t)p[0] << (0 * 8) |
+ (uint64_t)p[1] << (1 * 8) |
+ (uint64_t)p[2] << (2 * 8) |
+ (uint64_t)p[3] << (3 * 8) |
+ (uint64_t)p[4] << (4 * 8) |
+ (uint64_t)p[5] << (5 * 8) |
+ (uint64_t)p[6] << (6 * 8) |
+ (uint64_t)p[7] << (7 * 8);
+}
+
+
+static inline uint8_t get8(void const* data, size_t ix)
+{
+ return *((uint8_t const*)data + ix);
+}
+
+
+static inline uint64_t siplast(void const* data, size_t size)
+{
+ uint64_t last = 0;
+ size_t i;
+
+ for(i = 0; i < size % 8; ++i) {
+ last |= (uint64_t)get8(data, size / 8 * 8 + i) << (i * 8);
+ }
+ last |= (size % 0xff) << (7 * 8);
+
+ return last;
+}
+
+
+uint64_t siphash24(uint64_t key0, uint64_t key1, void const* data, size_t size)
+{
+ uint64_t v0 = key0 ^ 0x736f6d6570736575ull;
+ uint64_t v1 = key1 ^ 0x646f72616e646f6dull;
+ uint64_t v2 = key0 ^ 0x6c7967656e657261ull;
+ uint64_t v3 = key1 ^ 0x7465646279746573ull;
+ size_t i = 0;
+
+ for(i = 0; i < size / 8; ++i) {
+ uint64_t m = get64le(data, i);
+ sipcompress2(m);
+ }
+ uint64_t m = siplast(data, size);
+ sipcompress2(m);
+
+ v2 ^= 0xff;
+
+ sipround();
+ sipround();
+ sipround();
+ sipround();
+
+ return v0 ^ v1 ^ v2 ^ v3;
+}
+
View
@@ -0,0 +1,20 @@
+#ifndef __SIPHASH_H__
+#define __SIPHASH_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stddef.h>
+#include <stdint.h>
+
+
+uint64_t siphash24(uint64_t key0, uint64_t key1, void const* data, size_t size);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif
+

4 comments on commit a9a40fc

@jc00ke
Member
jc00ke commented on a9a40fc Dec 5, 2012

Curious, from where did you get siphash.c & siphash.h?

@nahi
nahi commented on a9a40fc Dec 12, 2012

CVE-2012-5372

@nahi
nahi commented on a9a40fc Dec 12, 2012

Oops, I didn't intend to post here. The number is assigned from CVE for this issue: http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2012-5372

Please sign in to comment.