Skip to content

Commit

Permalink
-This line, and those below, will be ignored--
Browse files Browse the repository at this point in the history
M    ruby_1_8_7/ChangeLog
M    ruby_1_8_7/inits.c
M    ruby_1_8_7/version.h
M    ruby_1_8_7/string.c
M    ruby_1_8_7/st.c
M    ruby_1_8_7/test/ruby/test_string.rb
M    ruby_1_8_7/random.c


git-svn-id: http://svn.ruby-lang.org/repos/ruby/branches/ruby_1_8_7@34151 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
  • Loading branch information
shyouhei committed Dec 28, 2011
1 parent f694cb0 commit e05ee61
Show file tree
Hide file tree
Showing 7 changed files with 123 additions and 23 deletions.
26 changes: 26 additions & 0 deletions ChangeLog
Original file line number Original file line Diff line number Diff line change
@@ -1,3 +1,29 @@
Wed Dec 28 21:34:23 2011 URABE Shyouhei <shyouhei@ruby-lang.org>

* string.c (rb_str_hash): randomize hash to avoid algorithmic
complexity attacks. CVE-2011-4815

* st.c (strhash): ditto.

* string.c (Init_String): initialization of hash_seed to be at the
beginning of the process.

* st.c (Init_st): ditto.

Thu Dec 8 11:57:04 2011 Tanaka Akira <akr@fsij.org>

* inits.c (rb_call_inits): call Init_RandomSeed at first.

* random.c (seed_initialized): defined.
(fill_random_seed): extracted from random_seed.
(make_seed_value): extracted from random_seed.
(rb_f_rand): initialize random seed at first.
(initial_seed): defined.
(Init_RandomSeed): defined.
(Init_RandomSeed2): defined.
(rb_reset_random_seed): defined.
(Init_Random): call Init_RandomSeed2.

Sat Dec 10 20:44:23 2011 Tanaka Akira <akr@fsij.org> Sat Dec 10 20:44:23 2011 Tanaka Akira <akr@fsij.org>


* lib/securerandom.rb: call OpenSSL::Random.seed at the * lib/securerandom.rb: call OpenSSL::Random.seed at the
Expand Down
4 changes: 4 additions & 0 deletions inits.c
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ void Init_Precision _((void));
void Init_sym _((void)); void Init_sym _((void));
void Init_process _((void)); void Init_process _((void));
void Init_Random _((void)); void Init_Random _((void));
void Init_RandomSeed _((void));
void Init_Range _((void)); void Init_Range _((void));
void Init_Regexp _((void)); void Init_Regexp _((void));
void Init_signal _((void)); void Init_signal _((void));
Expand All @@ -46,10 +47,13 @@ void Init_Struct _((void));
void Init_Time _((void)); void Init_Time _((void));
void Init_var_tables _((void)); void Init_var_tables _((void));
void Init_version _((void)); void Init_version _((void));
void Init_st _((void));


void void
rb_call_inits() rb_call_inits()
{ {
Init_RandomSeed();
Init_st();
Init_sym(); Init_sym();
Init_var_tables(); Init_var_tables();
Init_Object(); Init_Object();
Expand Down
74 changes: 57 additions & 17 deletions random.c
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -189,6 +189,7 @@ rb_genrand_real(void)
#include <fcntl.h> #include <fcntl.h>
#endif #endif


static int seed_initialized = 0;
static VALUE saved_seed = INT2FIX(0); static VALUE saved_seed = INT2FIX(0);


static VALUE static VALUE
Expand Down Expand Up @@ -250,27 +251,22 @@ rand_init(vseed)
return old; return old;
} }


