From: Hidetoshi NAGAI Date: 2003-11-01T13:25:15+09:00 Subject: [ruby-dev:21804] Re: access ENV on $SAFE==4 永井@知能.九工大です. 以下の仕様でのパッチです. 重要な点は,ENV のアクセス拒否の場合に例外を返すのではなく, 環境変数が存在しない場合と同様に nil を返すようにしたことです. その他 ENV.keys 等で,アクセス拒否の環境変数については その環境変数が存在しない場合と同様になるようにしました. # 定数については例外があがります. これは,例外をあげてしまうとその環境変数の存在が知られるため, その環境変数に関連するアプリケーションの存在が察知されて 攻撃の糸口になってしまうことを回避するためです. ----< $LOAD_PATH ($:, $-I) >------------------------ $SAFE >= 4 でのアクセスが禁止される. ---------------------------------------------------- ----< ENV >----------------------------------------- ENV.allow_insecure_ref(name) : $SAFE >= 4 での環境変数 name の読み出しを許可する. : $SAFE >= 4 でこのメソッドが呼ばれた場合は例外を発生する. : すべての環境変数のデフォルト設定は「読み出し可」である. : ( $SAFE >= 4 での書き込みは常に例外を発生することに注意.) ENV.deny_insecure_ref(name) : $SAFE >= 4 での環境変数 name の読み出しを禁止する. : $SAFE >= 4 でこのメソッドが呼ばれた場合は例外を発生する. : 読み出し禁止に設定した環境変数を $SAFE >= 4 で読み出そうとすると, : その環境変数が存在しない場合と同様に nil が返る. : また,読み出し禁止の環境変数は ENV.keys 等でも表示されない. ENV.insecure_ref_allowed?(name) : 環境変数 name (文字列指定) への $SAFE >= 4 でのアクセスが : 許可されているならば true を,そうでなければ false を返す. : $SAFE >= 4 でこのメソッドが呼ばれた場合は例外を発生する. ENV.insecure_ref_denied?(name) : ENV.insecure_ref_allowed?(name) の否定 : $SAFE >= 4 でこのメソッドが呼ばれた場合は例外を発生する. ENV.insecure_ref_allowings : $SAFE >= 4 でのアクセスが許可されている環境変数のリストを得る. : $SAFE >= 4 でこのメソッドが呼ばれた場合は例外を発生する. ENV.insecure_ref_denyings : $SAFE >= 4 でのアクセスが禁止されている環境変数のリストを得る. : $SAFE >= 4 でこのメソッドが呼ばれた場合は例外を発生する. ---------------------------------------------------- ----< Module >-------------------------------------- Module#allow_insecure_ref(const) : module/class において,定数 const (文字列またはシンボル) への : $SAFE >= 4 での参照を許可する.(戻り値は const のシンボル) : $SAFE >= 4 でこのメソッドが呼ばれた場合は例外を発生する. : すべての定数のデフォルト設定は「参照禁止」である. Module#deny_insecure_ref(const) : module/class において,定数 const (文字列またはシンボル) への : $SAFE >= 4 での参照を禁止する.(戻り値は const のシンボル) : $SAFE >= 4 でこのメソッドが呼ばれた場合は例外を発生する. : 参照禁止に設定した定数を $SAFE >= 4 で参照しようとすると : 例外を発生する. Module#insecure_ref_allowed?(const) : module/class において,定数 const (文字列またはシンボル) への : $SAFE >= 4 での参照が許可されているならば true を, : 禁止されているならば false を返す. : $SAFE >= 4 でこのメソッドが呼ばれた場合は例外を発生する. Module#insecure_ref_denied?(const) : Module#insecure_ref_allowed?(const) の否定 : $SAFE >= 4 でこのメソッドが呼ばれた場合は例外を発生する. Module#insecure_ref_allowings : module/class において,$SAFE >= 4 での参照が許可されている定数の : 一覧を返す. : $SAFE >= 4 でこのメソッドが呼ばれた場合は例外を発生する. Module#insecure_ref_denyings : module/class において,$SAFE >= 4 での参照が禁止されている定数の : 一覧を返す. : $SAFE >= 4 でこのメソッドが呼ばれた場合は例外を発生する. ---------------------------------------------------- ----< RUBY_PLATFORM (PLATFORM) >-------------------- Object.deny_insecure_ref(:RUBY_PLATFORM) および Object.deny_insecure_ref(:PLATFORM) として設定されている. ---------------------------------------------------- Index: eval.c =================================================================== RCS file: /src/ruby/eval.c,v retrieving revision 1.582 diff -u -r1.582 eval.c --- eval.c 30 Oct 2003 16:33:31 -0000 1.582 +++ eval.c 1 Nov 2003 04:24:01 -0000 @@ -6426,6 +6426,16 @@ } static VALUE +loadpath_getter(id) + ID id; +{ + if (rb_safe_level() >= 4) { + return rb_ary_new(); + } + return rb_load_path; +} + +static VALUE rb_f_local_variables() { ID *tbl; @@ -6725,9 +6735,9 @@ Init_load() { rb_load_path = rb_ary_new(); - rb_define_readonly_variable("$:", &rb_load_path); - rb_define_readonly_variable("$-I", &rb_load_path); - rb_define_readonly_variable("$LOAD_PATH", &rb_load_path); + rb_define_hooked_variable("$:", &rb_load_path, loadpath_getter, 0); + rb_define_hooked_variable("$-I", &rb_load_path, loadpath_getter, 0); + rb_define_hooked_variable("$LOAD_PATH", &rb_load_path, loadpath_getter, 0); rb_features = rb_ary_new(); rb_define_readonly_variable("$\"", &rb_features); Index: hash.c =================================================================== RCS file: /src/ruby/hash.c,v retrieving revision 1.117 diff -u -r1.117 hash.c --- hash.c 24 Oct 2003 14:31:10 -0000 1.117 +++ hash.c 1 Nov 2003 04:24:02 -0000 @@ -44,7 +44,6 @@ VALUE rb_cHash; -static VALUE envtbl; static ID id_hash, id_call, id_default; VALUE @@ -1017,6 +1016,60 @@ return env_str_new(ptr, strlen(ptr)); } +#define ENV_INSECURE_REF_ALLOW 1 +#define ENV_INSECURE_REF_DENY 0 + +#ifndef DEFAULT_ENVKEY_ON_TABLE +#define DEFAULT_ENVKEY_ON_TABLE ENV_INSECURE_REF_DENY +#endif +static int envkey_on_table = DEFAULT_ENVKEY_ON_TABLE; + +static VALUE envtbl, envkey_table; +static ID id_case_conv; + +static int +env_secure_i(name) + VALUE name; +{ + VALUE key; + + StringValue(name); +#ifdef ENV_IGNORECASE + key = rb_funcall(name, id_case_conv, 0); +#else + key = name; +#endif + if (RTEST(rb_ary_includes(envkey_table, key))) { + return envkey_on_table; + } else { + return !envkey_on_table; + } +} + +static VALUE +env_secure_p(obj, name) + VALUE obj, name; +{ + rb_secure(4); + if (env_secure_i(name)) { + return Qtrue; + } else { + return Qfalse; + } +} + +static VALUE +env_insecure_p(obj, name) + VALUE obj, name; +{ + rb_secure(4); + if (env_secure_i(name)) { + return Qfalse; + } else { + return Qtrue; + } +} + static VALUE env_delete(obj, name) VALUE obj, name; @@ -1069,6 +1122,14 @@ if (strlen(nam) != RSTRING(name)->len) { rb_raise(rb_eArgError, "bad environment variable name"); } + if (rb_safe_level() >= 4) { + /* allowed key? */ + if (!env_secure_i(name)) { + /* not allowed */ + /* rb_raise(rb_eSecurityError, "Insecure: can't refer ENV[\"%s\"]", name); */ + return Qnil; + } + } env = getenv(nam); if (env) { #ifdef ENV_IGNORECASE @@ -1101,7 +1162,12 @@ if (strlen(nam) != RSTRING(key)->len) { rb_raise(rb_eArgError, "bad environment variable name"); } - env = getenv(nam); + if (rb_safe_level() >= 4 && !env_secure_i(key)) { + /* not allowed */ + env = (char*)NULL; + } else { + env = getenv(nam); + } if (!env) { if (rb_block_given_p()) { if (argc > 1) { @@ -1304,7 +1370,10 @@ while (*env) { char *s = strchr(*env, '='); if (s) { - rb_ary_push(ary, env_str_new(*env, s-*env)); + VALUE k = env_str_new(*env, s-*env); + if (rb_safe_level() < 4 || env_secure_i(k)) { + rb_ary_push(ary, k); + } } env++; } @@ -1335,7 +1404,9 @@ while (*env) { char *s = strchr(*env, '='); if (s) { - rb_ary_push(ary, env_str_new2(s+1)); + if (rb_safe_level() < 4 || env_secure_i(env_str_new(*env,s-*env))) { + rb_ary_push(ary, env_str_new2(s+1)); + } } env++; } @@ -1369,8 +1440,11 @@ while (*env) { char *s = strchr(*env, '='); if (s) { - rb_ary_push(ary, env_str_new(*env, s-*env)); - rb_ary_push(ary, env_str_new2(s+1)); + VALUE k = env_str_new(*env, s-*env); + if (rb_safe_level() < 4 || env_secure_i(k)) { + rb_ary_push(ary, k); + rb_ary_push(ary, env_str_new2(s+1)); + } } env++; } @@ -1468,8 +1542,10 @@ if (s) { VALUE k = env_str_new(*env, s-*env); VALUE v = env_str_new2(s+1); - if (RTEST(rb_yield_values(2, k, v))) { - rb_ary_push(result, rb_assoc_new(k, v)); + if (rb_safe_level() < 4 || env_secure_i(k)) { + if (RTEST(rb_yield_values(2, k, v))) { + rb_ary_push(result, rb_assoc_new(k, v)); + } } } env++; @@ -1514,15 +1590,17 @@ while (*env) { char *s = strchr(*env, '='); - if (env != environ) { - rb_str_buf_cat2(str, ", "); - } if (s) { - rb_str_buf_cat2(str, "\""); - rb_str_buf_cat(str, *env, s-*env); - rb_str_buf_cat2(str, "\"=>"); - i = rb_inspect(rb_str_new2(s+1)); - rb_str_buf_append(str, i); + if (rb_safe_level() < 4 || env_secure_i(env_str_new(*env,s-*env))) { + if (env != environ) { + rb_str_buf_cat2(str, ", "); + } + rb_str_buf_cat2(str, "\""); + rb_str_buf_cat(str, *env, s-*env); + rb_str_buf_cat2(str, "\"=>"); + i = rb_inspect(rb_str_new2(s+1)); + rb_str_buf_append(str, i); + } } env++; } @@ -1543,8 +1621,10 @@ while (*env) { char *s = strchr(*env, '='); if (s) { - rb_ary_push(ary, rb_assoc_new(env_str_new(*env, s-*env), - env_str_new2(s+1))); + VALUE k = env_str_new(*env, s-*env); + if (rb_safe_level() < 4 || env_secure_i(k)) { + rb_ary_push(ary, rb_assoc_new(k, env_str_new2(s+1))); + } } env++; } @@ -1561,14 +1641,21 @@ static VALUE env_size() { - int i; + int size = 0; char **env; env = GET_ENVIRON(environ); - for(i=0; env[i]; i++) - ; + while (*env) { + char *s = strchr(*env, '='); + if (s) { + if (rb_safe_level() < 4 || env_secure_i(env_str_new(*env,s-*env))) { + size++; + } + } + env++; + } FREE_ENVIRON(environ); - return INT2FIX(i); + return INT2FIX(size); } static VALUE @@ -1576,6 +1663,13 @@ { char **env; + if (rb_safe_level() >= 4) { + if (FIX2INT(env_size()) > 0) { + return Qtrue; + } else { + return Qfalse; + } + } env = GET_ENVIRON(environ); if (env[0] == 0) { FREE_ENVIRON(environ); @@ -1591,6 +1685,9 @@ { char *s; + if (rb_safe_level() >= 4 && !env_secure_i(key)) { + return Qfalse; + } s = StringValuePtr(key); if (strlen(s) != RSTRING(key)->len) rb_raise(rb_eArgError, "bad environment variable name"); @@ -1609,13 +1706,16 @@ while (*env) { char *s = strchr(*env, '='); if (s++) { + VALUE k = env_str_new(*env, s-*env); + if (rb_safe_level() < 4 || env_secure_i(k)) { #ifdef ENV_IGNORECASE - if (strncasecmp(s, RSTRING(value)->ptr, strlen(s)) == 0) { + if (strncasecmp(s, RSTRING(value)->ptr, strlen(s)) == 0) { #else - if (strncmp(s, RSTRING(value)->ptr, strlen(s)) == 0) { + if (strncmp(s, RSTRING(value)->ptr, strlen(s)) == 0) { #endif - FREE_ENVIRON(environ); - return Qtrue; + FREE_ENVIRON(environ); + return Qtrue; + } } } env++; @@ -1629,21 +1729,22 @@ VALUE dmy, value; { char **env; - VALUE str; StringValue(value); env = GET_ENVIRON(environ); while (*env) { char *s = strchr(*env, '='); if (s++) { + VALUE k = env_str_new(*env, s-*env); + if (rb_safe_level() < 4 || env_secure_i(k)) { #ifdef ENV_IGNORECASE - if (strncasecmp(s, RSTRING(value)->ptr, strlen(s)) == 0) { + if (strncasecmp(s, RSTRING(value)->ptr, strlen(s)) == 0) { #else - if (strncmp(s, RSTRING(value)->ptr, strlen(s)) == 0) { + if (strncmp(s, RSTRING(value)->ptr, strlen(s)) == 0) { #endif - str = env_str_new(*env, s-*env-1); - FREE_ENVIRON(environ); - return str; + FREE_ENVIRON(environ); + return k; + } } } env++; @@ -1668,7 +1769,12 @@ RARRAY(indexes)->ptr[i] = Qnil; } else { - RARRAY(indexes)->ptr[i] = env_str_new2(getenv(RSTRING(tmp)->ptr)); + if (rb_safe_level() >= 4 && !env_secure_i(tmp)) { + RARRAY(indexes)->ptr[i] = Qnil; + } + else { + RARRAY(indexes)->ptr[i] = env_str_new2(getenv(RSTRING(tmp)->ptr)); + } } RARRAY(indexes)->len = i+1; } @@ -1686,8 +1792,10 @@ while (*env) { char *s = strchr(*env, '='); if (s) { - rb_hash_aset(hash, env_str_new(*env, s-*env), - env_str_new2(s+1)); + VALUE key = env_str_new(*env, s-*env); + if (rb_safe_level() < 4 || env_secure_i(key)) { + rb_hash_aset(hash, key, env_str_new2(s+1)); + } } env++; } @@ -1779,6 +1887,82 @@ return env; } +static VALUE +env_secure_keys(obj) + VALUE obj; +{ + VALUE keys, secure; + long i; + + rb_secure(4); + secure = rb_ary_new(); + keys = env_keys(); + for(i=0; ilen; i++) { + if (env_secure_i(RARRAY(keys)->ptr[i])) { + rb_ary_push(secure, RARRAY(keys)->ptr[i]); + } + } + return rb_obj_freeze(secure); +} + +static VALUE +env_insecure_keys(obj) + VALUE obj; +{ + VALUE keys, insecure; + long i; + + rb_secure(4); + insecure = rb_ary_new(); + keys = env_keys(); + for(i=0; ilen; i++) { + if (!env_secure_i(RARRAY(keys)->ptr[i])) { + rb_ary_push(insecure, RARRAY(keys)->ptr[i]); + } + } + return rb_obj_freeze(insecure); +} + +static VALUE +env_set_secure_mode(name, mode) + VALUE name; + int mode; +{ + VALUE key; + + rb_secure(4); + + StringValue(name); +#ifdef ENV_IGNORECASE + key = rb_funcall(name, id_case_conv, 0); +#else + key = name; +#endif + + if (envkey_on_table == mode) { + if (!RTEST(rb_ary_includes(envkey_table, key))) { + rb_ary_push(envkey_table, rb_obj_freeze(rb_obj_dup(key))); + } + } else { + rb_ary_delete(envkey_table, key); + } + return key; +} + +static VALUE +env_secure(obj, name) + VALUE obj, name; +{ + return env_set_secure_mode(name, ENV_INSECURE_REF_ALLOW); +} + +static VALUE +env_insecure(obj, name) + VALUE obj, name; +{ + return env_set_secure_mode(name, ENV_INSECURE_REF_DENY); +} + void Init_Hash() { @@ -1846,11 +2030,25 @@ rb_define_method(rb_cHash,"key?", rb_hash_has_key, 1); rb_define_method(rb_cHash,"value?", rb_hash_has_value, 1); +#if defined(__human68k__) + id_case_conv = rb_intern("downcase"); +#else + id_case_conv = rb_intern("upcase"); +#endif + #ifndef __MACOS__ /* environment variables nothing on MacOS. */ origenviron = environ; envtbl = rb_obj_alloc(rb_cObject); rb_extend_object(envtbl, rb_mEnumerable); + envkey_table = rb_ary_new(); + rb_global_variable(&envkey_table); + rb_define_singleton_method(envtbl,"allow_insecure_ref", env_secure, 1); + rb_define_singleton_method(envtbl,"deny_insecure_ref", env_insecure, 1); + rb_define_singleton_method(envtbl,"insecure_ref_allowed?", env_secure_p, 1); + rb_define_singleton_method(envtbl,"insecure_ref_denied?", env_insecure_p, 1); + rb_define_singleton_method(envtbl,"insecure_ref_allowings", env_secure_keys, 0); + rb_define_singleton_method(envtbl,"insecure_ref_denyings", env_insecure_keys, 0); rb_define_singleton_method(envtbl,"[]", rb_f_getenv, 1); rb_define_singleton_method(envtbl,"fetch", env_fetch, -1); rb_define_singleton_method(envtbl,"[]=", env_aset, 2); Index: intern.h =================================================================== RCS file: /src/ruby/intern.h,v retrieving revision 1.137 diff -u -r1.137 intern.h --- intern.h 14 Oct 2003 02:53:53 -0000 1.137 +++ intern.h 1 Nov 2003 04:24:02 -0000 @@ -476,6 +476,11 @@ void rb_define_class_variable _((VALUE, const char*, VALUE)); VALUE rb_mod_class_variables _((VALUE)); VALUE rb_mod_remove_cvar _((VALUE, VALUE)); +int rb_insecure_const_defined _((VALUE, ID)); +void rb_insecure_const_set _((VALUE, ID)); +VALUE rb_insecure_const_remove _((VALUE, ID)); +VALUE rb_mod_insecure_constants _((VALUE)); +VALUE rb_mod_secure_constants _((VALUE)); /* version.c */ void ruby_show_version _((void)); void ruby_show_copyright _((void)); Index: object.c =================================================================== RCS file: /src/ruby/object.c,v retrieving revision 1.129 diff -u -r1.129 object.c --- object.c 13 Aug 2003 07:13:45 -0000 1.129 +++ object.c 1 Nov 2003 04:24:02 -0000 @@ -908,6 +908,62 @@ } static VALUE +rb_mod_insecure_const(klass, name) + VALUE klass; + VALUE name; +{ + ID id; + + id = rb_to_id(name); + if (!rb_is_const_id(id)) { + rb_name_error(id, "wrong constant name %s", rb_id2name(id)); + } + + rb_insecure_const_set(klass, id); + return ID2SYM(id); +} + +static VALUE +rb_mod_secure_const(klass, name) + VALUE klass; + VALUE name; +{ + ID id; + + rb_secure(4); + id = rb_to_id(name); + if (!rb_is_const_id(id)) { + rb_name_error(id, "wrong constant name %s", rb_id2name(id)); + } + + return rb_insecure_const_remove(klass, id); +} + +VALUE +rb_mod_insecure_const_p(mod, name) + VALUE mod; + VALUE name; +{ + rb_secure(4); + if (rb_insecure_const_defined(mod, rb_to_id(name))) { + return Qtrue; + } + return Qfalse; +} + +VALUE +rb_mod_secure_const_p(mod, name) + VALUE mod; + VALUE name; +{ + rb_secure(4); + if (RTEST(rb_mod_insecure_const_p(mod, name))) { + return Qfalse; + } + return Qtrue; +} + +static VALUE rb_mod_const_defined(mod, name) VALUE mod, name; { @@ -1527,6 +1583,13 @@ rb_define_method(rb_cModule, "const_missing", rb_mod_const_missing, 1); rb_define_method(rb_cModule, "class_variables", rb_mod_class_variables, 0); rb_define_private_method(rb_cModule, "remove_class_variable", rb_mod_remove_cvar, 1); + + rb_define_method(rb_cModule, "allow_insecure_ref", rb_mod_secure_const, 1); + rb_define_method(rb_cModule, "deny_insecure_ref", rb_mod_insecure_const, 1); + rb_define_method(rb_cModule, "insecure_ref_allowed?", rb_mod_secure_const_p, 1); + rb_define_method(rb_cModule, "insecure_ref_denied?", rb_mod_insecure_const_p, 1); + rb_define_method(rb_cModule, "insecure_ref_allowings", rb_mod_secure_constants, 0); + rb_define_method(rb_cModule, "insecure_ref_denyings", rb_mod_insecure_constants, 0); rb_define_method(rb_cClass, "allocate", rb_obj_alloc, 0); rb_define_method(rb_cClass, "new", rb_class_new_instance, -1); Index: variable.c =================================================================== RCS file: /src/ruby/variable.c,v retrieving revision 1.107 diff -u -r1.107 variable.c --- variable.c 13 Oct 2003 14:57:36 -0000 1.107 +++ variable.c 1 Nov 2003 04:24:02 -0000 @@ -21,6 +21,7 @@ static st_table *rb_global_tbl; st_table *rb_class_tbl; static ID autoload, classpath, tmp_classpath; +static ID insecure_consts; void Init_var_tables() @@ -30,6 +31,7 @@ autoload = rb_intern("__autoload__"); classpath = rb_intern("__classpath__"); tmp_classpath = rb_intern("__tmp_classpath__"); + insecure_consts = rb_intern("__insecure_contants__"); } struct fc_result { @@ -1275,6 +1277,12 @@ VALUE value, tmp; int mod_retry = 0; + if (rb_insecure_const_defined(klass, id) && rb_safe_level() >= 4) { + rb_raise(rb_eSecurityError, + "Insecure: can't access insecure constant %s", + rb_id2name(id)); + } + tmp = klass; retry: while (tmp) { @@ -1430,6 +1438,141 @@ return rb_const_list(rb_mod_const_of(mod, 0)); } +static int +rb_insecure_const_defined_0(klass, id, exclude, recurse) + VALUE klass; + ID id; + int exclude, recurse; +{ + VALUE tmp, table, val; + int mod_retry = 0; + + tmp = klass; + retry: + while (tmp) { + table = ivar_get(tmp, insecure_consts, 0); + if (TYPE(table) == T_ARRAY && rb_ary_includes(table, ID2SYM(id))) { + if (exclude && tmp == rb_cObject && klass != rb_cObject) { + rb_warn("toplevel constant %s referenced by %s::%s", + rb_id2name(id), rb_class2name(klass), rb_id2name(id)); + } + return 1; + } + if (!recurse && klass != rb_cObject) break; + tmp = RCLASS(tmp)->super; + } + if (!exclude && !mod_retry && BUILTIN_TYPE(klass) == T_MODULE) { + mod_retry = 1; + tmp = rb_cObject; + goto retry; + } + + return 0; +} + +int +rb_insecure_const_defined_from(klass, id) + VALUE klass; + ID id; +{ + return rb_insecure_const_defined_0(klass, id, Qtrue, Qtrue); +} + +int +rb_insecure_const_defined(klass, id) + VALUE klass; + ID id; +{ + return rb_insecure_const_defined_0(klass, id, Qfalse, Qtrue); +} + +int +rb_insecure_const_defined_at(klass, id) + VALUE klass; + ID id; +{ + return rb_insecure_const_defined_0(klass, id, Qtrue, Qfalse); +} + +void +rb_insecure_const_set(klass, id) + VALUE klass; + ID id; +{ + VALUE table, sym; + long i; + + table = ivar_get(klass, insecure_consts, 0); + if (TYPE(table) != T_ARRAY) { + table = rb_ary_new(); + rb_ivar_set(klass, insecure_consts, table); + } + + sym = ID2SYM(id); + for (i=0; ilen; i++) { + if (rb_equal(RARRAY(table)->ptr[i], sym)) { + return; + } + } + rb_ary_push(table, sym); + return; +} + +VALUE +rb_insecure_const_remove(klass, id) + VALUE klass; + ID id; +{ + VALUE table; + + table = ivar_get(klass, insecure_consts, 0); + if (TYPE(table) == T_ARRAY) { + return rb_ary_delete(table, ID2SYM(id)); + } + return Qnil; +} + +VALUE +rb_mod_insecure_constants(mod) + VALUE mod; +{ + VALUE table, ary; + long i; + + rb_secure(4); + + table = ivar_get(mod, insecure_consts, 0); + + if (TYPE(table) != T_ARRAY) { + /* no table */ + return rb_obj_freeze(rb_ary_new2(0)); + } + + ary = rb_ary_new(); + for(i=0; ilen; i++) { + rb_ary_push(ary, rb_obj_freeze(rb_str_new2(rb_id2name(SYM2ID(RARRAY(table)->ptr[i]))))); + } + return rb_obj_freeze(ary); +} + +VALUE +rb_mod_secure_constants(mod) + VALUE mod; +{ + VALUE list, secure; + long i; + + rb_secure(4); + secure = rb_ary_new(); + list = rb_mod_constants(mod); + for(i=0; ilen; i++) { + if (!rb_insecure_const_defined(mod, rb_to_id(RARRAY(list)->ptr[i]))) { + rb_ary_push(secure, RARRAY(list)->ptr[i]); + } + } + return rb_obj_freeze(secure); +} + static int rb_const_defined_0(klass, id, exclude, recurse) VALUE klass; @@ -1517,6 +1660,11 @@ ID id; VALUE val; { + if (rb_insecure_const_defined(klass, id) && rb_safe_level() >= 4) { + rb_raise(rb_eSecurityError, + "Insecure: can't change insecure constant %s", + rb_id2name(id)); + } mod_av_set(klass, id, val, Qtrue); } Index: version.c =================================================================== RCS file: /src/ruby/version.c,v retrieving revision 1.8 diff -u -r1.8 version.c --- version.c 16 Jan 2003 07:34:03 -0000 1.8 +++ version.c 1 Nov 2003 04:24:02 -0000 @@ -24,11 +24,13 @@ rb_define_global_const("RUBY_VERSION", v); rb_define_global_const("RUBY_RELEASE_DATE", d); rb_define_global_const("RUBY_PLATFORM", p); + rb_insecure_const_set(rb_cObject, rb_intern("RUBY_PLATFORM")); /* obsolete constants */ rb_define_global_const("VERSION", v); rb_define_global_const("RELEASE_DATE", d); rb_define_global_const("PLATFORM", p); + rb_insecure_const_set(rb_cObject, rb_intern("PLATFORM")); } void -- 永井 秀利 (九工大 知能情報) nagai@ai.kyutech.ac.jp