[前][次][番号順一覧][スレッド一覧]

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/

[前][次][番号順一覧][スレッド一覧]