From f433d710d0ab3b367cc4a851cdfb81c5405bb7f8 Mon Sep 17 00:00:00 2001 From: shugo Date: Wed, 13 Aug 2008 07:25:05 +0000 Subject: * object.c (rb_obj_untrusted): new method Object#untrusted?. (rb_obj_untrust): new method Object#untrust. (rb_obj_trust): new method Object#trust. * array.c, debug.c, time.c, include/ruby/ruby.h, re.c, variable.c, string.c, io.c, dir.c, vm_method.c, struct.c, class.c, hash.c, ruby.c, marshal.c: fixes for Object#untrusted?. * test/ruby/test_module.rb, test/ruby/test_array.rb, test/ruby/test_object.rb, test/ruby/test_string.rb, test/ruby/test_marshal.rb, test/ruby/test_hash.rb: added tests for Object#untrusted?. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@18568 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ChangeLog | 15 +++++++++ array.c | 11 +++++-- class.c | 8 ++++- debug.c | 4 +-- dir.c | 6 ++-- hash.c | 4 +-- include/ruby/ruby.h | 16 +++++----- io.c | 13 ++++---- marshal.c | 14 +++++++++ object.c | 67 +++++++++++++++++++++++++++++++++++++--- re.c | 2 +- ruby.c | 4 +-- string.c | 6 +++- struct.c | 2 +- test/ruby/test_array.rb | 46 ++++++++++++++++++++++------ test/ruby/test_hash.rb | 54 ++++++++++++++++++++------------ test/ruby/test_marshal.rb | 12 ++++++++ test/ruby/test_module.rb | 18 +++++++++++ test/ruby/test_object.rb | 78 +++++++++++++++++++++++++++++++++++++++++++++++ test/ruby/test_string.rb | 61 +++++++++++++++++++++++------------- time.c | 2 +- variable.c | 10 +++--- vm_method.c | 9 +++--- 23 files changed, 369 insertions(+), 93 deletions(-) diff --git a/ChangeLog b/ChangeLog index 14be731f13..c98ecad643 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,18 @@ +Wed Aug 13 16:02:14 2008 Shugo Maeda + + * object.c (rb_obj_untrusted): new method Object#untrusted?. + (rb_obj_untrust): new method Object#untrust. + (rb_obj_trust): new method Object#trust. + + * array.c, debug.c, time.c, include/ruby/ruby.h, re.c, variable.c, + string.c, io.c, dir.c, vm_method.c, struct.c, class.c, hash.c, + ruby.c, marshal.c: fixes for Object#untrusted?. + + * test/ruby/test_module.rb, test/ruby/test_array.rb, + test/ruby/test_object.rb, test/ruby/test_string.rb, + test/ruby/test_marshal.rb, test/ruby/test_hash.rb: added tests for + Object#untrusted?. + Wed Aug 13 16:13:58 2008 NARUSE, Yui * test/ruby/test_m17n.rb: follow EncodingCompatibilityError. diff --git a/array.c b/array.c index 59f5fe3f72..941f3ffac4 100644 --- a/array.c +++ b/array.c @@ -54,7 +54,7 @@ static inline void rb_ary_modify_check(VALUE ary) { if (OBJ_FROZEN(ary)) rb_error_frozen("array"); - if (!OBJ_TAINTED(ary) && rb_safe_level() >= 4) + if (!OBJ_UNTRUSTED(ary) && rb_safe_level() >= 4) rb_raise(rb_eSecurityError, "Insecure: can't modify array"); } @@ -1263,10 +1263,12 @@ rb_ary_join(VALUE ary, VALUE sep) { long len = 1, i; int taint = Qfalse; + int untrust = Qfalse; VALUE result, tmp; if (RARRAY_LEN(ary) == 0) return rb_str_new(0, 0); if (OBJ_TAINTED(ary) || OBJ_TAINTED(sep)) taint = Qtrue; + if (OBJ_UNTRUSTED(ary) || OBJ_UNTRUSTED(sep)) untrust = Qtrue; for (i=0; i 0) rb_str_buf_cat2(str, ", "); rb_str_buf_append(str, s); } rb_str_buf_cat2(str, "]"); if (tainted) OBJ_TAINT(str); + if (untrust) OBJ_UNTRUST(str); return str; } @@ -2952,7 +2959,7 @@ rb_ary_flatten(int argc, VALUE *argv, VALUE ary) if (level == 0) return ary; result = flatten(ary, level, &mod); - if (OBJ_TAINTED(ary)) OBJ_TAINT(result); + OBJ_INFECT(result, ary); return result; } diff --git a/class.c b/class.c index 91ba3e6361..6f64d07612 100644 --- a/class.c +++ b/class.c @@ -383,7 +383,7 @@ rb_include_module(VALUE klass, VALUE module) int changed = 0; rb_frozen_class_p(klass); - if (!OBJ_TAINTED(klass)) { + if (!OBJ_UNTRUSTED(klass)) { rb_secure(4); } @@ -833,6 +833,12 @@ rb_singleton_class(VALUE obj) else { FL_UNSET(klass, FL_TAINT); } + if (OBJ_UNTRUSTED(obj)) { + OBJ_UNTRUST(klass); + } + else { + FL_UNSET(klass, FL_UNTRUSTED); + } if (OBJ_FROZEN(obj)) OBJ_FREEZE(klass); ALLOW_INTS; diff --git a/debug.c b/debug.c index 44b95118c8..265e864aec 100644 --- a/debug.c +++ b/debug.c @@ -35,6 +35,7 @@ static const union { RUBY_FL_RESERVED = FL_RESERVED, RUBY_FL_FINALIZE = FL_FINALIZE, RUBY_FL_TAINT = FL_TAINT, + RUBY_FL_UNTRUSTED = FL_UNTRUSTED, RUBY_FL_EXIVAR = FL_EXIVAR, RUBY_FL_FREEZE = FL_FREEZE, RUBY_FL_SINGLETON = FL_SINGLETON, @@ -57,7 +58,6 @@ static const union { RUBY_FL_USER16 = FL_USER16, RUBY_FL_USER17 = FL_USER17, RUBY_FL_USER18 = FL_USER18, - RUBY_FL_USER19 = FL_USER19, RUBY_FL_USHIFT = FL_USHIFT, RUBY_NODE_TYPESHIFT = NODE_TYPESHIFT, RUBY_NODE_TYPEMASK = NODE_TYPEMASK, @@ -67,7 +67,7 @@ static const union { } various; } dummy_gdb_enums; -const VALUE RUBY_FL_USER20 = FL_USER20; +const VALUE RUBY_FL_USER19 = FL_USER19; int ruby_debug_print_indent(int level, int debug_level, int indent_level) diff --git a/dir.c b/dir.c index dcbbc14e0e..a3eed26c75 100644 --- a/dir.c +++ b/dir.c @@ -414,8 +414,8 @@ dir_closed(void) static void dir_check(VALUE dir) { - if (!OBJ_TAINTED(dir) && rb_safe_level() >= 4) - rb_raise(rb_eSecurityError, "Insecure: operation on untainted Dir"); + if (!OBJ_UNTRUSTED(dir) && rb_safe_level() >= 4) + rb_raise(rb_eSecurityError, "Insecure: operation on trusted Dir"); rb_check_frozen(dir); } @@ -630,7 +630,7 @@ dir_rewind(VALUE dir) { struct dir_data *dirp; - if (rb_safe_level() >= 4 && !OBJ_TAINTED(dir)) { + if (rb_safe_level() >= 4 && !OBJ_UNTRUSTED(dir)) { rb_raise(rb_eSecurityError, "Insecure: can't close"); } GetDIR(dir, dirp); diff --git a/hash.c b/hash.c index 89139e852f..ee90a840bb 100644 --- a/hash.c +++ b/hash.c @@ -247,7 +247,7 @@ static void rb_hash_modify_check(VALUE hash) { if (OBJ_FROZEN(hash)) rb_error_frozen("hash"); - if (!OBJ_TAINTED(hash) && rb_safe_level() >= 4) + if (!OBJ_UNTRUSTED(hash) && rb_safe_level() >= 4) rb_raise(rb_eSecurityError, "Insecure: can't modify hash"); } @@ -1166,7 +1166,7 @@ rb_hash_to_a(VALUE hash) ary = rb_ary_new(); rb_hash_foreach(hash, to_a_i, ary); - if (OBJ_TAINTED(hash)) OBJ_TAINT(ary); + OBJ_INFECT(ary, hash); return ary; } diff --git a/include/ruby/ruby.h b/include/ruby/ruby.h index 0a53670ae7..41b4d34a97 100644 --- a/include/ruby/ruby.h +++ b/include/ruby/ruby.h @@ -432,7 +432,7 @@ VALUE rb_newobj(void); #define OBJSETUP(obj,c,t) do {\ RBASIC(obj)->flags = (t);\ RBASIC(obj)->klass = (c);\ - if (rb_safe_level() >= 3) FL_SET(obj, FL_TAINT);\ + if (rb_safe_level() >= 3) FL_SET(obj, FL_TAINT | FL_UNTRUSTED);\ } while (0) #define CLONESETUP(clone,obj) do {\ OBJSETUP(clone,rb_singleton_class_clone((VALUE)obj),RBASIC(obj)->flags);\ @@ -440,7 +440,7 @@ VALUE rb_newobj(void); if (FL_TEST(obj, FL_EXIVAR)) rb_copy_generic_ivar((VALUE)clone,(VALUE)obj);\ } while (0) #define DUPSETUP(dup,obj) do {\ - OBJSETUP(dup,rb_obj_class(obj),(RBASIC(obj)->flags)&(T_MASK|FL_EXIVAR|FL_TAINT));\ + OBJSETUP(dup,rb_obj_class(obj),(RBASIC(obj)->flags)&(T_MASK|FL_EXIVAR|FL_TAINT|FL_UNTRUSTED));\ if (FL_TEST(obj, FL_EXIVAR)) rb_copy_generic_ivar((VALUE)dup,(VALUE)obj);\ } while (0) @@ -693,10 +693,11 @@ struct RBignum { #define FL_RESERVED (((VALUE)1)<<6) /* will be used in the future GC */ #define FL_FINALIZE (((VALUE)1)<<7) #define FL_TAINT (((VALUE)1)<<8) -#define FL_EXIVAR (((VALUE)1)<<9) -#define FL_FREEZE (((VALUE)1)<<10) +#define FL_UNTRUSTED (((VALUE)1)<<9) +#define FL_EXIVAR (((VALUE)1)<<10) +#define FL_FREEZE (((VALUE)1)<<11) -#define FL_USHIFT 11 +#define FL_USHIFT 12 #define FL_USER0 (((VALUE)1)<<(FL_USHIFT+0)) #define FL_USER1 (((VALUE)1)<<(FL_USHIFT+1)) @@ -718,7 +719,6 @@ struct RBignum { #define FL_USER17 (((VALUE)1)<<(FL_USHIFT+17)) #define FL_USER18 (((VALUE)1)<<(FL_USHIFT+18)) #define FL_USER19 (((VALUE)1)<<(FL_USHIFT+19)) -#define FL_USER20 (((VALUE)1)<<(FL_USHIFT+20)) #define SPECIAL_CONST_P(x) (IMMEDIATE_P(x) || !RTEST(x)) @@ -732,7 +732,9 @@ struct RBignum { #define OBJ_TAINTED(x) FL_TEST((x), FL_TAINT) #define OBJ_TAINT(x) FL_SET((x), FL_TAINT) -#define OBJ_INFECT(x,s) do {if (FL_ABLE(x) && FL_ABLE(s)) RBASIC(x)->flags |= RBASIC(s)->flags & FL_TAINT;} while (0) +#define OBJ_UNTRUSTED(x) FL_TEST((x), FL_UNTRUSTED) +#define OBJ_UNTRUST(x) FL_SET((x), FL_UNTRUSTED) +#define OBJ_INFECT(x,s) do {if (FL_ABLE(x) && FL_ABLE(s)) RBASIC(x)->flags |= RBASIC(s)->flags & (FL_TAINT | FL_UNTRUSTED);} while (0) #define OBJ_FROZEN(x) FL_TEST((x), FL_FREEZE) #define OBJ_FREEZE(x) FL_SET((x), FL_FREEZE) diff --git a/io.c b/io.c index 77b85de9e3..08578cf035 100644 --- a/io.c +++ b/io.c @@ -227,8 +227,8 @@ rb_eof_error(void) VALUE rb_io_taint_check(VALUE io) { - if (!OBJ_TAINTED(io) && rb_safe_level() >= 4) - rb_raise(rb_eSecurityError, "Insecure: operation on untainted IO"); + if (!OBJ_UNTRUSTED(io) && rb_safe_level() >= 4) + rb_raise(rb_eSecurityError, "Insecure: operation on trusted IO"); rb_check_frozen(io); return io; } @@ -2819,7 +2819,7 @@ rb_io_close(VALUE io) static VALUE rb_io_close_m(VALUE io) { - if (rb_safe_level() >= 4 && !OBJ_TAINTED(io)) { + if (rb_safe_level() >= 4 && !OBJ_UNTRUSTED(io)) { rb_raise(rb_eSecurityError, "Insecure: can't close"); } rb_io_check_closed(RFILE(io)->fptr); @@ -2902,7 +2902,7 @@ rb_io_close_read(VALUE io) rb_io_t *fptr; VALUE write_io; - if (rb_safe_level() >= 4 && !OBJ_TAINTED(io)) { + if (rb_safe_level() >= 4 && !OBJ_UNTRUSTED(io)) { rb_raise(rb_eSecurityError, "Insecure: can't close"); } GetOpenFile(io, fptr); @@ -2962,7 +2962,7 @@ rb_io_close_write(VALUE io) rb_io_t *fptr; VALUE write_io; - if (rb_safe_level() >= 4 && !OBJ_TAINTED(io)) { + if (rb_safe_level() >= 4 && !OBJ_UNTRUSTED(io)) { rb_raise(rb_eSecurityError, "Insecure: can't close"); } write_io = GetWriteIO(io); @@ -4430,7 +4430,8 @@ io_reopen(VALUE io, VALUE nfile) off_t pos = 0; nfile = rb_io_get_io(nfile); - if (rb_safe_level() >= 4 && (!OBJ_TAINTED(io) || !OBJ_TAINTED(nfile))) { + if (rb_safe_level() >= 4 && + (!OBJ_UNTRUSTED(io) || !OBJ_UNTRUSTED(nfile))) { rb_raise(rb_eSecurityError, "Insecure: can't reopen"); } GetOpenFile(io, fptr); diff --git a/marshal.c b/marshal.c index b01d2de201..676f4f8eef 100644 --- a/marshal.c +++ b/marshal.c @@ -137,6 +137,7 @@ struct dump_arg { st_table *symbols; st_table *data; int taint; + int untrust; st_table *compat_tbl; VALUE wrapper; st_table *encodings; @@ -192,6 +193,7 @@ w_nbyte(const char *s, int n, struct dump_arg *arg) rb_str_buf_cat(buf, s, n); if (arg->dest && RSTRING_LEN(buf) >= BUFSIZ) { if (arg->taint) OBJ_TAINT(buf); + if (arg->untrust) OBJ_UNTRUST(buf); rb_io_write(arg->dest, buf); rb_str_resize(buf, 0); } @@ -581,6 +583,7 @@ w_object(VALUE obj, struct dump_arg *arg, int limit) } else { if (OBJ_TAINTED(obj)) arg->taint = Qtrue; + if (OBJ_UNTRUSTED(obj)) arg->untrust = Qtrue; if (rb_respond_to(obj, s_mdump)) { volatile VALUE v; @@ -809,6 +812,9 @@ dump_ensure(struct dump_arg *arg) if (arg->taint) { OBJ_TAINT(arg->str); } + if (arg->untrust) { + OBJ_UNTRUST(arg->str); + } return 0; } @@ -878,6 +884,7 @@ marshal_dump(int argc, VALUE *argv) arg.symbols = st_init_numtable(); arg.data = st_init_numtable(); arg.taint = Qfalse; + arg.untrust = Qfalse; arg.compat_tbl = st_init_numtable(); arg.wrapper = Data_Wrap_Struct(rb_cData, mark_dump_arg, 0, &arg); arg.encodings = 0; @@ -900,6 +907,7 @@ struct load_arg { VALUE data; VALUE proc; int taint; + int untrust; st_table *compat_tbl; VALUE compat_tbl_wrapper; }; @@ -1014,6 +1022,7 @@ r_bytes0(long len, struct load_arg *arg) StringValue(str); if (RSTRING_LEN(str) != len) goto too_short; if (OBJ_TAINTED(str)) arg->taint = Qtrue; + if (OBJ_UNTRUSTED(str)) arg->untrust = Qtrue; } return str; } @@ -1084,6 +1093,11 @@ r_entry(VALUE v, struct load_arg *arg) if ((VALUE)real_obj != Qundef) OBJ_TAINT((VALUE)real_obj); } + if (arg->untrust) { + OBJ_UNTRUST(v); + if ((VALUE)real_obj != Qundef) + OBJ_UNTRUST((VALUE)real_obj); + } return v; } diff --git a/object.c b/object.c index 83b541b205..e4fcf77752 100644 --- a/object.c +++ b/object.c @@ -161,7 +161,7 @@ init_copy(VALUE dest, VALUE obj) rb_raise(rb_eTypeError, "[bug] frozen object (%s) allocated", rb_obj_classname(dest)); } RBASIC(dest)->flags &= ~(T_MASK|FL_EXIVAR); - RBASIC(dest)->flags |= RBASIC(obj)->flags & (T_MASK|FL_EXIVAR|FL_TAINT); + RBASIC(dest)->flags |= RBASIC(obj)->flags & (T_MASK|FL_EXIVAR|FL_TAINT|FL_UNTRUSTED); rb_copy_generic_ivar(dest, obj); rb_gc_copy_finalizer(dest, obj); switch (TYPE(obj)) { @@ -234,7 +234,7 @@ rb_obj_clone(VALUE obj) } clone = rb_obj_alloc(rb_obj_class(obj)); RBASIC(clone)->klass = rb_singleton_class_clone(obj); - RBASIC(clone)->flags = (RBASIC(obj)->flags | FL_TEST(clone, FL_TAINT)) & ~(FL_FREEZE|FL_FINALIZE); + RBASIC(clone)->flags = (RBASIC(obj)->flags | FL_TEST(clone, FL_TAINT) | FL_TEST(clone, FL_UNTRUSTED)) & ~(FL_FREEZE|FL_FINALIZE); init_copy(clone, obj); RBASIC(clone)->flags |= RBASIC(obj)->flags & FL_FREEZE; @@ -302,7 +302,7 @@ rb_any_to_s(VALUE obj) VALUE str; str = rb_sprintf("#<%s:%p>", cname, (void*)obj); - if (OBJ_TAINTED(obj)) OBJ_TAINT(str); + OBJ_INFECT(str, obj); return str; } @@ -692,6 +692,62 @@ rb_obj_untaint(VALUE obj) return obj; } +/* + * call-seq: + * obj.untrusted? => true or false + * + * Returns true if the object is untrusted. + */ + +VALUE +rb_obj_untrusted(VALUE obj) +{ + if (OBJ_UNTRUSTED(obj)) + return Qtrue; + return Qfalse; +} + +/* + * call-seq: + * obj.untrust -> obj + * + * Marks obj as untrusted. + */ + +VALUE +rb_obj_untrust(VALUE obj) +{ + rb_secure(4); + if (!OBJ_UNTRUSTED(obj)) { + if (OBJ_FROZEN(obj)) { + rb_error_frozen("object"); + } + OBJ_UNTRUST(obj); + } + return obj; +} + + +/* + * call-seq: + * obj.trust => obj + * + * Removes the untrusted mark from obj. + */ + +VALUE +rb_obj_trust(VALUE obj) +{ + rb_secure(3); + if (OBJ_UNTRUSTED(obj)) { + if (OBJ_FROZEN(obj)) { + rb_error_frozen("object"); + } + FL_UNSET(obj, FL_UNTRUSTED); + } + return obj; +} + void rb_obj_infect(VALUE obj1, VALUE obj2) { @@ -723,7 +779,7 @@ VALUE rb_obj_freeze(VALUE obj) { if (!OBJ_FROZEN(obj)) { - if (rb_safe_level() >= 4 && !OBJ_TAINTED(obj)) { + if (rb_safe_level() >= 4 && !OBJ_UNTRUSTED(obj)) { rb_raise(rb_eSecurityError, "Insecure: can't freeze object"); } OBJ_FREEZE(obj); @@ -2419,6 +2475,9 @@ Init_Object(void) rb_define_method(rb_mKernel, "taint", rb_obj_taint, 0); rb_define_method(rb_mKernel, "tainted?", rb_obj_tainted, 0); rb_define_method(rb_mKernel, "untaint", rb_obj_untaint, 0); + rb_define_method(rb_mKernel, "untrust", rb_obj_untrust, 0); + rb_define_method(rb_mKernel, "untrusted?", rb_obj_untrusted, 0); + rb_define_method(rb_mKernel, "trust", rb_obj_trust, 0); rb_define_method(rb_mKernel, "freeze", rb_obj_freeze, 0); rb_define_method(rb_mKernel, "frozen?", rb_obj_frozen_p, 0); diff --git a/re.c b/re.c index 504c1d2435..ff82636a46 100644 --- a/re.c +++ b/re.c @@ -2299,7 +2299,7 @@ rb_reg_initialize(VALUE obj, const char *s, int len, rb_encoding *enc, rb_encoding *fixed_enc = 0; rb_encoding *a_enc = rb_ascii8bit_encoding(); - if (!OBJ_TAINTED(obj) && rb_safe_level() >= 4) + if (!OBJ_UNTRUSTED(obj) && rb_safe_level() >= 4) rb_raise(rb_eSecurityError, "Insecure: can't modify regexp"); rb_check_frozen(obj); if (FL_TEST(obj, REG_LITERAL)) diff --git a/ruby.c b/ruby.c index 1c541f36e9..25d95901e7 100644 --- a/ruby.c +++ b/ruby.c @@ -1069,12 +1069,12 @@ process_options(VALUE arg) #endif opt->script_name = rb_str_new4(rb_progname); opt->script = RSTRING_PTR(opt->script_name); + safe = rb_safe_level(); + rb_set_safe_level_force(0); ruby_set_argv(argc, argv); process_sflag(opt); ruby_init_loadpath(); - safe = rb_safe_level(); - rb_set_safe_level_force(0); ruby_init_gems(!(opt->disable & DISABLE_BIT(gems))); lenc = rb_locale_encoding(); for (i = 0; i < RARRAY_LEN(rb_argv); i++) { diff --git a/string.c b/string.c index e72becfbdc..7df1d00a88 100644 --- a/string.c +++ b/string.c @@ -1027,7 +1027,7 @@ str_modifiable(VALUE str) rb_raise(rb_eRuntimeError, "can't modify string; temporarily locked"); } if (OBJ_FROZEN(str)) rb_error_frozen("string"); - if (!OBJ_TAINTED(str) && rb_safe_level() >= 4) + if (!OBJ_UNTRUSTED(str) && rb_safe_level() >= 4) rb_raise(rb_eSecurityError, "Insecure: can't modify string"); } @@ -3170,6 +3170,7 @@ rb_str_sub_bang(int argc, VALUE *argv, VALUE str) VALUE pat, repl, hash = Qnil; int iter = 0; int tainted = 0; + int untrusted = 0; long plen; if (argc == 1 && rb_block_given_p()) { @@ -3182,6 +3183,7 @@ rb_str_sub_bang(int argc, VALUE *argv, VALUE str) StringValue(repl); } if (OBJ_TAINTED(repl)) tainted = 1; + if (OBJ_UNTRUSTED(repl)) untrusted = 1; } else { rb_raise(rb_eArgError, "wrong number of arguments (%d for 2)", argc); @@ -3227,6 +3229,7 @@ rb_str_sub_bang(int argc, VALUE *argv, VALUE str) rb_str_modify(str); rb_enc_associate(str, enc); if (OBJ_TAINTED(repl)) tainted = 1; + if (OBJ_UNTRUSTED(repl)) untrusted = 1; if (ENC_CODERANGE_UNKNOWN < cr && cr < ENC_CODERANGE_BROKEN) { int cr2 = ENC_CODERANGE(repl); if (cr2 == ENC_CODERANGE_UNKNOWN || cr2 > cr) cr = cr2; @@ -3246,6 +3249,7 @@ rb_str_sub_bang(int argc, VALUE *argv, VALUE str) RSTRING_PTR(str)[RSTRING_LEN(str)] = '\0'; ENC_CODERANGE_SET(str, cr); if (tainted) OBJ_TAINT(str); + if (untrusted) OBJ_UNTRUST(str); return str; } diff --git a/struct.c b/struct.c index 027256869a..83b0f7b31b 100644 --- a/struct.c +++ b/struct.c @@ -144,7 +144,7 @@ static void rb_struct_modify(VALUE s) { if (OBJ_FROZEN(s)) rb_error_frozen("Struct"); - if (!OBJ_TAINTED(s) && rb_safe_level() >= 4) + if (!OBJ_UNTRUSTED(s) && rb_safe_level() >= 4) rb_raise(rb_eSecurityError, "Insecure: can't modify Struct"); } diff --git a/test/ruby/test_array.rb b/test/ruby/test_array.rb index 7258b22a5b..1139e36900 100644 --- a/test/ruby/test_array.rb +++ b/test/ruby/test_array.rb @@ -451,16 +451,20 @@ class TestArray < Test::Unit::TestCase def test_clone for taint in [ false, true ] - for frozen in [ false, true ] - a = @cls[*(0..99).to_a] - a.taint if taint - a.freeze if frozen - b = a.clone - - assert_equal(a, b) - assert(a.__id__ != b.__id__) - assert_equal(a.frozen?, b.frozen?) - assert_equal(a.tainted?, b.tainted?) + for untrust in [ false, true ] + for frozen in [ false, true ] + a = @cls[*(0..99).to_a] + a.taint if taint + a.untrust if untrust + a.freeze if frozen + b = a.clone + + assert_equal(a, b) + assert(a.__id__ != b.__id__) + assert_equal(a.frozen?, b.frozen?) + assert_equal(a.untrusted?, b.untrusted?) + assert_equal(a.tainted?, b.tainted?) + end end end end @@ -708,6 +712,13 @@ class TestArray < Test::Unit::TestCase @cls[@cls[@cls[@cls[],@cls[]],@cls[@cls[]],@cls[]],@cls[@cls[@cls[]]]].flatten) assert_raise(TypeError, "[ruby-dev:31197]") { [[]].flatten("") } + + a6 = @cls[[1, 2], 3] + a6.taint + a6.untrust + a7 = a6.flatten + assert_equal(true, a7.tainted?) + assert_equal(true, a7.untrusted?) end def test_flatten! @@ -797,6 +808,12 @@ class TestArray < Test::Unit::TestCase assert_equal("1,2,3", a.join(',')) $, = "" + a = @cls[1, 2, 3] + a.taint + a.untrust + s = a.join + assert_equal(true, s.tainted?) + assert_equal(true, s.untrusted?) end def test_last @@ -1574,4 +1591,13 @@ class TestArray < Test::Unit::TestCase def test_array_subclass assert_equal(Array2, Array2[1,2,3].uniq.class, "[ruby-dev:34581]") end + + def test_inspect + a = @cls[1, 2, 3] + a.taint + a.untrust + s = a.inspect + assert_equal(true, s.tainted?) + assert_equal(true, s.untrusted?) + end end diff --git a/test/ruby/test_hash.rb b/test/ruby/test_hash.rb index c86cf3297d..de0ba37fb7 100644 --- a/test/ruby/test_hash.rb +++ b/test/ruby/test_hash.rb @@ -206,16 +206,20 @@ class TestHash < Test::Unit::TestCase def test_clone for taint in [ false, true ] - for frozen in [ false, true ] - a = @h.clone - a.taint if taint - a.freeze if frozen - b = a.clone - - assert_equal(a, b) - assert(a.__id__ != b.__id__) - assert_equal(a.frozen?, b.frozen?) - assert_equal(a.tainted?, b.tainted?) + for untrust in [ false, true ] + for frozen in [ false, true ] + a = @h.clone + a.taint if taint + a.untrust if untrust + a.freeze if frozen + b = a.clone + + assert_equal(a, b) + assert(a.__id__ != b.__id__) + assert_equal(a.frozen?, b.frozen?) + assert_equal(a.untrusted?, b.untrusted?) + assert_equal(a.tainted?, b.tainted?) + end end end end @@ -288,16 +292,19 @@ class TestHash < Test::Unit::TestCase def test_dup for taint in [ false, true ] - for frozen in [ false, true ] - a = @h.dup - a.taint if taint - a.freeze if frozen - b = a.dup - - assert_equal(a, b) - assert(a.__id__ != b.__id__) - assert_equal(false, b.frozen?) - assert_equal(a.tainted?, b.tainted?) + for untrust in [ false, true ] + for frozen in [ false, true ] + a = @h.dup + a.taint if taint + a.freeze if frozen + b = a.dup + + assert_equal(a, b) + assert(a.__id__ != b.__id__) + assert_equal(false, b.frozen?) + assert_equal(a.tainted?, b.tainted?) + assert_equal(a.untrusted?, b.untrusted?) + end end end end @@ -599,6 +606,13 @@ class TestHash < Test::Unit::TestCase assert_equal([3,4], a.delete([3,4])) assert_equal([5,6], a.delete([5,6])) assert_equal(0, a.length) + + h = @cls[ 1=>2, 3=>4, 5=>6 ] + h.taint + h.untrust + a = h.to_a + assert_equal(true, a.tainted?) + assert_equal(true, a.untrusted?) end def test_to_hash diff --git a/test/ruby/test_marshal.rb b/test/ruby/test_marshal.rb index 069844583b..af389d2b2d 100644 --- a/test/ruby/test_marshal.rb +++ b/test/ruby/test_marshal.rb @@ -179,4 +179,16 @@ class TestMarshal < Test::Unit::TestCase Marshal.dump((0..1000).map {|x| C4.new(x % 50 == 25) }) end end + + def test_taint_and_untrust + x = Object.new + x.taint + x.untrust + s = Marshal.dump(x) + assert_equal(true, s.tainted?) + assert_equal(true, s.untrusted?) + y = Marshal.load(s) + assert_equal(true, y.tainted?) + assert_equal(true, y.untrusted?) + end end diff --git a/test/ruby/test_module.rb b/test/ruby/test_module.rb index 247ecc12be..edbbf250dd 100644 --- a/test/ruby/test_module.rb +++ b/test/ruby/test_module.rb @@ -699,4 +699,22 @@ class TestModule < Test::Unit::TestCase assert_equal(true, c2.include?(m)) assert_equal(false, m.include?(m)) end + + def test_include_under_safe4 + m = Module.new + c1 = Class.new + assert_raise(SecurityError) do + lambda { + $SAFE = 4 + c1.instance_eval { include(m) } + }.call + end + assert_nothing_raised do + lambda { + $SAFE = 4 + c2 = Class.new + c2.instance_eval { include(m) } + }.call + end + end end diff --git a/test/ruby/test_object.rb b/test/ruby/test_object.rb index 14ce98f8bc..5190eb69e5 100644 --- a/test/ruby/test_object.rb +++ b/test/ruby/test_object.rb @@ -320,4 +320,82 @@ class TestObject < Test::Unit::TestCase 1.extend end end + + def test_untrusted + obj = lambda { + $SAFE = 4 + x = Object.new + x.instance_eval { @foo = 1 } + x + }.call + assert_equal(true, obj.untrusted?) + assert_equal(true, obj.tainted?) + + x = Object.new + assert_equal(false, x.untrusted?) + assert_raise(SecurityError) do + lambda { + $SAFE = 4 + x.instance_eval { @foo = 1 } + }.call + end + + x = Object.new + x.taint + assert_raise(SecurityError) do + lambda { + $SAFE = 4 + x.instance_eval { @foo = 1 } + }.call + end + + x.untrust + assert_equal(true, x.untrusted?) + assert_nothing_raised do + lambda { + $SAFE = 4 + x.instance_eval { @foo = 1 } + }.call + end + + x.trust + assert_equal(false, x.untrusted?) + assert_raise(SecurityError) do + lambda { + $SAFE = 4 + x.instance_eval { @foo = 1 } + }.call + end + + a = Object.new + a.untrust + assert_equal(true, a.untrusted?) + b = a.dup + assert_equal(true, b.untrusted?) + c = a.clone + assert_equal(true, c.untrusted?) + + a = Object.new + b = lambda { + $SAFE = 4 + a.dup + }.call + assert_equal(true, b.untrusted?) + + a = Object.new + b = lambda { + $SAFE = 4 + a.clone + }.call + assert_equal(true, b.untrusted?) + end + + def test_to_s + x = Object.new + x.taint + x.untrust + s = x.to_s + assert_equal(true, s.untrusted?) + assert_equal(true, s.tainted?) + end end diff --git a/test/ruby/test_string.rb b/test/ruby/test_string.rb index 6dd46895eb..cd32709658 100644 --- a/test/ruby/test_string.rb +++ b/test/ruby/test_string.rb @@ -427,16 +427,20 @@ class TestString < Test::Unit::TestCase def test_clone for taint in [ false, true ] - for frozen in [ false, true ] - a = S("Cool") - a.taint if taint - a.freeze if frozen - b = a.clone - - assert_equal(a, b) - assert(a.__id__ != b.__id__) - assert_equal(a.frozen?, b.frozen?) - assert_equal(a.tainted?, b.tainted?) + for untrust in [ false, true ] + for frozen in [ false, true ] + a = S("Cool") + a.taint if taint + a.untrust if untrust + a.freeze if frozen + b = a.clone + + assert_equal(a, b) + assert(a.__id__ != b.__id__) + assert_equal(a.frozen?, b.frozen?) + assert_equal(a.untrusted?, b.untrusted?) + assert_equal(a.tainted?, b.tainted?) + end end end @@ -532,16 +536,20 @@ class TestString < Test::Unit::TestCase def test_dup for taint in [ false, true ] - for frozen in [ false, true ] - a = S("hello") - a.taint if taint - a.freeze if frozen - b = a.dup - - assert_equal(a, b) - assert(a.__id__ != b.__id__) - assert(!b.frozen?) - assert_equal(a.tainted?, b.tainted?) + for untrust in [ false, true ] + for frozen in [ false, true ] + a = S("hello") + a.taint if taint + a.untrust if untrust + a.freeze if frozen + b = a.dup + + assert_equal(a, b) + assert(a.__id__ != b.__id__) + assert(!b.frozen?) + assert_equal(a.tainted?, b.tainted?) + assert_equal(a.untrusted?, b.untrusted?) + end end end end @@ -623,7 +631,9 @@ class TestString < Test::Unit::TestCase a = S("hello") a.taint + a.untrust assert(a.gsub(/./, S('X')).tainted?) + assert(a.gsub(/./, S('X')).untrusted?) assert_equal("z", "abc".gsub(/./, "a" => "z"), "moved from btest/knownbug") @@ -651,8 +661,10 @@ class TestString < Test::Unit::TestCase r = S('X') r.taint + r.untrust a.gsub!(/./, r) assert(a.tainted?) + assert(a.untrusted?) a = S("hello") assert_nil(a.sub!(S('X'), S('Y'))) @@ -823,9 +835,11 @@ class TestString < Test::Unit::TestCase a = S("foo") a.taint + a.untrust b = a.replace(S("xyz")) assert_equal(S("xyz"), b) assert(b.tainted?) + assert(b.untrusted?) s = "foo" * 100 s2 = ("bar" * 100).dup @@ -1170,7 +1184,10 @@ class TestString < Test::Unit::TestCase a = S("hello") a.taint - assert(a.sub(/./, S('X')).tainted?) + a.untrust + x = a.sub(/./, S('X')) + assert(x.tainted?) + assert(x.untrusted?) o = Object.new def o.to_str; "bar"; end @@ -1211,8 +1228,10 @@ class TestString < Test::Unit::TestCase r = S('X') r.taint + r.untrust a.sub!(/./, r) assert(a.tainted?) + assert(a.untrusted?) end def test_succ diff --git a/time.c b/time.c index 236c2e9683..b3eabbcc71 100644 --- a/time.c +++ b/time.c @@ -60,7 +60,7 @@ static void time_modify(VALUE time) { rb_check_frozen(time); - if (!OBJ_TAINTED(time) && rb_safe_level() >= 4) + if (!OBJ_UNTRUSTED(time) && rb_safe_level() >= 4) rb_raise(rb_eSecurityError, "Insecure: can't modify Time"); } diff --git a/variable.c b/variable.c index 476220aa4b..48de287408 100644 --- a/variable.c +++ b/variable.c @@ -995,7 +995,7 @@ rb_ivar_set(VALUE obj, ID id, VALUE val) long i, len; int ivar_extended; - if (!OBJ_TAINTED(obj) && rb_safe_level() >= 4) + if (!OBJ_UNTRUSTED(obj) && rb_safe_level() >= 4) rb_raise(rb_eSecurityError, "Insecure: can't modify instance variable"); if (OBJ_FROZEN(obj)) rb_error_frozen("object"); switch (TYPE(obj)) { @@ -1216,7 +1216,7 @@ rb_obj_remove_instance_variable(VALUE obj, VALUE name) struct st_table *iv_index_tbl; st_data_t index; - if (!OBJ_TAINTED(obj) && rb_safe_level() >= 4) + if (!OBJ_UNTRUSTED(obj) && rb_safe_level() >= 4) rb_raise(rb_eSecurityError, "Insecure: can't modify instance variable"); if (OBJ_FROZEN(obj)) rb_error_frozen("object"); if (!rb_is_instance_id(id)) { @@ -1505,7 +1505,7 @@ rb_mod_remove_const(VALUE mod, VALUE name) if (!rb_is_const_id(id)) { rb_name_error(id, "`%s' is not allowed as a constant name", rb_id2name(id)); } - if (!OBJ_TAINTED(mod) && rb_safe_level() >= 4) + if (!OBJ_UNTRUSTED(mod) && rb_safe_level() >= 4) rb_raise(rb_eSecurityError, "Insecure: can't remove constant"); if (OBJ_FROZEN(mod)) rb_error_frozen("class/module"); @@ -1667,7 +1667,7 @@ mod_av_set(VALUE klass, ID id, VALUE val, int isconst) { const char *dest = isconst ? "constant" : "class variable"; - if (!OBJ_TAINTED(klass) && rb_safe_level() >= 4) + if (!OBJ_UNTRUSTED(klass) && rb_safe_level() >= 4) rb_raise(rb_eSecurityError, "Insecure: can't set %s", dest); if (OBJ_FROZEN(klass)) { if (BUILTIN_TYPE(klass) == T_MODULE) { @@ -1922,7 +1922,7 @@ rb_mod_remove_cvar(VALUE mod, VALUE name) if (!rb_is_class_id(id)) { rb_name_error(id, "wrong class variable name %s", rb_id2name(id)); } - if (!OBJ_TAINTED(mod) && rb_safe_level() >= 4) + if (!OBJ_UNTRUSTED(mod) && rb_safe_level() >= 4) rb_raise(rb_eSecurityError, "Insecure: can't remove class variable"); if (OBJ_FROZEN(mod)) rb_error_frozen("class/module"); diff --git a/vm_method.c b/vm_method.c index b9940a7230..d3f38d7945 100644 --- a/vm_method.c +++ b/vm_method.c @@ -108,7 +108,8 @@ rb_add_method(VALUE klass, ID mid, NODE * node, int noex) if (NIL_P(klass)) { klass = rb_cObject; } - if (rb_safe_level() >= 4 && (klass == rb_cObject || !OBJ_TAINTED(klass))) { + if (rb_safe_level() >= 4 && + (klass == rb_cObject || !OBJ_UNTRUSTED(klass))) { rb_raise(rb_eSecurityError, "Insecure: can't define method"); } if (!FL_TEST(klass, FL_SINGLETON) && @@ -307,7 +308,7 @@ remove_method(VALUE klass, ID mid) if (klass == rb_cObject) { rb_secure(4); } - if (rb_safe_level() >= 4 && !OBJ_TAINTED(klass)) { + if (rb_safe_level() >= 4 && !OBJ_UNTRUSTED(klass)) { rb_raise(rb_eSecurityError, "Insecure: can't remove method"); } if (OBJ_FROZEN(klass)) @@ -474,7 +475,7 @@ rb_undef(VALUE klass, ID id) if (rb_vm_cbase() == rb_cObject && klass == rb_cObject) { rb_secure(4); } - if (rb_safe_level() >= 4 && !OBJ_TAINTED(klass)) { + if (rb_safe_level() >= 4 && !OBJ_UNTRUSTED(klass)) { rb_raise(rb_eSecurityError, "Insecure: can't undef `%s'", rb_id2name(id)); } @@ -810,7 +811,7 @@ rb_mod_alias_method(VALUE mod, VALUE newname, VALUE oldname) static void secure_visibility(VALUE self) { - if (rb_safe_level() >= 4 && !OBJ_TAINTED(self)) { + if (rb_safe_level() >= 4 && !OBJ_UNTRUSTED(self)) { rb_raise(rb_eSecurityError, "Insecure: can't change method visibility"); } -- cgit v1.2.3