ruby-changes:5957
From: akr <ko1@a...>
Date: Fri, 20 Jun 2008 11:48:00 +0900 (JST)
Subject: [ruby-changes:5957] Ruby:r17465 (trunk): * string.c (rb_memhash): randomize hash to avoid algorithmic
akr 2008-06-20 11:46:17 +0900 (Fri, 20 Jun 2008) New Revision: 17465 Modified files: trunk/ChangeLog trunk/include/ruby/intern.h trunk/inits.c trunk/random.c trunk/string.c trunk/test/ruby/test_string.rb trunk/thread.c Log: * string.c (rb_memhash): randomize hash to avoid algorithmic complexity attacks. (rb_str_hash): use rb_memhash. * include/ruby/intern.h (rb_reset_random_seed): declared. * thread.c (rb_thread_atfork): call rb_reset_random_seed. * 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. http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/test/ruby/test_string.rb?r1=17465&r2=17464&diff_format=u http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/string.c?r1=17465&r2=17464&diff_format=u http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/ChangeLog?r1=17465&r2=17464&diff_format=u http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/thread.c?r1=17465&r2=17464&diff_format=u http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/inits.c?r1=17465&r2=17464&diff_format=u http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/random.c?r1=17465&r2=17464&diff_format=u http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/include/ruby/intern.h?r1=17465&r2=17464&diff_format=u Index: include/ruby/intern.h =================================================================== --- include/ruby/intern.h (revision 17464) +++ include/ruby/intern.h (revision 17465) @@ -475,6 +475,7 @@ /* random.c */ unsigned long rb_genrand_int32(void); double rb_genrand_real(void); +void rb_reset_random_seed(void); /* re.c */ #define rb_memcmp memcmp int rb_memcicmp(const void*,const void*,long); Index: ChangeLog =================================================================== --- ChangeLog (revision 17464) +++ ChangeLog (revision 17465) @@ -1,3 +1,25 @@ +Fri Jun 20 11:07:56 2008 Tanaka Akira <akr@f...> + + * string.c (rb_memhash): randomize hash to avoid algorithmic + complexity attacks. + (rb_str_hash): use rb_memhash. + + * include/ruby/intern.h (rb_reset_random_seed): declared. + + * thread.c (rb_thread_atfork): call rb_reset_random_seed. + + * 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. + Wed Jun 18 21:52:38 2008 URABE Shyouhei <shyouhei@r...> * array.c (ary_new, rb_ary_initialize, rb_ary_store, Index: string.c =================================================================== --- string.c (revision 17464) +++ string.c (revision 17465) @@ -1820,13 +1820,21 @@ int rb_memhash(const void *ptr, long len) { - return hash(ptr, len, 0); + static int hashseed_init = 0; + static unsigned int hashseed; + + if (!hashseed_init) { + hashseed = rb_genrand_int32(); + hashseed_init = 1; + } + + return hash(ptr, len, hashseed); } int rb_str_hash(VALUE str) { - return hash((const void *)RSTRING_PTR(str), RSTRING_LEN(str), 0); + return rb_memhash((const void *)RSTRING_PTR(str), RSTRING_LEN(str)); } int Index: thread.c =================================================================== --- thread.c (revision 17464) +++ thread.c (revision 17465) @@ -2124,6 +2124,7 @@ st_clear(vm->living_threads); st_insert(vm->living_threads, thval, (st_data_t) th->thread_id); vm->sleeper = 0; + rb_reset_random_seed(); } static int Index: inits.c =================================================================== --- inits.c (revision 17464) +++ inits.c (revision 17465) @@ -38,6 +38,7 @@ void Init_sym(void); void Init_id(void); void Init_process(void); +void Init_RandomSeed(void); void Init_Random(void); void Init_Range(void); void Init_Rational(void); @@ -58,6 +59,7 @@ void rb_call_inits() { + Init_RandomSeed(); Init_sym(); Init_id(); Init_var_tables(); Index: test/ruby/test_string.rb =================================================================== --- test/ruby/test_string.rb (revision 17464) +++ test/ruby/test_string.rb (revision 17465) @@ -683,6 +683,17 @@ assert(S("hello").hash != S("helLO").hash) end + def test_hash_random + str = 'abc' + a = [str.hash.to_s] + 3.times { + EnvUtil.rubyexec("-e", "print #{str.dump}.hash") {|i,o,e| + a << o.read + } + } + assert_not_equal([str.hash.to_s], a.uniq) + end + def test_hex assert_equal(255, S("0xff").hex) assert_equal(-255, S("-0xff").hex) Index: random.c =================================================================== --- random.c (revision 17464) +++ random.c (revision 17465) @@ -199,6 +199,7 @@ return genrand_real(); } +static int seed_initialized = 0; static VALUE saved_seed = INT2FIX(0); static VALUE @@ -259,28 +260,22 @@ return old; } -static VALUE -random_seed(void) +#define DEFAULT_SEED_LEN (4 * sizeof(long)) + +static void +fill_random_seed(char *ptr) { static int n = 0; + unsigned long *seed; struct timeval tv; int fd; struct stat statbuf; + char *buf = (char*)ptr; - int seed_len; - BDIGIT *digits; - unsigned long *seed; - NEWOBJ(big, struct RBignum); - OBJSETUP(big, rb_cBignum, T_BIGNUM); + seed = (unsigned long *)buf; - seed_len = 4 * sizeof(long); - RBIGNUM_SET_SIGN(big, 1); - rb_big_resize((VALUE)big, seed_len / SIZEOF_BDIGITS + 1); - digits = RBIGNUM_DIGITS(big); - seed = (unsigned long *)RBIGNUM_DIGITS(big); + memset(buf, 0, DEFAULT_SEED_LEN); - memset(digits, 0, RBIGNUM_LEN(big) * SIZEOF_BDIGITS); - #ifdef S_ISCHR if ((fd = open("/dev/urandom", O_RDONLY #ifdef O_NONBLOCK @@ -294,7 +289,7 @@ #endif )) >= 0) { if (fstat(fd, &statbuf) == 0 && S_ISCHR(statbuf.st_mode)) { - read(fd, seed, seed_len); + read(fd, seed, DEFAULT_SEED_LEN); } close(fd); } @@ -305,13 +300,35 @@ seed[1] ^= tv.tv_sec; seed[2] ^= getpid() ^ (n++ << 16); 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); + rb_big_resize((VALUE)big, DEFAULT_SEED_LEN / SIZEOF_BDIGITS + 1); + digits = RBIGNUM_DIGITS(big); + + MEMCPY((char *)RBIGNUM_DIGITS(big), ptr, char, DEFAULT_SEED_LEN); + /* set leading-zero-guard if need. */ digits[RBIGNUM_LEN(big)-1] = digits[RBIGNUM_LEN(big)-2] <= 1 ? 1 : 0; 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: * srand(number=0) => old_seed @@ -453,6 +470,9 @@ long val, max; rb_scan_args(argc, argv, "01", &vmax); + if (!seed_initialized) { + rand_init(random_seed()); + } switch (TYPE(vmax)) { case T_FLOAT: if (RFLOAT_VALUE(vmax) <= LONG_MAX && RFLOAT_VALUE(vmax) >= LONG_MIN) { @@ -499,10 +519,34 @@ return LONG2NUM(val); } +static char initial_seed[DEFAULT_SEED_LEN]; + 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 VALUE +Init_RandomSeed2(void) +{ + saved_seed = make_seed_value(initial_seed); + memset(initial_seed, 0, DEFAULT_SEED_LEN); +} + +void +rb_reset_random_seed(void) +{ + seed_initialized = 0; + saved_seed = INT2FIX(0); +} + +void Init_Random(void) { - rand_init(random_seed()); + Init_RandomSeed2(); rb_define_global_function("srand", rb_f_srand, -1); rb_define_global_function("rand", rb_f_rand, -1); rb_global_variable(&saved_seed); -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/