summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog8
-rw-r--r--error.c16
-rw-r--r--include/ruby/intern.h15
-rw-r--r--struct.c3
-rwxr-xr-xt.rb8
-rw-r--r--test/ruby/test_struct.rb14
-rw-r--r--test/ruby/test_time.rb17
-rw-r--r--time.c3
8 files changed, 79 insertions, 5 deletions
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 <nobu@ruby-lang.org>
+
+ * 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 <nobu@ruby-lang.org>
* 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
@@ -1715,6 +1715,22 @@ rb_check_frozen(VALUE 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)
{
rb_eNOERROR = set_syserr(0, "NOERROR");
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 <<t0; end
+ class << t0; end
t1 = t0.getlocal
def t0.m
@@ -711,4 +712,18 @@ class TestTime < Test::Unit::TestCase
assert_raise(NoMethodError, bug5012) { t1.m }
end
+
+ def test_time_subclass
+ bug5036 = '[ruby-dev:44122]'
+ tc = Class.new(Time)
+ tc.inspect
+ t = tc.now
+ error = assert_raise(SecurityError) do
+ proc do
+ $SAFE = 4
+ t.gmtime
+ end.call
+ end
+ assert_equal("Insecure: can't modify #{tc}", error.message, bug5036)
+ end
end
diff --git a/time.c b/time.c
index b2e3448610..dd846a630c 100644
--- a/time.c
+++ b/time.c
@@ -1876,8 +1876,7 @@ static void
time_modify(VALUE time)
{
rb_check_frozen(time);
- if (!OBJ_UNTRUSTED(time) && rb_safe_level() >= 4)
- rb_raise(rb_eSecurityError, "Insecure: can't modify Time");
+ rb_check_trusted(time);
}
static wideval_t