Skip to content
Permalink
Browse files

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

  • Loading branch information...
evanphx committed Dec 4, 2012
1 parent af17380 commit a9a40fc6a1256bcf6382631b710430105c5dd868
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
@@ -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);
@@ -96,6 +96,8 @@ namespace rubinius {
#endif
#endif

String::init_hash();

VM::init_stack_size();

shared = new SharedState(this, config, config_parser);
@@ -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;
}

@@ -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

This comment has been minimized.

Copy link
Member

jc00ke replied Dec 5, 2012

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

@guilleiguaran

This comment has been minimized.

@nahi

This comment has been minimized.

Copy link

nahi replied Dec 12, 2012

CVE-2012-5372

@nahi

This comment has been minimized.

Copy link

nahi replied 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.
You can’t perform that action at this time.