diff --git a/ChangeLog b/ChangeLog index 6f6b3f9cde..21d8b7ae86 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +Sun Jul 17 16:26:40 2011 Nobuyoshi Nakada + + * error.c (rb_check_trusted): new function to check an object is + trusted. + + * struct.c (rb_struct_modify), time.c (time_modify): check by the + above function to show proper class names. [Bug #5036] + Sun Jul 17 15:30:04 2011 Nobuyoshi Nakada * error.c (rb_warn_m): accept multiple args in like puts. rdoc diff --git a/error.c b/error.c index 53f5472efc..42f83682ea 100644 --- a/error.c +++ b/error.c @@ -1714,6 +1714,22 @@ rb_check_frozen(VALUE obj) rb_check_frozen_internal(obj); } +void +rb_error_untrusted(VALUE obj) +{ + if (rb_safe_level() >= 4) { + rb_raise(rb_eSecurityError, "Insecure: can't modify %s", + rb_obj_classname(obj)); + } +} + +#undef rb_check_trusted +void +rb_check_trusted(VALUE obj) +{ + rb_check_trusted_internal(obj); +} + void Init_syserr(void) { diff --git a/include/ruby/intern.h b/include/ruby/intern.h index da1c036740..41a41ea757 100644 --- a/include/ruby/intern.h +++ b/include/ruby/intern.h @@ -215,15 +215,24 @@ PRINTF_ARGS(void rb_compile_error_with_enc(const char*, int, void *, const char* PRINTF_ARGS(void rb_compile_error_append(const char*, ...), 1, 2); NORETURN(void rb_load_fail(const char*)); NORETURN(void rb_error_frozen(const char*)); +void rb_error_untrusted(VALUE); void rb_check_frozen(VALUE); +void rb_check_trusted(VALUE); #define rb_check_frozen_internal(obj) do { \ VALUE frozen_obj = (obj); \ if (OBJ_FROZEN(frozen_obj)) { \ rb_error_frozen(rb_obj_classname(frozen_obj)); \ } \ } while (0) +#define rb_check_trusted_internal(obj) do { \ + VALUE untrusted_obj = (obj); \ + if (!OBJ_UNTRUSTED(untrusted_obj)) { \ + rb_error_untrusted(untrusted_obj); \ + } \ + } while (0) #ifdef __GNUC__ #define rb_check_frozen(obj) __extension__({rb_check_frozen_internal(obj);}) +#define rb_check_trusted(obj) __extension__({rb_check_trusted_internal(obj);}) #else static inline void rb_check_frozen_inline(VALUE obj) @@ -231,6 +240,12 @@ rb_check_frozen_inline(VALUE obj) rb_check_frozen_internal(obj); } #define rb_check_frozen(obj) rb_check_frozen_inline(obj) +static inline void +rb_check_trusted_inline(VALUE obj) +{ + rb_check_trusted_internal(obj); +} +#define rb_check_trusted(obj) rb_check_trusted_inline(obj) #endif /* eval.c */ diff --git a/struct.c b/struct.c index 136ba0acee..ab82fadd1c 100644 --- a/struct.c +++ b/struct.c @@ -153,8 +153,7 @@ static void rb_struct_modify(VALUE s) { rb_check_frozen(s); - if (!OBJ_UNTRUSTED(s) && rb_safe_level() >= 4) - rb_raise(rb_eSecurityError, "Insecure: can't modify Struct"); + rb_check_trusted(s); } static VALUE diff --git a/t.rb b/t.rb new file mode 100755 index 0000000000..757a2b6edf --- /dev/null +++ b/t.rb @@ -0,0 +1,8 @@ +#! /usr/bin/ruby +tc = Class.new(Time) +tc.inspect +t = tc.now +proc do + $SAFE=4 + t.gmtime +end.call diff --git a/test/ruby/test_struct.rb b/test/ruby/test_struct.rb index 49dcdb45b2..d769e47dc5 100644 --- a/test/ruby/test_struct.rb +++ b/test/ruby/test_struct.rb @@ -1,5 +1,6 @@ require 'test/unit' require 'timeout' +require_relative 'envutil' class TestStruct < Test::Unit::TestCase def test_struct @@ -249,4 +250,17 @@ class TestStruct < Test::Unit::TestCase assert !x.eql?(z) } end + + def test_struct_subclass + bug5036 = '[ruby-dev:44122]' + st = Class.new(Struct) + s = st.new("S", :m).new + error = assert_raise(SecurityError) do + proc do + $SAFE = 4 + s.m = 1 + end.call + end + assert_equal("Insecure: can't modify #{st}::S", error.message, bug5036) + end end diff --git a/test/ruby/test_time.rb b/test/ruby/test_time.rb index aea4c2edc0..38e567a703 100644 --- a/test/ruby/test_time.rb +++ b/test/ruby/test_time.rb @@ -3,6 +3,7 @@ require 'rational' require 'delegate' require 'timeout' require 'delegate' +require_relative 'envutil' class TestTime < Test::Unit::TestCase def setup @@ -702,7 +703,7 @@ class TestTime < Test::Unit::TestCase bug5012 = "[ruby-dev:44071]" t0 = Time.now - class <= 4) - rb_raise(rb_eSecurityError, "Insecure: can't modify Time"); + rb_check_trusted(time); } static wideval_t