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/