Skip to content

Commit e19bd3e

Browse files
committed
-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 git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_1_8_7@34151 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
1 parent 858cb3f commit e19bd3e

File tree

7 files changed

+123
-23
lines changed

7 files changed

+123
-23
lines changed

ChangeLog

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,29 @@
1+
Wed Dec 28 21:34:23 2011 URABE Shyouhei <shyouhei@ruby-lang.org>
2+
3+
* string.c (rb_str_hash): randomize hash to avoid algorithmic
4+
complexity attacks. CVE-2011-4815
5+
6+
* st.c (strhash): ditto.
7+
8+
* string.c (Init_String): initialization of hash_seed to be at the
9+
beginning of the process.
10+
11+
* st.c (Init_st): ditto.
12+
13+
Thu Dec 8 11:57:04 2011 Tanaka Akira <akr@fsij.org>
14+
15+
* inits.c (rb_call_inits): call Init_RandomSeed at first.
16+
17+
* random.c (seed_initialized): defined.
18+
(fill_random_seed): extracted from random_seed.
19+
(make_seed_value): extracted from random_seed.
20+
(rb_f_rand): initialize random seed at first.
21+
(initial_seed): defined.
22+
(Init_RandomSeed): defined.
23+
(Init_RandomSeed2): defined.
24+
(rb_reset_random_seed): defined.
25+
(Init_Random): call Init_RandomSeed2.
26+
127
Sat Dec 10 20:44:23 2011 Tanaka Akira <akr@fsij.org>
228

329
* lib/securerandom.rb: call OpenSSL::Random.seed at the

inits.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ void Init_Precision _((void));
3838
void Init_sym _((void));
3939
void Init_process _((void));
4040
void Init_Random _((void));
41+
void Init_RandomSeed _((void));
4142
void Init_Range _((void));
4243
void Init_Regexp _((void));
4344
void Init_signal _((void));
@@ -46,10 +47,13 @@ void Init_Struct _((void));
4647
void Init_Time _((void));
4748
void Init_var_tables _((void));
4849
void Init_version _((void));
50+
void Init_st _((void));
4951

5052
void
5153
rb_call_inits()
5254
{
55+
Init_RandomSeed();
56+
Init_st();
5357
Init_sym();
5458
Init_var_tables();
5559
Init_Object();

random.c

Lines changed: 57 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,7 @@ rb_genrand_real(void)
189189
#include <fcntl.h>
190190
#endif
191191

192+
static int seed_initialized = 0;
192193
static VALUE saved_seed = INT2FIX(0);
193194

194195
static VALUE
@@ -250,27 +251,22 @@ rand_init(vseed)
250251
return old;
251252
}
252253

