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

ruby-changes:22102

From: shyouhei <ko1@a...>
Date: Wed, 28 Dec 2011 21:47:27 +0900 (JST)
Subject: [ruby-changes:22102] shyouhei:r34151 (ruby_1_8_7): -This line, and those below, will be ignored--

shyouhei	2011-12-28 21:47:15 +0900 (Wed, 28 Dec 2011)

  New Revision: 34151

  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=34151

  Log:
    -This line, and those below, will be ignored--
    
    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

  Modified files:
    branches/ruby_1_8_7/ChangeLog
    branches/ruby_1_8_7/inits.c
    branches/ruby_1_8_7/random.c
    branches/ruby_1_8_7/st.c
    branches/ruby_1_8_7/string.c
    branches/ruby_1_8_7/test/ruby/test_string.rb
    branches/ruby_1_8_7/version.h

Index: ruby_1_8_7/ChangeLog
===================================================================
--- ruby_1_8_7/ChangeLog	(revision 34150)
+++ ruby_1_8_7/ChangeLog	(revision 34151)
@@ -1,3 +1,29 @@
+Wed Dec 28 21:34:23 2011  URABE Shyouhei  <shyouhei@r...>
+
+	* 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@f...>
+
+	* 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@f...>
 
 	* lib/securerandom.rb: call OpenSSL::Random.seed at the
Index: ruby_1_8_7/inits.c
===================================================================
--- ruby_1_8_7/inits.c	(revision 34150)
+++ ruby_1_8_7/inits.c	(revision 34151)
@@ -38,6 +38,7 @@
 void Init_sym _((void));
 void Init_process _((void));
 void Init_Random _((void));
+void Init_RandomSeed _((void));
 void Init_Range _((void));
 void Init_Regexp _((void));
 void Init_signal _((void));
@@ -46,10 +47,13 @@
 void Init_Time _((void));
 void Init_var_tables _((void));
 void Init_version _((void));
+void Init_st _((void));
 
 void
 rb_call_inits()
 {
+    Init_RandomSeed();
+    Init_st();
     Init_sym();
     Init_var_tables();
     Init_Object();
Index: ruby_1_8_7/version.h
===================================================================
--- ruby_1_8_7/version.h	(revision 34150)
+++ ruby_1_8_7/version.h	(revision 34151)
@@ -1,15 +1,15 @@
 #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_RELEASE_CODE 20111210
-#define RUBY_PATCHLEVEL 356
+#define RUBY_RELEASE_CODE 20111228
+#define RUBY_PATCHLEVEL 357
 
 #define RUBY_VERSION_MAJOR 1
 #define RUBY_VERSION_MINOR 8
 #define RUBY_VERSION_TEENY 7
 #define RUBY_RELEASE_YEAR 2011
 #define RUBY_RELEASE_MONTH 12
-#define RUBY_RELEASE_DAY 10
+#define RUBY_RELEASE_DAY 28
 
 #ifdef RUBY_EXTERN
 RUBY_EXTERN const char ruby_version[];
Index: ruby_1_8_7/string.c
===================================================================
--- ruby_1_8_7/string.c	(revision 34150)
+++ ruby_1_8_7/string.c	(revision 34151)
@@ -875,13 +875,15 @@
     return str1;
 }
 
+static unsigned long hash_seed;
+
 int
 rb_str_hash(str)
     VALUE str;
 {
     register long len = RSTRING(str)->len;
     register char *p = RSTRING(str)->ptr;
-    register int key = 0;
+    register unsigned long key = hash_seed;
 
 #if defined(HASH_ELFHASH)
     register unsigned int g;
@@ -905,6 +907,7 @@
     while (len--) {
 	key = key*65599 + *p;
 	p++;
+	key = (key << 13) | (key >> ((sizeof(unsigned long) * CHAR_BIT) - 13));
     }
     key = key + (key>>5);
 #endif
@@ -5062,4 +5065,6 @@
     rb_fs = Qnil;
     rb_define_variable("$;", &rb_fs);
     rb_define_variable("$-F", &rb_fs);
+
+    hash_seed = rb_genrand_int32();
 }
Index: ruby_1_8_7/st.c
===================================================================
--- ruby_1_8_7/st.c	(revision 34150)
+++ ruby_1_8_7/st.c	(revision 34151)
@@ -9,6 +9,7 @@
 #include <stdlib.h>
 #endif
 #include <string.h>
+#include <limits.h>
 #include "st.h"
 
 typedef struct st_table_entry st_table_entry;
@@ -521,6 +522,8 @@
     return 0;
 }
 
+static unsigned long hash_seed = 0;
+
 static int
 strhash(string)
     register const char *string;
@@ -550,10 +553,11 @@
 
     return val + (val << 15);
 #else
-    register int val = 0;
+    register unsigned long val = hash_seed;
 
     while ((c = *string++) != '\0') {
 	val = val*997 + c;
+	val = (val << 13) | (val >> (sizeof(st_data_t) * CHAR_BIT - 13));
     }
 
     return val + (val>>5);
@@ -573,3 +577,11 @@
 {
     return n;
 }
+
+extern unsigned long rb_genrand_int32(void);
+
+void
+Init_st(void)
+{
+    hash_seed = rb_genrand_int32();
+}
Index: ruby_1_8_7/test/ruby/test_string.rb
===================================================================
--- ruby_1_8_7/test/ruby/test_string.rb	(revision 34150)
+++ ruby_1_8_7/test/ruby/test_string.rb	(revision 34151)
@@ -1,4 +1,5 @@
 require 'test/unit'
+require File.expand_path('envutil', File.dirname(__FILE__))
 
 class TestString < Test::Unit::TestCase
   def check_sum(str, bits=16)
@@ -29,4 +30,16 @@
   ensure
     $KCODE = original_kcode
   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
Index: ruby_1_8_7/random.c
===================================================================
--- ruby_1_8_7/random.c	(revision 34150)
+++ ruby_1_8_7/random.c	(revision 34151)
@@ -189,6 +189,7 @@
 #include <fcntl.h>
 #endif
 
+static int seed_initialized = 0;
 static VALUE saved_seed = INT2FIX(0);
 
 static VALUE
@@ -250,28 +251,23 @@
     return old;
 }
 
-static VALUE
-random_seed()
+#define DEFAULT_SEED_LEN (4 * sizeof(long))
+
+static void
+fill_random_seed(ptr)
+    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);
-    big->sign = 1;
-    big->len = seed_len / SIZEOF_BDIGITS + 1;
-    digits = big->digits = ALLOC_N(BDIGIT, big->len);
-    seed = (unsigned long *)big->digits;
+    memset(buf, 0, DEFAULT_SEED_LEN);
 
-    memset(digits, 0, big->len * SIZEOF_BDIGITS);
-
 #ifdef S_ISCHR
     if ((fd = open("/dev/urandom", O_RDONLY
 #ifdef O_NONBLOCK
@@ -285,7 +281,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);
     }
@@ -296,13 +292,37 @@
     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);
+
+    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. */
-    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);
 }
 
+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
@@ -443,6 +463,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(vmax)->value <= LONG_MAX && RFLOAT(vmax)->value >= LONG_MIN) {
@@ -490,6 +513,8 @@
     return LONG2NUM(val);
 }
 
+static char initial_seed[DEFAULT_SEED_LEN];
+
 void
 rb_reset_random_seed()
 {
@@ -497,9 +522,24 @@
 }
 
 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
 Init_Random()
 {
-    rb_reset_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/

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