summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog15
-rw-r--r--array.c11
-rw-r--r--class.c8
-rw-r--r--debug.c4
-rw-r--r--dir.c6
-rw-r--r--hash.c4
-rw-r--r--include/ruby/ruby.h16
-rw-r--r--io.c13
-rw-r--r--marshal.c14
-rw-r--r--object.c67
-rw-r--r--re.c2
-rw-r--r--ruby.c4
-rw-r--r--string.c6
-rw-r--r--struct.c2
-rw-r--r--test/ruby/test_array.rb46
-rw-r--r--test/ruby/test_hash.rb54
-rw-r--r--test/ruby/test_marshal.rb12
-rw-r--r--test/ruby/test_module.rb18
-rw-r--r--test/ruby/test_object.rb78
-rw-r--r--test/ruby/test_string.rb61
-rw-r--r--time.c2
-rw-r--r--variable.c10
-rw-r--r--vm_method.c9
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 <shugo@ruby-lang.org>
+
+ * 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 <naruse@ruby-lang.org>
* 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<RARRAY_LEN(ary); i++) {
tmp = rb_check_string_type(RARRAY_PTR(ary)[i]);
@@ -1298,9 +1300,11 @@ rb_ary_join(VALUE ary, VALUE sep)
rb_str_buf_append(result, sep);
rb_str_buf_append(result, tmp);
if (OBJ_TAINTED(tmp)) taint = Qtrue;
+ if (OBJ_UNTRUSTED(tmp)) untrust = Qtrue;
}
if (taint) OBJ_TAINT(result);
+ if (untrust) OBJ_UNTRUST(result);
return result;
}
@@ -1330,6 +1334,7 @@ static VALUE
inspect_ary(VALUE ary, VALUE dummy, int recur)
{
int tainted = OBJ_TAINTED(ary);
+ int untrust = OBJ_UNTRUSTED(ary);
long i;
VALUE s, str;
@@ -1338,11 +1343,13 @@ inspect_ary(VALUE ary, VALUE dummy, int recur)
for (i=0; i<RARRAY_LEN(ary); i++) {
s = rb_inspect(RARRAY_PTR(ary)[i]);
if (OBJ_TAINTED(s)) tainted = Qtrue;
+ if (OBJ_UNTRUSTED(s)) untrust = Qtrue;
if (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 <code>true</code> 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 <i>obj</i> 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 <i>obj</i>.
+ */
+
+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");
}