253-
static VALUE
254-
random_seed()
254+
#define DEFAULT_SEED_LEN (4 * sizeof(long))
255+
256+
static void
257+
fill_random_seed(ptr)
258+
char *ptr;
255259
{
256260
static int n = 0;
261+
unsigned long *seed;
257262
struct timeval tv;
258263
int fd;
259264
struct stat statbuf;
265+
char *buf = (char*)ptr;
260266

261-
int seed_len;
262-
BDIGIT *digits;
263-
unsigned long *seed;
264-
NEWOBJ(big, struct RBignum);
265-
OBJSETUP(big, rb_cBignum, T_BIGNUM);
266-
267-
seed_len = 4 * sizeof(long);
268-
big->sign = 1;
269-
big->len = seed_len / SIZEOF_BDIGITS + 1;
270-
digits = big->digits = ALLOC_N(BDIGIT, big->len);
271-
seed = (unsigned long *)big->digits;
267+
seed = (unsigned long *)buf;
272268

273-
memset(digits, 0, big->len * SIZEOF_BDIGITS);
269+
memset(buf, 0, DEFAULT_SEED_LEN);
274270

275271
#ifdef S_ISCHR
276272
if ((fd = open("/dev/urandom", O_RDONLY
@@ -285,7 +281,7 @@ random_seed()
285281
#endif
286282
)) >= 0) {
287283
if (fstat(fd, &statbuf) == 0 && S_ISCHR(statbuf.st_mode)) {
288-
read(fd, seed, seed_len);
284+
read(fd, seed, DEFAULT_SEED_LEN);
289285
}
290286
close(fd);
291287
}
@@ -296,13 +292,37 @@ random_seed()
296292
seed[1] ^= tv.tv_sec;
297293
seed[2] ^= getpid() ^ (n++ << 16);
298294
seed[3] ^= (unsigned long)&seed;
295+
}
296+
297+
static VALUE
298+
make_seed_value(char *ptr)
299+
{
300+
BDIGIT *digits;
301+
NEWOBJ(big, struct RBignum);
302+
OBJSETUP(big, rb_cBignum, T_BIGNUM);
303+
304+
RBIGNUM_SET_SIGN(big, 1);
305+
306+
digits = ALLOC_N(char, DEFAULT_SEED_LEN);
307+
RBIGNUM(big)->digits = digits;
308+
RBIGNUM(big)->len = DEFAULT_SEED_LEN / SIZEOF_BDIGITS;
309+
310+
MEMCPY(digits, ptr, char, DEFAULT_SEED_LEN);
299311

300312
/* set leading-zero-guard if need. */
301-
digits[big->len-1] = digits[big->len-2] <= 1 ? 1 : 0;
313+
digits[RBIGNUM_LEN(big)-1] = digits[RBIGNUM_LEN(big)-2] <= 1 ? 1 : 0;
302314

303315
return rb_big_norm((VALUE)big);
304316
}
305317

