[ruby-dev:21727] Re: access ENV on $SAFE==4
From:
Hidetoshi NAGAI <nagai@...>
Date:
2003-10-26 15:08:45 UTC
List:
ruby-dev #21727
永井@知能.九工大です.
From: nobu.nakada@nifty.ne.jp
Subject: [ruby-dev:21725] Re: access ENV on $SAFE==4
Date: Sun, 26 Oct 2003 19:29:07 +0900
Message-ID: <200310261029.h9QAT69P024191@sharui.nakada.kanuma.tochigi.jp>
> > どういうケースを想定されてたんでしょう? > 中田さん
> >
> > 特に「これ」というケースがないようでしたら,
> > レベル設定機能はなくしちゃいましょう.
> とくに何も考えてませんでした。なしでいいと思います。
了解です.では正式に「レベル設定機能なし」ということで.
From: Hidetoshi NAGAI <nagai@ai.kyutech.ac.jp>
Subject: [ruby-dev:21723] Re: access ENV on $SAFE==4
Date: Sun, 26 Oct 2003 07:33:09 +0900
Message-ID: <20031026.073307.41640216.nagai@ai.kyutech.ac.jp>
> ところで,こうして ENV と Module とで secure/insecure を
> 使うように揃えてみると,secure? <-> insecure? のように
> 不揃いなのが気になりますね.
> 基本禁止 <-> 基本許可の違いゆえに仕方ないという感じもありますが,
> 対称性のため,無理やり ENV.insecure?(name), ENV.insecure_variables,
> Module#secure_const(const), Module#secure_const?(const),
> Module#secure_constants を追加するという選択もありそうです.
試しに加えてみました.
先のメールで ENV.insecure_variables と書いていたのは
ENV.keys と揃えて ENV.insecure_keys としています.
insecure_const? の語順はとりあえずそのままです.
----< $LOAD_PATH ($:, $-I) >------------------------
$SAFE >= 4 でのアクセスが禁止される.
----------------------------------------------------
----< ENV >-----------------------------------------
ENV.insecure(name)
: 環境変数 name は insecure であると設定する.
: ただし,$SAFE >= 4 で呼ばれた場合は例外を発生する.
: insecure に設定されている環境変数を $SAFE >= 4 で
: 読み出そうとした場合には例外を発生する.
: ( $SAFE >= 4 での書き込みは常に例外を発生することに注意.)
: すべての環境変数のデフォルト設定は「insecure」である.
ENV.secure(name)
: 環境変数 name を secure であると設定する.
: ただし,$SAFE >= 4 で呼ばれた場合は例外を発生する.
: $SAFE >= 4 で環境変数の値を読み出すためには
: その環境変数が secure に設定されていなければならない.
: そうでなければ例外を発生する.
ENV.insecure?(name)
: 環境変数 name (文字列指定) への $SAFE >= 4 でのアクセスが
: 禁止されている (insecureである) ならば true を,
: 許可されている (secureである) ならば false を返す.
ENV.secure?(name)
: ENV.insecure?(name) の否定
ENV.insecure_keys
: $SAFE >= 4 でのアクセスが禁止されている (insecureである)
: ような環境変数のリストを得る.
: ただし,$SAFE >= 4 で呼ばれた場合は例外を発生する.
ENV.secure_keys
: $SAFE >= 4 でのアクセスが許可されている (secureである)
: ような環境変数のリストを得る.
: ただし,$SAFE >= 4 で呼ばれた場合は例外を発生する.
----------------------------------------------------
----< Module >--------------------------------------
Module#insecure_const(const)
: module/class において,定数 const (文字列またはシンボル) が
: insecure であると設定する.(戻り値は const のシンボル)
: ただし,$SAFE >= 4 で呼ばれた場合は例外を発生する.
: insecure とされた定数への $SAFE >= 4 でのアクセスは例外を発生する.
: すべての環境変数のデフォルト設定は「secure」である.
Module#secure_const(const)
: module/class において,定数 const (文字列またはシンボル) が
: secure であると設定する.(戻り値は const のシンボル)
: ただし,$SAFE >= 4 で呼ばれた場合は例外を発生する.
Module#insecure_const?(const)
: module/class において,定数 const (文字列またはシンボル) が
: insecure と設定されているばあいは true を,
: 設定されていない場合には false を返す.
Module#secure_const?(const)
: Module#insecure_const?(const) の否定
Module#insecure_constants
: module/class において,insecure に設定されている定数の一覧を返す.
: ただし,$SAFE >= 4 で呼ばれた場合は例外を発生する.
Module#secure_constants
: module/class において,secure に設定されている定数の一覧を返す.
: ただし,$SAFE >= 4 で呼ばれた場合は例外を発生する.
----------------------------------------------------
----< RUBY_PLATFORM (PLATFORM) >--------------------
Object.insecure_const(:RUBY_PLATFORM) および
Object.insecure_const(:PLATFORM) として設定されている.
----------------------------------------------------
Index: eval.c
===================================================================
RCS file: /src/ruby/eval.c,v
retrieving revision 1.575
diff -u -r1.575 eval.c
--- eval.c 25 Oct 2003 00:36:56 -0000 1.575
+++ eval.c 26 Oct 2003 14:49:30 -0000
@@ -6424,6 +6424,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;
@@ -6723,9 +6733,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 26 Oct 2003 14:49:30 -0000
@@ -44,7 +44,7 @@
VALUE rb_cHash;
-static VALUE envtbl;
+static VALUE envtbl, secure_envkeys;
static ID id_hash, id_call, id_default;
VALUE
@@ -1017,6 +1017,53 @@
return env_str_new(ptr, strlen(ptr));
}
+
+static ID id_case_conv;
+
+static int
+env_secure_i(name)
+ VALUE name;
+{
+ VALUE key;
+
+ if (TYPE(name) == T_SYMBOL) {
+ name = rb_str_new2(rb_id2name(SYM2ID(name)));
+ }
+ StringValue(name);
+#ifdef ENV_IGNORECASE
+ key = rb_funcall(name, id_case_conv, 0);
+#else
+ key = name;
+#endif
+ if (RTEST(rb_ary_includes(secure_envkeys, key))) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+static VALUE
+env_secure_p(obj, name)
+ VALUE obj, name;
+{
+ if (env_secure_i(name)) {
+ return Qtrue;
+ } else {
+ return Qfalse;
+ }
+}
+
+static VALUE
+env_insecure_p(obj, name)
+ VALUE obj, name;
+{
+ if (env_secure_i(name)) {
+ return Qfalse;
+ } else {
+ return Qtrue;
+ }
+}
+
static VALUE
env_delete(obj, name)
VALUE obj, name;
@@ -1069,6 +1116,13 @@
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 */
+ return Qnil;
+ }
+ }
env = getenv(nam);
if (env) {
#ifdef ENV_IGNORECASE
@@ -1101,7 +1155,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 +1363,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 +1397,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 +1433,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 +1535,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 +1583,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 +1614,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 +1634,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 +1656,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 +1678,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 +1699,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 +1722,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 +1762,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 +1785,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 +1880,76 @@
return env;
}
+static VALUE
+env_secure_keys(obj)
+ VALUE obj;
+{
+ rb_secure(4);
+ return rb_ary_dup(secure_envkeys);
+}
+
+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; i<RARRAY(keys)->len; 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_secure(obj, name)
+ VALUE obj, name;
+{
+ VALUE key;
+
+ rb_secure(4);
+ if (!env_secure_i(name)) {
+ if (TYPE(name) == T_SYMBOL) {
+ name = rb_str_new2(rb_id2name(SYM2ID(name)));
+ }
+ StringValue(name);
+#ifdef ENV_IGNORECASE
+ key = rb_funcall(name, id_case_conv, 0);
+#else
+ key = name;
+#endif
+ rb_ary_push(secure_envkeys, name);
+ }
+ return key;
+}
+
+static VALUE
+env_insecure(obj, name)
+ VALUE obj, name;
+{
+ VALUE key;
+
+ rb_secure(4);
+ if (TYPE(name) == T_SYMBOL) {
+ name = rb_str_new2(rb_id2name(SYM2ID(name)));
+ }
+ StringValue(name);
+#ifdef ENV_IGNORECASE
+ key = rb_funcall(name, id_case_conv, 0);
+#else
+ key = name;
+#endif
+ if (RTEST(rb_ary_delete(secure_envkeys, key))) {
+ return key;
+ }
+ return Qnil;
+}
+
void
Init_Hash()
{
@@ -1846,11 +2017,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);
+ secure_envkeys = rb_ary_new();
+ rb_global_variable(&secure_envkeys);
+ rb_define_singleton_method(envtbl,"secure?", env_secure_p, 1);
+ rb_define_singleton_method(envtbl,"insecure?", env_insecure_p, 1);
+ rb_define_singleton_method(envtbl,"secure_keys", env_secure_keys, 0);
+ rb_define_singleton_method(envtbl,"insecure_keys", env_insecure_keys, 0);
+ rb_define_singleton_method(envtbl,"secure", env_secure, 1);
+ rb_define_singleton_method(envtbl,"insecure", env_insecure, 1);
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 26 Oct 2003 14:49:30 -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 26 Oct 2003 14:49:31 -0000
@@ -908,6 +908,60 @@
}
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;
+{
+ 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;
+{
+ 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 +1581,14 @@
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, "insecure_const", rb_mod_insecure_const, 1);
+ rb_define_method(rb_cModule, "insecure_const?", rb_mod_insecure_const_p, 1);
+ rb_define_method(rb_cModule, "insecure_constants", rb_mod_insecure_constants, 0);
+
+ rb_define_method(rb_cModule, "secure_const", rb_mod_secure_const, 1);
+ rb_define_method(rb_cModule, "secure_const?", rb_mod_secure_const_p, 1);
+ rb_define_method(rb_cModule, "secure_constants", rb_mod_secure_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 26 Oct 2003 14:49:31 -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; i<RARRAY(table)->len; 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; i<RARRAY(table)->len; 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; i<RARRAY(list)->len; 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 26 Oct 2003 14:49:31 -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