static VALUE #define DEFAULT_SEED_LEN (4 * sizeof(long))
random_seed()
static void
fill_random_seed(ptr)
char *ptr;
{ {
static int n = 0; static int n = 0;
unsigned long *seed;
struct timeval tv; struct timeval tv;
int fd; int fd;
struct stat statbuf; struct stat statbuf;
char *buf = (char*)ptr;


int seed_len; seed = (unsigned long *)buf;
BDIGIT *digits;
unsigned long *seed;
NEWOBJ(big, struct RBignum);
OBJSETUP(big, rb_cBignum, T_BIGNUM);

seed_len = 4 * sizeof(long);
big->sign = 1;
big->len = seed_len / SIZEOF_BDIGITS + 1;
digits = big->digits = ALLOC_N(BDIGIT, big->len);
seed = (unsigned long *)big->digits;


memset(digits, 0, big->len * SIZEOF_BDIGITS); memset(buf, 0, DEFAULT_SEED_LEN);


#ifdef S_ISCHR #ifdef S_ISCHR
if ((fd = open("/dev/urandom", O_RDONLY if ((fd = open("/dev/urandom", O_RDONLY
Expand All @@ -285,7 +281,7 @@ random_seed()
#endif #endif
)) >= 0) { )) >= 0) {
if (fstat(fd, &statbuf) == 0 && S_ISCHR(statbuf.st_mode)) { if (fstat(fd, &statbuf) == 0 && S_ISCHR(statbuf.st_mode)) {
read(fd, seed, seed_len); read(fd, seed, DEFAULT_SEED_LEN);
} }
close(fd); close(fd);
} }
Expand All @@ -296,13 +292,37 @@ random_seed()
seed[1] ^= tv.tv_sec; seed[1] ^= tv.tv_sec;
seed[2] ^= getpid() ^ (n++ << 16); seed[2] ^= getpid() ^ (n++ << 16);
seed[3] ^= (unsigned long)&seed; seed[3] ^= (unsigned long)&seed;
}

static VALUE
make_seed_value(char *ptr)
{
BDIGIT *digits;
NEWOBJ(big, struct RBignum);
OBJSETUP(big, rb_cBignum, T_BIGNUM);

RBIGNUM_SET_SIGN(big, 1);

digits = ALLOC_N(char, DEFAULT_SEED_LEN);
RBIGNUM(big)->digits = digits;
RBIGNUM(big)->len = DEFAULT_SEED_LEN / SIZEOF_BDIGITS;

MEMCPY(digits, ptr, char, DEFAULT_SEED_LEN);


/* set leading-zero-guard if need. */ /* set leading-zero-guard if need. */
digits[big->len-1] = digits[big->len-2] <= 1 ? 1 : 0; digits[RBIGNUM_LEN(big)-1] = digits[RBIGNUM_LEN(big)-2] <= 1 ? 1 : 0;


return rb_big_norm((VALUE)big); return rb_big_norm((VALUE)big);
} }


static VALUE
random_seed(void)
{
char buf[DEFAULT_SEED_LEN];
fill_random_seed(buf);
return make_seed_value(buf);
}