318+
static VALUE
319+
random_seed(void)
320+
{
321+
char buf[DEFAULT_SEED_LEN];
322+
fill_random_seed(buf);
323+
return make_seed_value(buf);
324+
}
325+
306326
/*
307327
* call-seq:
308328
* srand(number=0) => old_seed
@@ -443,6 +463,9 @@ rb_f_rand(argc, argv, obj)
443463
long val, max;
444464

445465
rb_scan_args(argc, argv, "01", &vmax);
466+
if (!seed_initialized) {
467+
rand_init(random_seed());
468+
}
446469
switch (TYPE(vmax)) {
447470
case T_FLOAT:
448471
if (RFLOAT(vmax)->value <= LONG_MAX && RFLOAT(vmax)->value >= LONG_MIN) {
@@ -490,16 +513,33 @@ rb_f_rand(argc, argv, obj)
490513
return LONG2NUM(val);
491514
}
492515

516+
static char initial_seed[DEFAULT_SEED_LEN];
517+
493518
void
494519
rb_reset_random_seed()
495520
{
496521
rand_init(random_seed());
497522
}
498523

524+
void
525+
Init_RandomSeed(void)
526+
{
527+
fill_random_seed(initial_seed);
528+
init_by_array((unsigned long*)initial_seed, DEFAULT_SEED_LEN/sizeof(unsigned long));
529+
seed_initialized = 1;
530+
}
531+
532+
static void
533+
Init_RandomSeed2(void)
534+
{
535+
saved_seed = make_seed_value(initial_seed);
536+
memset(initial_seed, 0, DEFAULT_SEED_LEN);
537+
}
538+
499539
void
500540
Init_Random()
501541
{
502-
rb_reset_random_seed();
542+
Init_RandomSeed2();
503543
rb_define_global_function("srand", rb_f_srand, -1);
504544
rb_define_global_function("rand", rb_f_rand, -1);
505545
rb_global_variable(&saved_seed);

st.c

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include <stdlib.h>
1010
#endif
1111
#include <string.h>
12+
#include <limits.h>
1213
#include "st.h"
1314

1415
typedef struct st_table_entry st_table_entry;
@@ -521,6 +522,8 @@ st_foreach(table, func, arg)
521522
return 0;
522523
}
523524

525+
static unsigned long hash_seed = 0;
526+
524527
static int
525528
strhash(string)
526529
register const char *string;
@@ -550,10 +553,11 @@ strhash(string)
550553

551554
return val + (val << 15);
552555
#else
553-
register int val = 0;
556+
register unsigned long val = hash_seed;
554557

555558
while ((c = *string++) != '\0') {
556559
val = val*997 + c;
560+
val = (val << 13) | (val >> (sizeof(st_data_t) * CHAR_BIT - 13));
557561
}
558562

559563
return val + (val>>5);
@@ -573,3 +577,11 @@ numhash(n)
573577
{
574578
return n;
575579
}
580+
581+
extern unsigned long rb_genrand_int32(void);
582+
583+
void
584+
Init_st(void)
585+
{
586+
hash_seed = rb_genrand_int32();
587+
}

string.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -875,13 +875,15 @@ rb_str_concat(str1, str2)
875875
return str1;
876876
}
877877

878+
static unsigned long hash_seed;
879+
878880
int
879881
rb_str_hash(str)
880882
VALUE str;
881883
{
882884
register long len = RSTRING(str)->len;
883885
register char *p = RSTRING(str)->ptr;
884-
register int key = 0;
886+
register unsigned long key = hash_seed;
885887

886888
#if defined(HASH_ELFHASH)
887889
register unsigned int g;
@@ -905,6 +907,7 @@ rb_str_hash(str)
905907
while (len--) {
906908
key = key*65599 + *p;
907909
p++;
910+
key = (key << 13) | (key >> ((sizeof(unsigned long) * CHAR_BIT) - 13));
908911
}
909912
key = key + (key>>5);
910913
#endif
@@ -5062,4 +5065,6 @@ Init_String()
50625065
rb_fs = Qnil;
50635066
rb_define_variable("$;", &rb_fs);
50645067
rb_define_variable("$-F", &rb_fs);
5068+
5069+
hash_seed = rb_genrand_int32();
50655070
}

test/ruby/test_string.rb

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
require 'test/unit'
2+
require File.expand_path('envutil', File.dirname(__FILE__))
23

34
class TestString < Test::Unit::TestCase
45
def check_sum(str, bits=16)
@@ -29,4 +30,16 @@ def test_inspect
2930
ensure
3031
$KCODE = original_kcode
3132
end
33+
34+
def test_hash_random
35+
str = 'abc'
36+
a = [str.hash.to_s]
37+
cmd = sprintf("%s -e 'print %s.hash'", EnvUtil.rubybin, str.dump)
38+
3.times {
39+
IO.popen(cmd, "rb") {|o|
40+
a << o.read
41+
}
42+
}
43+
assert_not_equal([str.hash.to_s], a.uniq)
44+
end
3245
end

version.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
#define RUBY_VERSION "1.8.7"
2-
#define RUBY_RELEASE_DATE "2011-12-10"
2+
#define RUBY_RELEASE_DATE "2011-12-28"
33
#define RUBY_VERSION_CODE 187
4-
#define RUBY_RELEASE_CODE 20111210
5-
#define RUBY_PATCHLEVEL 356
4+
#define RUBY_RELEASE_CODE 20111228
5+
#define RUBY_PATCHLEVEL 357
66

77
#define RUBY_VERSION_MAJOR 1
88
#define RUBY_VERSION_MINOR 8
99
#define RUBY_VERSION_TEENY 7
1010
#define RUBY_RELEASE_YEAR 2011
1111
#define RUBY_RELEASE_MONTH 12
12-
#define RUBY_RELEASE_DAY 10
12+
#define RUBY_RELEASE_DAY 28
1313

1414
#ifdef RUBY_EXTERN
1515
RUBY_EXTERN const char ruby_version[];

0 commit comments

Comments
 (0)