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/