/* /*
* call-seq: * call-seq:
* srand(number=0) => old_seed * srand(number=0) => old_seed
Expand Down Expand Up @@ -443,6 +463,9 @@ rb_f_rand(argc, argv, obj)
long val, max; long val, max;


rb_scan_args(argc, argv, "01", &vmax); rb_scan_args(argc, argv, "01", &vmax);
if (!seed_initialized) {
rand_init(random_seed());
}
switch (TYPE(vmax)) { switch (TYPE(vmax)) {
case T_FLOAT: case T_FLOAT:
if (RFLOAT(vmax)->value <= LONG_MAX && RFLOAT(vmax)->value >= LONG_MIN) { if (RFLOAT(vmax)->value <= LONG_MAX && RFLOAT(vmax)->value >= LONG_MIN) {
Expand Down Expand Up @@ -490,16 +513,33 @@ rb_f_rand(argc, argv, obj)
return LONG2NUM(val); return LONG2NUM(val);
} }


static char initial_seed[DEFAULT_SEED_LEN];

void void
rb_reset_random_seed() rb_reset_random_seed()
{ {
rand_init(random_seed()); rand_init(random_seed());
} }


void
Init_RandomSeed(void)
{
fill_random_seed(initial_seed);
init_by_array((unsigned long*)initial_seed, DEFAULT_SEED_LEN/sizeof(unsigned long));
seed_initialized = 1;
}

static void
Init_RandomSeed2(void)
{
saved_seed = make_seed_value(initial_seed);
memset(initial_seed, 0, DEFAULT_SEED_LEN);
}

void void
Init_Random() Init_Random()
{ {
rb_reset_random_seed(); Init_RandomSeed2();
rb_define_global_function("srand", rb_f_srand, -1); rb_define_global_function("srand", rb_f_srand, -1);
rb_define_global_function("rand", rb_f_rand, -1); rb_define_global_function("rand", rb_f_rand, -1);
rb_global_variable(&saved_seed); rb_global_variable(&saved_seed);
Expand Down
14 changes: 13 additions & 1 deletion st.c
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include <stdlib.h> #include <stdlib.h>
#endif #endif
#include <string.h> #include <string.h>
#include <limits.h>
#include "st.h" #include "st.h"


typedef struct st_table_entry st_table_entry; typedef struct st_table_entry st_table_entry;
Expand Down Expand Up @@ -521,6 +522,8 @@ st_foreach(table, func, arg)
return 0; return 0;
} }


static unsigned long hash_seed = 0;

static int static int
strhash(string) strhash(string)
register const char *string; register const char *string;
Expand Down Expand Up @@ -550,10 +553,11 @@ strhash(string)


return val + (val << 15); return val + (val << 15);
#else #else
register int val = 0; register unsigned long val = hash_seed;


while ((c = *string++) != '\0') { while ((c = *string++) != '\0') {
val = val*997 + c; val = val*997 + c;
val = (val << 13) | (val >> (sizeof(st_data_t) * CHAR_BIT - 13));
} }


return val + (val>>5); return val + (val>>5);
Expand All @@ -573,3 +577,11 @@ numhash(n)
{ {
return n; return n;
} }

extern unsigned long rb_genrand_int32(void);

void
Init_st(void)
{
hash_seed = rb_genrand_int32();
}
7 changes: 6 additions & 1 deletion string.c
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -875,13 +875,15 @@ rb_str_concat(str1, str2)
return str1; return str1;
} }


static unsigned long hash_seed;

int int
rb_str_hash(str) rb_str_hash(str)
VALUE str; VALUE str;
{ {
register long len = RSTRING(str)->len; register long len = RSTRING(str)->len;
register char *p = RSTRING(str)->ptr; register char *p = RSTRING(str)->ptr;
register int key = 0; register unsigned long key = hash_seed;


#if defined(HASH_ELFHASH) #if defined(HASH_ELFHASH)
register unsigned int g; register unsigned int g;
Expand All @@ -905,6 +907,7 @@ rb_str_hash(str)
while (len--) { while (len--) {
key = key*65599 + *p; key = key*65599 + *p;
p++; p++;
key = (key << 13) | (key >> ((sizeof(unsigned long) * CHAR_BIT) - 13));
} }
key = key + (key>>5); key = key + (key>>5);
#endif #endif
Expand Down Expand Up @@ -5062,4 +5065,6 @@ Init_String()
rb_fs = Qnil; rb_fs = Qnil;
rb_define_variable("$;", &rb_fs); rb_define_variable("$;", &rb_fs);
rb_define_variable("$-F", &rb_fs); rb_define_variable("$-F", &rb_fs);

hash_seed = rb_genrand_int32();
} }
13 changes: 13 additions & 0 deletions test/ruby/test_string.rb
Original file line number Original file line Diff line number Diff line change
@@ -1,4 +1,5 @@
require 'test/unit' require 'test/unit'
require File.expand_path('envutil', File.dirname(__FILE__))


class TestString < Test::Unit::TestCase class TestString < Test::Unit::TestCase
def check_sum(str, bits=16) def check_sum(str, bits=16)
Expand Down Expand Up @@ -29,4 +30,16 @@ def test_inspect
ensure ensure
$KCODE = original_kcode $KCODE = original_kcode
end end

def test_hash_random
str = 'abc'
a = [str.hash.to_s]
cmd = sprintf("%s -e 'print %s.hash'", EnvUtil.rubybin, str.dump)
3.times {
IO.popen(cmd, "rb") {|o|
a << o.read
}
}
assert_not_equal([str.hash.to_s], a.uniq)
end
end end
8 changes: 4 additions & 4 deletions version.h
Original file line number Original file line Diff line number Diff line change
@@ -1,15 +1,15 @@
#define RUBY_VERSION "1.8.7" #define RUBY_VERSION "1.8.7"
#define RUBY_RELEASE_DATE "2011-12-10" #define RUBY_RELEASE_DATE "2011-12-28"
#define RUBY_VERSION_CODE 187 #define RUBY_VERSION_CODE 187
#define RUBY_RELEASE_CODE 20111210 #define RUBY_RELEASE_CODE 20111228
#define RUBY_PATCHLEVEL 356 #define RUBY_PATCHLEVEL 357


#define RUBY_VERSION_MAJOR 1 #define RUBY_VERSION_MAJOR 1
#define RUBY_VERSION_MINOR 8 #define RUBY_VERSION_MINOR 8
#define RUBY_VERSION_TEENY 7 #define RUBY_VERSION_TEENY 7
#define RUBY_RELEASE_YEAR 2011 #define RUBY_RELEASE_YEAR 2011
#define RUBY_RELEASE_MONTH 12 #define RUBY_RELEASE_MONTH 12
#define RUBY_RELEASE_DAY 10 #define RUBY_RELEASE_DAY 28


#ifdef RUBY_EXTERN #ifdef RUBY_EXTERN
RUBY_EXTERN const char ruby_version[]; RUBY_EXTERN const char ruby_version[];
Expand Down

0 comments on commit e05ee61

Please sign in to comment.