summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeremy Evans <code@jeremyevans.net>2019-09-20 19:06:22 -0700
committerJeremy Evans <code@jeremyevans.net>2019-11-18 01:00:25 +0200
commitc5c05460ac20abcbc0ed686eb4acf06da7a39a79 (patch)
tree991109a68f3b1cd2e256a936701d3b2badd3ddac
parent7b6a8b5b54448235e17ed187d9d73f56893e1b6f (diff)
Warn on access/modify of $SAFE, and remove effects of modifying $SAFE
This removes the security features added by $SAFE = 1, and warns for access or modification of $SAFE from Ruby-level, as well as warning when calling all public C functions related to $SAFE. This modifies some internal functions that took a safe level argument to no longer take the argument. rb_require_safe now warns, rb_require_string has been added as a version that takes a VALUE and does not warn. One public C function that still takes a safe level argument and that this doesn't warn for is rb_eval_cmd. We may want to consider adding an alternative method that does not take a safe level argument, and warn for rb_eval_cmd.
Notes
Notes: Merged: https://github.com/ruby/ruby/pull/2476
-rw-r--r--dir.c1
-rw-r--r--encoding.c2
-rw-r--r--error.c6
-rw-r--r--eval.c1
-rw-r--r--ext/etc/etc.c2
-rw-r--r--ext/io/console/console.c1
-rw-r--r--ext/openssl/ossl_rand.c8
-rw-r--r--ext/openssl/ossl_x509store.c2
-rw-r--r--ext/readline/readline.c1
-rw-r--r--ext/socket/constants.c1
-rw-r--r--ext/socket/raddrinfo.c8
-rw-r--r--ext/socket/unixsocket.c1
-rw-r--r--ext/syslog/syslog.c1
-rw-r--r--ext/win32ole/win32ole.c12
-rw-r--r--ext/win32ole/win32ole_event.c4
-rw-r--r--file.c64
-rw-r--r--gc.c10
-rw-r--r--hash.c2
-rw-r--r--include/ruby/intern.h7
-rw-r--r--include/ruby/ruby.h16
-rw-r--r--internal.h9
-rw-r--r--io.c3
-rw-r--r--iseq.c10
-rw-r--r--lib/debug.rb5
-rw-r--r--lib/drb/drb.rb62
-rw-r--r--lib/erb.rb20
-rw-r--r--lib/net/smtp.rb6
-rw-r--r--lib/tempfile.rb4
-rw-r--r--lib/tmpdir.rb34
-rw-r--r--load.c68
-rw-r--r--parse.y2
-rw-r--r--proc.c29
-rw-r--r--process.c12
-rw-r--r--ruby.c56
-rw-r--r--safe.c36
-rw-r--r--signal.c10
-rw-r--r--spec/ruby/language/predefined_spec.rb2
-rw-r--r--spec/ruby/language/safe_spec.rb201
-rw-r--r--spec/ruby/optional/capi/string_spec.rb26
-rw-r--r--test/net/imap/test_imap_response_parser.rb13
-rw-r--r--test/pathname/test_pathname.rb10
-rw-r--r--test/readline/test_readline.rb15
-rw-r--r--test/ruby/test_alias.rb6
-rw-r--r--test/ruby/test_file.rb12
-rw-r--r--test/ruby/test_optimization.rb11
-rw-r--r--test/ruby/test_proc.rb39
-rw-r--r--test/ruby/test_require.rb7
-rw-r--r--test/ruby/test_rubyoptions.rb14
-rw-r--r--test/ruby/test_thread.rb17
-rw-r--r--test/test_tempfile.rb11
-rw-r--r--test/test_tmpdir.rb13
-rw-r--r--test/win32ole/test_win32ole.rb49
-rw-r--r--test/win32ole/test_win32ole_event.rb15
-rw-r--r--thread.c3
-rw-r--r--tool/lib/leakchecker.rb5
-rw-r--r--transcode.c2
-rw-r--r--variable.c25
-rw-r--r--vm_core.h1
-rw-r--r--vm_eval.c9
59 files changed, 277 insertions, 745 deletions
diff --git a/dir.c b/dir.c
index 5221490..cefb5e7 100644
--- a/dir.c
+++ b/dir.c
@@ -2719,7 +2719,6 @@ rb_push_glob(VALUE str, VALUE base, int flags) /* '\0' is delimiter */
rb_raise(rb_eArgError, "nul-separated glob pattern is deprecated");
}
else {
- rb_check_safe_obj(str);
rb_enc_check(str, rb_enc_from_encoding(rb_usascii_encoding()));
}
ary = rb_ary_new();
diff --git a/encoding.c b/encoding.c
index c136908..b000e0f 100644
--- a/encoding.c
+++ b/encoding.c
@@ -654,7 +654,7 @@ load_encoding(const char *name)
ruby_verbose = Qfalse;
ruby_debug = Qfalse;
errinfo = rb_errinfo();
- loaded = rb_require_internal(enclib, rb_safe_level());
+ loaded = rb_require_internal(enclib);
ruby_verbose = verbose;
ruby_debug = debug;
rb_set_errinfo(errinfo);
diff --git a/error.c b/error.c
index 7a88ccb..6ce49e0 100644
--- a/error.c
+++ b/error.c
@@ -2985,12 +2985,6 @@ rb_check_copyable(VALUE obj, VALUE orig)
if (!FL_ABLE(obj)) return;
rb_check_frozen_internal(obj);
if (!FL_ABLE(orig)) return;
- if ((~RBASIC(obj)->flags & RBASIC(orig)->flags) & FL_TAINT) {
- if (rb_safe_level() > 0) {
- rb_raise(rb_eSecurityError, "Insecure: can't modify %"PRIsVALUE,
- RBASIC(obj)->klass);
- }
- }
}
void
diff --git a/eval.c b/eval.c
index 64149d2..77b0efa 100644
--- a/eval.c
+++ b/eval.c
@@ -204,7 +204,6 @@ rb_ec_cleanup(rb_execution_context_t *ec, volatile int ex)
th = th0;
errs[1] = ec->errinfo;
if (THROW_DATA_P(ec->errinfo)) ec->errinfo = Qnil;
- rb_set_safe_level_force(0);
ruby_init_stack(&errs[STACK_UPPER(errs, 0, 1)]);
SAVE_ROOT_JMPBUF(th, rb_ec_teardown(ec));
diff --git a/ext/etc/etc.c b/ext/etc/etc.c
index 28761df..1bb10e0 100644
--- a/ext/etc/etc.c
+++ b/ext/etc/etc.c
@@ -219,7 +219,6 @@ etc_getpwnam(VALUE obj, VALUE nam)
struct passwd *pwd;
const char *p = StringValueCStr(nam);
- rb_check_safe_obj(nam);
pwd = getpwnam(p);
if (pwd == 0) rb_raise(rb_eArgError, "can't find user for %"PRIsVALUE, nam);
return setup_passwd(pwd);
@@ -463,7 +462,6 @@ etc_getgrnam(VALUE obj, VALUE nam)
struct group *grp;
const char *p = StringValueCStr(nam);
- rb_check_safe_obj(nam);
grp = getgrnam(p);
if (grp == 0) rb_raise(rb_eArgError, "can't find group for %"PRIsVALUE, nam);
return setup_group(grp);
diff --git a/ext/io/console/console.c b/ext/io/console/console.c
index 4f04709..42b000f 100644
--- a/ext/io/console/console.c
+++ b/ext/io/console/console.c
@@ -1483,7 +1483,6 @@ prompt(int argc, VALUE *argv, VALUE io)
if (argc > 0 && !NIL_P(argv[0])) {
VALUE str = argv[0];
StringValueCStr(str);
- rb_check_safe_obj(str);
rb_io_write(io, str);
}
}
diff --git a/ext/openssl/ossl_rand.c b/ext/openssl/ossl_rand.c
index c958570..4a4f9dd 100644
--- a/ext/openssl/ossl_rand.c
+++ b/ext/openssl/ossl_rand.c
@@ -67,8 +67,6 @@ ossl_rand_add(VALUE self, VALUE str, VALUE entropy)
static VALUE
ossl_rand_load_file(VALUE self, VALUE filename)
{
- rb_check_safe_obj(filename);
-
if(!RAND_load_file(StringValueCStr(filename), -1)) {
ossl_raise(eRandomError, NULL);
}
@@ -86,8 +84,6 @@ ossl_rand_load_file(VALUE self, VALUE filename)
static VALUE
ossl_rand_write_file(VALUE self, VALUE filename)
{
- rb_check_safe_obj(filename);
-
if (RAND_write_file(StringValueCStr(filename)) == -1) {
ossl_raise(eRandomError, NULL);
}
@@ -164,8 +160,6 @@ ossl_rand_pseudo_bytes(VALUE self, VALUE len)
static VALUE
ossl_rand_egd(VALUE self, VALUE filename)
{
- rb_check_safe_obj(filename);
-
if (RAND_egd(StringValueCStr(filename)) == -1) {
ossl_raise(eRandomError, NULL);
}
@@ -186,8 +180,6 @@ ossl_rand_egd_bytes(VALUE self, VALUE filename, VALUE len)
{
int n = NUM2INT(len);
- rb_check_safe_obj(filename);
-
if (RAND_egd_bytes(StringValueCStr(filename), n) == -1) {
ossl_raise(eRandomError, NULL);
}
diff --git a/ext/openssl/ossl_x509store.c b/ext/openssl/ossl_x509store.c
index 2909eed..61543d4 100644
--- a/ext/openssl/ossl_x509store.c
+++ b/ext/openssl/ossl_x509store.c
@@ -304,7 +304,6 @@ ossl_x509store_add_file(VALUE self, VALUE file)
char *path = NULL;
if(file != Qnil){
- rb_check_safe_obj(file);
path = StringValueCStr(file);
}
GetX509Store(self, store);
@@ -340,7 +339,6 @@ ossl_x509store_add_path(VALUE self, VALUE dir)
char *path = NULL;
if(dir != Qnil){
- rb_check_safe_obj(dir);
path = StringValueCStr(dir);
}
GetX509Store(self, store);
diff --git a/ext/readline/readline.c b/ext/readline/readline.c
index b686f99..646be2b 100644
--- a/ext/readline/readline.c
+++ b/ext/readline/readline.c
@@ -95,7 +95,6 @@ static char **readline_attempted_completion_function(const char *text,
#define OutputStringValue(str) do {\
StringValueCStr(str);\
- rb_check_safe_obj(str);\
(str) = rb_str_conv_enc((str), rb_enc_get(str), rb_locale_encoding());\
} while (0)\
diff --git a/ext/socket/constants.c b/ext/socket/constants.c
index 6fc8627..1bbb53b 100644
--- a/ext/socket/constants.c
+++ b/ext/socket/constants.c
@@ -28,7 +28,6 @@ constant_arg(VALUE arg, int (*str_to_int)(const char*, long, int*), const char *
else if (!NIL_P(tmp = rb_check_string_type(arg))) {
arg = tmp;
str:
- rb_check_safe_obj(arg);
ptr = RSTRING_PTR(arg);
if (str_to_int(ptr, RSTRING_LEN(arg), &ret) == -1)
rb_raise(rb_eSocket, "%s: %s", errmsg, ptr);
diff --git a/ext/socket/raddrinfo.c b/ext/socket/raddrinfo.c
index 0499b84..cc29674 100644
--- a/ext/socket/raddrinfo.c
+++ b/ext/socket/raddrinfo.c
@@ -503,10 +503,6 @@ str_is_number(const char *p)
#define str_equal(ptr, len, name) \
((ptr)[0] == name[0] && \
rb_strlen_lit(name) == (len) && memcmp(ptr, name, len) == 0)
-#define SafeStringValueCStr(v) do {\
- StringValueCStr(v);\
- rb_check_safe_obj(v);\
-} while(0)
static char*
host_str(VALUE host, char *hbuf, size_t hbuflen, int *flags_ptr)
@@ -525,7 +521,7 @@ host_str(VALUE host, char *hbuf, size_t hbuflen, int *flags_ptr)
const char *name;
size_t len;
- SafeStringValueCStr(host);
+ StringValueCStr(host);
RSTRING_GETMEM(host, name, len);
if (!len || str_equal(name, len, "<any>")) {
make_inetaddr(INADDR_ANY, hbuf, hbuflen);
@@ -564,7 +560,7 @@ port_str(VALUE port, char *pbuf, size_t pbuflen, int *flags_ptr)
const char *serv;
size_t len;
- SafeStringValueCStr(port);
+ StringValueCStr(port);
RSTRING_GETMEM(port, serv, len);
if (len >= pbuflen) {
rb_raise(rb_eArgError, "service name too long (%"PRIuSIZE")",
diff --git a/ext/socket/unixsocket.c b/ext/socket/unixsocket.c
index 8bdfc84..0c3a01d 100644
--- a/ext/socket/unixsocket.c
+++ b/ext/socket/unixsocket.c
@@ -39,7 +39,6 @@ unixsock_path_value(VALUE path)
#endif
if (isstr) {
if (RSTRING_LEN(name) == 0 || RSTRING_PTR(name)[0] == '\0') {
- rb_check_safe_obj(name);
return name; /* ignore encoding */
}
}
diff --git a/ext/syslog/syslog.c b/ext/syslog/syslog.c
index 23dcf6c..4c540fc 100644
--- a/ext/syslog/syslog.c
+++ b/ext/syslog/syslog.c
@@ -162,7 +162,6 @@ static VALUE mSyslog_open(int argc, VALUE *argv, VALUE self)
ident = rb_gv_get("$0");
}
ident_ptr = StringValueCStr(ident);
- rb_check_safe_obj(ident);
syslog_ident = strdup(ident_ptr);
if (NIL_P(opt)) {
diff --git a/ext/win32ole/win32ole.c b/ext/win32ole/win32ole.c
index c46d393..f20bfc8 100644
--- a/ext/win32ole/win32ole.c
+++ b/ext/win32ole/win32ole.c
@@ -1985,10 +1985,6 @@ fole_s_connect(int argc, VALUE *argv, VALUE self)
rb_scan_args(argc, argv, "1*", &svr_name, &others);
StringValue(svr_name);
- if (rb_safe_level() > 0 && OBJ_TAINTED(svr_name)) {
- rb_raise(rb_eSecurityError, "insecure connection - `%s'",
- StringValuePtr(svr_name));
- }
/* get CLSID from OLE server name */
pBuf = ole_vstr2wc(svr_name);
@@ -2478,16 +2474,8 @@ fole_initialize(int argc, VALUE *argv, VALUE self)
rb_scan_args(argc, argv, "11*:", &svr_name, &host, &others, &opts);
StringValue(svr_name);
- if (rb_safe_level() > 0 && OBJ_TAINTED(svr_name)) {
- rb_raise(rb_eSecurityError, "insecure object creation - `%s'",
- StringValuePtr(svr_name));
- }
if (!NIL_P(host)) {
StringValue(host);
- if (rb_safe_level() > 0 && OBJ_TAINTED(host)) {
- rb_raise(rb_eSecurityError, "insecure object creation - `%s'",
- StringValuePtr(host));
- }
return ole_create_dcom(self, svr_name, host, others);
}
diff --git a/ext/win32ole/win32ole_event.c b/ext/win32ole/win32ole_event.c
index ddb5200..041639a 100644
--- a/ext/win32ole/win32ole_event.c
+++ b/ext/win32ole/win32ole_event.c
@@ -922,10 +922,6 @@ ev_advise(int argc, VALUE *argv, VALUE self)
if(!RB_TYPE_P(itf, T_NIL)) {
pitf = StringValuePtr(itf);
- if (rb_safe_level() > 0 && OBJ_TAINTED(itf)) {
- rb_raise(rb_eSecurityError, "insecure event creation - `%s'",
- StringValuePtr(itf));
- }
hr = find_iid(ole, pitf, &iid, &pTypeInfo);
}
else {
diff --git a/file.c b/file.c
index 17881c0..67ef2d0 100644
--- a/file.c
+++ b/file.c
@@ -195,15 +195,11 @@ check_path_encoding(VALUE str)
}
VALUE
-rb_get_path_check_to_string(VALUE obj, int level)
+rb_get_path_check_to_string(VALUE obj)
{
VALUE tmp;
ID to_path;
- if (insecure_obj_p(obj, level)) {
- rb_insecure_operation();
- }
-
if (RB_TYPE_P(obj, T_STRING)) {
return obj;
}
@@ -214,38 +210,28 @@ rb_get_path_check_to_string(VALUE obj, int level)
}
VALUE
-rb_get_path_check_convert(VALUE obj, VALUE tmp, int level)
+rb_get_path_check_convert(VALUE obj)
{
- tmp = file_path_convert(tmp);
- if (obj != tmp && insecure_obj_p(tmp, level)) {
- rb_insecure_operation();
- }
+ obj = file_path_convert(obj);
- check_path_encoding(tmp);
- if (!rb_str_to_cstr(tmp)) {
+ check_path_encoding(obj);
+ if (!rb_str_to_cstr(obj)) {
rb_raise(rb_eArgError, "path name contains null byte");
}
- return rb_str_new4(tmp);
-}
-
-VALUE
-rb_get_path_check(VALUE obj, int level)
-{
- VALUE tmp = rb_get_path_check_to_string(obj, level);
- return rb_get_path_check_convert(obj, tmp, level);
+ return rb_str_new4(obj);
}
VALUE
rb_get_path_no_checksafe(VALUE obj)
{
- return rb_get_path_check(obj, 0);
+ return rb_get_path(obj);
}
VALUE
rb_get_path(VALUE obj)
{
- return rb_get_path_check(obj, rb_safe_level());
+ return rb_get_path_check_convert(rb_get_path_check_to_string(obj));
}
VALUE
@@ -6290,13 +6276,14 @@ copy_path_class(VALUE path, VALUE orig)
}
int
-rb_find_file_ext(VALUE *filep, const char *const *ext)
+rb_find_file_ext_safe(VALUE *filep, const char *const *ext, int _level)
{
- return rb_find_file_ext_safe(filep, ext, rb_safe_level());
+ rb_warn("rb_find_file_ext_safe will be removed in Ruby 3.0");
+ return rb_find_file_ext(filep, ext);
}
int
-rb_find_file_ext_safe(VALUE *filep, const char *const *ext, int safe_level)
+rb_find_file_ext(VALUE *filep, const char *const *ext)
{
const char *f = StringValueCStr(*filep);
VALUE fname = *filep, load_path, tmp;
@@ -6307,18 +6294,12 @@ rb_find_file_ext_safe(VALUE *filep, const char *const *ext, int safe_level)
if (f[0] == '~') {
fname = file_expand_path_1(fname);
- if (safe_level >= 1 && OBJ_TAINTED(fname)) {
- rb_raise(rb_eSecurityError, "loading from unsafe file %s", f);
- }
f = RSTRING_PTR(fname);
*filep = fname;
expanded = 1;
}
if (expanded || rb_is_absolute_path(f) || is_explicit_relative(f)) {
- if (safe_level >= 1 && !fpath_check(fname)) {
- rb_raise(rb_eSecurityError, "loading from unsafe path %s", f);
- }
if (!expanded) fname = file_expand_path_1(fname);
fnlen = RSTRING_LEN(fname);
for (i=0; ext[i]; i++) {
@@ -6345,7 +6326,7 @@ rb_find_file_ext_safe(VALUE *filep, const char *const *ext, int safe_level)
for (i = 0; i < RARRAY_LEN(load_path); i++) {
VALUE str = RARRAY_AREF(load_path, i);
- RB_GC_GUARD(str) = rb_get_path_check(str, safe_level);
+ RB_GC_GUARD(str) = rb_get_path(str);
if (RSTRING_LEN(str) == 0) continue;
rb_file_expand_path_internal(fname, str, 0, 0, tmp);
if (rb_file_load_ok(RSTRING_PTR(tmp))) {
@@ -6362,13 +6343,14 @@ rb_find_file_ext_safe(VALUE *filep, const char *const *ext, int safe_level)
}
VALUE
-rb_find_file(VALUE path)
+rb_find_file_safe(VALUE path, int _level)
{
- return rb_find_file_safe(path, rb_safe_level());
+ rb_warn("rb_find_file_safe will be removed in Ruby 3.0");
+ return rb_find_file(path);
}
VALUE
-rb_find_file_safe(VALUE path, int safe_level)
+rb_find_file(VALUE path)
{
VALUE tmp, load_path;
const char *f = StringValueCStr(path);
@@ -6376,18 +6358,12 @@ rb_find_file_safe(VALUE path, int safe_level)
if (f[0] == '~') {
tmp = file_expand_path_1(path);
- if (safe_level >= 1 && OBJ_TAINTED(tmp)) {
- rb_raise(rb_eSecurityError, "loading from unsafe file %"PRIsVALUE, tmp);
- }
path = copy_path_class(tmp, path);
f = RSTRING_PTR(path);
expanded = 1;
}
if (expanded || rb_is_absolute_path(f) || is_explicit_relative(f)) {
- if (safe_level >= 1 && !fpath_check(path)) {
- rb_raise(rb_eSecurityError, "loading from unsafe path %"PRIsVALUE, path);
- }
if (!rb_file_load_ok(f)) return 0;
if (!expanded)
path = copy_path_class(file_expand_path_1(path), path);
@@ -6402,7 +6378,7 @@ rb_find_file_safe(VALUE path, int safe_level)
rb_enc_associate_index(tmp, rb_usascii_encindex());
for (i = 0; i < RARRAY_LEN(load_path); i++) {
VALUE str = RARRAY_AREF(load_path, i);
- RB_GC_GUARD(str) = rb_get_path_check(str, safe_level);
+ RB_GC_GUARD(str) = rb_get_path(str);
if (RSTRING_LEN(str) > 0) {
rb_file_expand_path_internal(path, str, 0, 0, tmp);
f = RSTRING_PTR(tmp);
@@ -6417,10 +6393,6 @@ rb_find_file_safe(VALUE path, int safe_level)
}
found:
- if (safe_level >= 1 && !fpath_check(tmp)) {
- rb_raise(rb_eSecurityError, "loading from unsafe file %"PRIsVALUE, tmp);
- }
-
return copy_path_class(tmp, path);
}
diff --git a/gc.c b/gc.c
index 2ef9569..7f541e9 100644
--- a/gc.c
+++ b/gc.c
@@ -3232,7 +3232,7 @@ define_final0(VALUE obj, VALUE block)
RBASIC(obj)->flags |= FL_FINALIZE;
- block = rb_ary_new3(2, INT2FIX(rb_safe_level()), block);
+ block = rb_ary_new3(2, INT2FIX(0), block);
OBJ_FREEZE(block);
if (st_lookup(finalizer_table, obj, &data)) {
@@ -3291,7 +3291,6 @@ run_single_final(VALUE final, VALUE objid)
const int level = OBJ_TAINTED(cmd) ?
RUBY_SAFE_LEVEL_MAX : FIX2INT(RARRAY_AREF(final, 0));
- rb_set_safe_level_force(level);
return rb_check_funcall(cmd, idCall, 1, &objid);
}
@@ -3305,15 +3304,12 @@ run_finalizer(rb_objspace_t *objspace, VALUE obj, VALUE table)
VALUE objid;
rb_control_frame_t *cfp;
long finished;
- int safe;
} saved;
rb_execution_context_t * volatile ec = GET_EC();
#define RESTORE_FINALIZER() (\
ec->cfp = saved.cfp, \
- rb_set_safe_level_force(saved.safe), \
rb_set_errinfo(saved.errinfo))
- saved.safe = rb_safe_level();
saved.errinfo = rb_errinfo();
saved.objid = rb_obj_id(obj);
saved.cfp = ec->cfp;
@@ -9389,10 +9385,8 @@ gc_set_initial_pages(void)
*/
void
-ruby_gc_set_params(int safe_level)
+ruby_gc_set_params(void)
{
- if (safe_level > 0) return;
-
/* RUBY_GC_HEAP_FREE_SLOTS */
if (get_envparam_size("RUBY_GC_HEAP_FREE_SLOTS", &gc_params.heap_free_slots, 0)) {
/* ok */
diff --git a/hash.c b/hash.c
index 77c83d9..b0746cb 100644
--- a/hash.c
+++ b/hash.c
@@ -5719,7 +5719,6 @@ env_has_value(VALUE dmy, VALUE obj)
obj = rb_check_string_type(obj);
if (NIL_P(obj)) return Qnil;
- rb_check_safe_obj(obj);
env = GET_ENVIRON(environ);
while (*env) {
char *s = strchr(*env, '=');
@@ -5750,7 +5749,6 @@ env_rassoc(VALUE dmy, VALUE obj)
obj = rb_check_string_type(obj);
if (NIL_P(obj)) return Qnil;
- rb_check_safe_obj(obj);
env = GET_ENVIRON(environ);
while (*env) {
char *s = strchr(*env, '=');
diff --git a/include/ruby/intern.h b/include/ruby/intern.h
index e53b4e6..e20aa31 100644
--- a/include/ruby/intern.h
+++ b/include/ruby/intern.h
@@ -459,7 +459,8 @@ int rb_provided(const char*);
int rb_feature_provided(const char *, const char **);
void rb_provide(const char*);
VALUE rb_f_require(VALUE, VALUE);
-VALUE rb_require_safe(VALUE, int);
+VALUE rb_require_safe(VALUE, int); /* Remove in 3.0 */
+VALUE rb_require_string(VALUE);
void rb_obj_call_init(VALUE, int, const VALUE*);
void rb_obj_call_init_kw(VALUE, int, const VALUE*, int);
VALUE rb_class_new_instance(int, const VALUE*, VALUE);
@@ -519,8 +520,8 @@ VALUE rb_file_expand_path(VALUE, VALUE);
VALUE rb_file_s_absolute_path(int, const VALUE *);
VALUE rb_file_absolute_path(VALUE, VALUE);
VALUE rb_file_dirname(VALUE fname);
-int rb_find_file_ext_safe(VALUE*, const char* const*, int);
-VALUE rb_find_file_safe(VALUE, int);
+int rb_find_file_ext_safe(VALUE*, const char* const*, int); /* Remove in 3.0 */
+VALUE rb_find_file_safe(VALUE, int); /* Remove in 3.0 */
int rb_find_file_ext(VALUE*, const char* const*);
VALUE rb_find_file(VALUE);
VALUE rb_file_directory_p(VALUE,VALUE);
diff --git a/include/ruby/ruby.h b/include/ruby/ruby.h
index 2f9855e..8a5aacb 100644
--- a/include/ruby/ruby.h
+++ b/include/ruby/ruby.h
@@ -604,21 +604,18 @@ char *rb_string_value_cstr(volatile VALUE*);
#define StringValueCStr(v) rb_string_value_cstr(&(v))
void rb_check_safe_obj(VALUE);
-#define SafeStringValue(v) do {\
- StringValue(v);\
- rb_check_safe_obj(v);\
-} while (0)
+#define SafeStringValue(v) StringValue(v)
#if GCC_VERSION_SINCE(4,4,0)
-void rb_check_safe_str(VALUE) __attribute__((error("rb_check_safe_str() and Check_SafeStr() are obsolete; use SafeStringValue() instead")));
+void rb_check_safe_str(VALUE) __attribute__((error("rb_check_safe_str() and Check_SafeStr() are obsolete; use StringValue() instead")));
# define Check_SafeStr(v) rb_check_safe_str((VALUE)(v))
#else
-# define rb_check_safe_str(x) [<"rb_check_safe_str() is obsolete; use SafeStringValue() instead">]
-# define Check_SafeStr(v) [<"Check_SafeStr() is obsolete; use SafeStringValue() instead">]
+# define rb_check_safe_str(x) [<"rb_check_safe_str() is obsolete; use StringValue() instead">]
+# define Check_SafeStr(v) [<"Check_SafeStr() is obsolete; use StringValue() instead">]
#endif
VALUE rb_str_export(VALUE);
#define ExportStringValue(v) do {\
- SafeStringValue(v);\
+ StringValue(v);\
(v) = rb_str_export(v);\
} while (0)
VALUE rb_str_export_locale(VALUE);
@@ -627,8 +624,9 @@ VALUE rb_get_path(VALUE);
#define FilePathValue(v) (RB_GC_GUARD(v) = rb_get_path(v))
VALUE rb_get_path_no_checksafe(VALUE);
-#define FilePathStringValue(v) ((v) = rb_get_path_no_checksafe(v))
+#define FilePathStringValue(v) ((v) = rb_get_path(v))
+/* Remove in 3.0 */
#define RUBY_SAFE_LEVEL_MAX 1
void rb_secure(int);
int rb_safe_level(void);
diff --git a/internal.h b/internal.h
index ec8725a..3cfb5a4 100644
--- a/internal.h
+++ b/internal.h
@@ -1570,9 +1570,8 @@ void rb_file_const(const char*, VALUE);
int rb_file_load_ok(const char *);
VALUE rb_file_expand_path_fast(VALUE, VALUE);
VALUE rb_file_expand_path_internal(VALUE, VALUE, int, int, VALUE);
-VALUE rb_get_path_check_to_string(VALUE, int);
-VALUE rb_get_path_check_convert(VALUE, VALUE, int);
-VALUE rb_get_path_check(VALUE, int);
+VALUE rb_get_path_check_to_string(VALUE);
+VALUE rb_get_path_check_convert(VALUE);
void Init_File(void);
int ruby_is_fd_loadable(int fd);
@@ -1604,7 +1603,7 @@ void rb_gc_writebarrier_remember(VALUE obj);
#else
#define rb_gc_writebarrier_remember(obj) 0
#endif
-void ruby_gc_set_params(int safe_level);
+void ruby_gc_set_params(void);
void rb_copy_wb_protected_attribute(VALUE dest, VALUE obj);
#if defined(HAVE_MALLOC_USABLE_SIZE) || defined(HAVE_MALLOC_SIZE) || defined(_WIN32)
@@ -1696,7 +1695,7 @@ void rb_io_fptr_finalize_internal(void *ptr);
/* load.c */
VALUE rb_get_expanded_load_path(void);
-int rb_require_internal(VALUE fname, int safe);
+int rb_require_internal(VALUE fname);
NORETURN(void rb_load_fail(VALUE, const char*));
/* loadpath.c */
diff --git a/io.c b/io.c
index f4dc499..47d37d1 100644
--- a/io.c
+++ b/io.c
@@ -12839,9 +12839,6 @@ opt_i_get(ID id, VALUE *var)
static VALUE
argf_inplace_mode_set(VALUE argf, VALUE val)
{
- if (rb_safe_level() >= 1 && OBJ_TAINTED(val))
- rb_insecure_operation();
-
if (!RTEST(val)) {
ARGF.inplace = Qfalse;
}
diff --git a/iseq.c b/iseq.c
index c2f2412..cb179d1 100644
--- a/iseq.c
+++ b/iseq.c
@@ -1175,8 +1175,6 @@ iseqw_s_compile(int argc, VALUE *argv, VALUE self)
VALUE src, file = Qnil, path = Qnil, line = INT2FIX(1), opt = Qnil;
int i;
- rb_secure(1);
-
i = rb_scan_args(argc, argv, "1*:", &src, NULL, &opt);
if (i > 4+NIL_P(opt)) rb_error_arity(argc, 1, 5);
switch (i) {
@@ -1225,7 +1223,6 @@ iseqw_s_compile_file(int argc, VALUE *argv, VALUE self)
rb_compile_option_t option;
int i;
- rb_secure(1);
i = rb_scan_args(argc, argv, "1*:", &file, NULL, &opt);
if (i > 1+NIL_P(opt)) rb_error_arity(argc, 1, 2);
switch (i) {
@@ -1292,7 +1289,6 @@ static VALUE
iseqw_s_compile_option_set(VALUE self, VALUE opt)
{
rb_compile_option_t option;
- rb_secure(1);
make_compile_option(&option, opt);
COMPILE_OPTION_DEFAULT = option;
return opt;
@@ -1344,7 +1340,6 @@ rb_iseqw_to_iseq(VALUE iseqw)
static VALUE
iseqw_eval(VALUE self)
{
- rb_secure(1);
return rb_iseq_eval(iseqw_check(self));
}
@@ -1579,7 +1574,6 @@ static VALUE
iseqw_to_a(VALUE self)
{
const rb_iseq_t *iseq = iseqw_check(self);
- rb_secure(1);
return iseq_data_to_ary(iseq);
}
@@ -2134,8 +2128,6 @@ rb_iseq_disasm_recursive(const rb_iseq_t *iseq, VALUE indent)
const char *indent_str;
long indent_len;
- rb_secure(1);
-
size = body->iseq_size;
indent_len = RSTRING_LEN(indent);
@@ -2438,8 +2430,6 @@ iseqw_s_of(VALUE klass, VALUE body)
{
const rb_iseq_t *iseq = NULL;
- rb_secure(1);
-
if (rb_obj_is_proc(body)) {
iseq = vm_proc_iseq(body);
diff --git a/lib/debug.rb b/lib/debug.rb
index 34d7d27..ce8b7d7 100644
--- a/lib/debug.rb
+++ b/lib/debug.rb
@@ -5,11 +5,6 @@
require 'continuation'
-if $SAFE > 0
- STDERR.print "-r debug.rb is not available in safe mode\n"
- exit 1
-end
-
require 'tracer'
require 'pp'
diff --git a/lib/drb/drb.rb b/lib/drb/drb.rb
index 5c7f66a..0063e20 100644
--- a/lib/drb/drb.rb
+++ b/lib/drb/drb.rb
@@ -160,8 +160,6 @@ require_relative 'eq'
# # The object that handles requests on the server
# FRONT_OBJECT=TimeServer.new
#
-# $SAFE = 1 # disable eval() and friends
-#
# DRb.start_service(URI, FRONT_OBJECT)
# # Wait for the drb server thread to finish before exiting.
# DRb.thread.join
@@ -245,8 +243,6 @@ require_relative 'eq'
#
# FRONT_OBJECT=LoggerFactory.new("/tmp/dlog")
#
-# $SAFE = 1 # disable eval() and friends
-#
# DRb.start_service(URI, FRONT_OBJECT)
# DRb.thread.join
#
@@ -286,10 +282,7 @@ require_relative 'eq'
# ro.instance_eval("`rm -rf *`")
#
# The dangers posed by instance_eval and friends are such that a
-# DRbServer should generally be run with $SAFE set to at least
-# level 1. This will disable eval() and related calls on strings
-# passed across the wire. The sample usage code given above follows
-# this practice.
+# DRbServer should only be used when clients are trusted.
#
# A DRbServer can be configured with an access control list to
# selectively allow or deny access from specified IP addresses. The
@@ -1362,7 +1355,6 @@ module DRb
@@argc_limit = 256
@@load_limit = 0xffffffff
@@verbose = false
- @@safe_level = 0
# Set the default value for the :argc_limit option.
#
@@ -1392,11 +1384,8 @@ module DRb
@@idconv = idconv
end
- # Set the default safe level to +level+. The default safe level is 0
- #
- # See #new for more information.
- def self.default_safe_level(level)
- @@safe_level = level
+ def self.default_safe_level(level) # :nodoc:
+ # Remove in Ruby 3.0
end
# Set the default value of the :verbose option.
@@ -1418,7 +1407,6 @@ module DRb
:tcp_acl => @@acl,
:load_limit => @@load_limit,
:argc_limit => @@argc_limit,
- :safe_level => @@safe_level
}
default_config.update(hash)
end
@@ -1452,10 +1440,6 @@ module DRb
# :argc_limit :: the maximum number of arguments to a remote
# method accepted by the server. Defaults to
# 256.
- # :safe_level :: The safe level of the DRbServer. The attribute
- # sets $SAFE for methods performed in the main_loop.
- # Defaults to 0.
- #
# The default values of these options can be modified on
# a class-wide basis by the class methods #default_argc_limit,
# #default_load_limit, #default_acl, #default_id_conv,
@@ -1487,7 +1471,6 @@ module DRb
@front = front
@idconv = @config[:idconv]
- @safe_level = @config[:safe_level]
@grp = ThreadGroup.new
@thread = run
@@ -1514,11 +1497,10 @@ module DRb
# The configuration of this DRbServer
attr_reader :config
- # The safe level for this server. This is a number corresponding to
- # $SAFE.
- #
- # The default safe_level is 0
- attr_reader :safe_level
+ def safe_level # :nodoc:
+ # Remove in Ruby 3.0
+ 0
+ end
# Set whether to operate in verbose mode.
#
@@ -1652,7 +1634,6 @@ module DRb
class InvokeMethod # :nodoc:
def initialize(drb_server, client)
@drb_server = drb_server
- @safe_level = drb_server.safe_level
@client = client
end
@@ -1661,33 +1642,10 @@ module DRb
@succ = false
setup_message
- if $SAFE < @safe_level
- info = Thread.current['DRb']
- if @block
- @result = Thread.new do
- Thread.current['DRb'] = info
- prev_safe_level = $SAFE
- $SAFE = @safe_level
- perform_with_block
- ensure
- $SAFE = prev_safe_level
- end.value
- else
- @result = Thread.new do
- Thread.current['DRb'] = info
- prev_safe_level = $SAFE
- $SAFE = @safe_level
- perform_without_block
- ensure
- $SAFE = prev_safe_level
- end.value
- end
+ if @block
+ @result = perform_with_block
else
- if @block
- @result = perform_with_block
- else
- @result = perform_without_block
- end
+ @result = perform_without_block
end
@succ = true
case @result
diff --git a/lib/erb.rb b/lib/erb.rb
index 3f26c2f..d2ea64a 100644
--- a/lib/erb.rb
+++ b/lib/erb.rb
@@ -57,7 +57,6 @@ require "cgi/util"
#
# There are several settings you can change when you use ERB:
# * the nature of the tags that are recognized;
-# * the value of <tt>$SAFE</tt> under which the template is run;
# * the binding used to resolve local variables in the template.
#
# See the ERB.new and ERB#result methods for more detail.
@@ -747,9 +746,7 @@ class ERB
# Constructs a new ERB object with the template specified in _str_.
#
# An ERB object works by building a chunk of Ruby code that will output
- # the completed template when run. If _safe_level_ is set to a non-nil value,
- # ERB code will be run in a separate thread with <b>$SAFE</b> set to the
- # provided level.
+ # the completed template when run.
#
# If _trim_mode_ is passed a String containing one or more of the following
# modifiers, ERB will adjust its code generation as listed:
@@ -813,8 +810,6 @@ class ERB
# Complex initializer for $SAFE deprecation at [Feature #14256]. Use keyword arguments to pass trim_mode or eoutvar.
if safe_level != NOT_GIVEN
warn 'Passing safe_level with the 2nd argument of ERB.new is deprecated. Do not use it, and specify other arguments as keyword arguments.', uplevel: 1 if $VERBOSE || !ZERO_SAFE_LEVELS.include?(safe_level)
- else
- safe_level = nil
end
if legacy_trim_mode != NOT_GIVEN
warn 'Passing trim_mode with the 3rd argument of ERB.new is deprecated. Use keyword argument like ERB.new(str, trim_mode: ...) instead.', uplevel: 1 if $VERBOSE
@@ -825,7 +820,6 @@ class ERB
eoutvar = legacy_eoutvar
end
- @safe_level = safe_level
compiler = make_compiler(trim_mode)
set_eoutvar(compiler, eoutvar)
@src, @encoding, @frozen_string = *compiler.compile(str)
@@ -908,17 +902,7 @@ class ERB
unless @_init.equal?(self.class.singleton_class)
raise ArgumentError, "not initialized"
end
- if @safe_level
- proc do
- prev_safe_level = $SAFE
- $SAFE = @safe_level
- eval(@src, b, (@filename || '(erb)'), @lineno)
- ensure
- $SAFE = prev_safe_level
- end.call
- else
- eval(@src, b, (@filename || '(erb)'), @lineno)
- end
+ eval(@src, b, (@filename || '(erb)'), @lineno)
end
# Render a template on a new toplevel binding with local variables specified
diff --git a/lib/net/smtp.rb b/lib/net/smtp.rb
index 8e10dc2..460ad08 100644
--- a/lib/net/smtp.rb
+++ b/lib/net/smtp.rb
@@ -831,9 +831,6 @@ module Net
end
def mailfrom(from_addr)
- if $SAFE > 0
- raise SecurityError, 'tainted from_addr' if from_addr.tainted?
- end
getok("MAIL FROM:<#{from_addr}>")
end
@@ -859,9 +856,6 @@ module Net
end
def rcptto(to_addr)
- if $SAFE > 0
- raise SecurityError, 'tainted to_addr' if to_addr.tainted?
- end
getok("RCPT TO:<#{to_addr}>")
end
diff --git a/lib/tempfile.rb b/lib/tempfile.rb
index f7caf65..efb0b1b 100644
--- a/lib/tempfile.rb
+++ b/lib/tempfile.rb
@@ -98,10 +98,6 @@ class Tempfile < DelegateClass(File)
#
# The temporary file will be placed in the directory as specified
# by the +tmpdir+ parameter. By default, this is +Dir.tmpdir+.
- # When $SAFE > 0 and the given +tmpdir+ is tainted, it uses
- # '/tmp' as the temporary directory. Please note that ENV values
- # are tainted by default, and +Dir.tmpdir+'s return value might
- # come from environment variables (e.g. <tt>$TMPDIR</tt>).
#
# file = Tempfile.new('hello', '/home/aisaka')
# file.path # => something like: "/home/aisaka/hello2843-8392-92849382--0"
diff --git a/lib/tmpdir.rb b/lib/tmpdir.rb
index d7a8f79..ea1d380 100644
--- a/lib/tmpdir.rb
+++ b/lib/tmpdir.rb
@@ -19,22 +19,18 @@ class Dir
# Returns the operating system's temporary file path.
def self.tmpdir
- if $SAFE > 0
- @@systmpdir.dup
- else
- tmp = nil
- [ENV['TMPDIR'], ENV['TMP'], ENV['TEMP'], @@systmpdir, '/tmp', '.'].each do |dir|
- next if !dir
- dir = File.expand_path(dir)
- if stat = File.stat(dir) and stat.directory? and stat.writable? and
- (!stat.world_writable? or stat.sticky?)
- tmp = dir
- break
- end rescue nil
- end
- raise ArgumentError, "could not find a temporary directory" unless tmp
- tmp
+ tmp = nil
+ [ENV['TMPDIR'], ENV['TMP'], ENV['TEMP'], @@systmpdir, '/tmp', '.'].each do |dir|
+ next if !dir
+ dir = File.expand_path(dir)
+ if stat = File.stat(dir) and stat.directory? and stat.writable? and
+ (!stat.world_writable? or stat.sticky?)
+ tmp = dir
+ break
+ end rescue nil
end
+ raise ArgumentError, "could not find a temporary directory" unless tmp
+ tmp
end
# Dir.mktmpdir creates a temporary directory.
@@ -115,12 +111,8 @@ class Dir
UNUSABLE_CHARS = [File::SEPARATOR, File::ALT_SEPARATOR, File::PATH_SEPARATOR, ":"].uniq.join("").freeze
def create(basename, tmpdir=nil, max_try: nil, **opts)
- if $SAFE > 0 and tmpdir.tainted?
- tmpdir = '/tmp'
- else
- origdir = tmpdir
- tmpdir ||= tmpdir()
- end
+ origdir = tmpdir
+ tmpdir ||= tmpdir()
n = nil
prefix, suffix = basename
prefix = (String.try_convert(prefix) or
diff --git a/load.c b/load.c
index b95d228..5b27fd1 100644
--- a/load.c
+++ b/load.c
@@ -48,7 +48,6 @@ rb_construct_expanded_load_path(enum expand_type type, int *has_relative, int *h
VALUE expanded_load_path = vm->expanded_load_path;
VALUE ary;
long i;
- int level = rb_safe_level();
ary = rb_ary_tmp_new(RARRAY_LEN(load_path));
for (i = 0; i < RARRAY_LEN(load_path); ++i) {
@@ -58,7 +57,7 @@ rb_construct_expanded_load_path(enum expand_type type, int *has_relative, int *h
as_str = path = RARRAY_AREF(load_path, i);
is_string = RB_TYPE_P(path, T_STRING) ? 1 : 0;
non_cache = !is_string ? 1 : 0;
- as_str = rb_get_path_check_to_string(path, level);
+ as_str = rb_get_path_check_to_string(path);
as_cstr = RSTRING_PTR(as_str);
if (!non_cache) {
@@ -79,7 +78,7 @@ rb_construct_expanded_load_path(enum expand_type type, int *has_relative, int *h
/* Freeze only string object. We expand other objects every time. */
if (is_string)
rb_str_freeze(path);
- as_str = rb_get_path_check_convert(path, as_str, level);
+ as_str = rb_get_path_check_convert(as_str);
expanded_path = rb_check_realpath(Qnil, as_str);
if (NIL_P(expanded_path)) expanded_path = as_str;
rb_ary_push(ary, rb_fstring(expanded_path));
@@ -689,7 +688,7 @@ rb_f_load(int argc, VALUE *argv, VALUE _)
rb_scan_args(argc, argv, "11", &fname, &wrap);
- orig_fname = rb_get_path_check_to_string(fname, rb_safe_level());
+ orig_fname = rb_get_path_check_to_string(fname);
fname = rb_str_encode_ospath(orig_fname);
RUBY_DTRACE_HOOK(LOAD_ENTRY, RSTRING_PTR(orig_fname));
@@ -809,7 +808,7 @@ load_unlock(const char *ftptr, int done)
VALUE
rb_f_require(VALUE obj, VALUE fname)
{
- return rb_require_safe(fname, rb_safe_level());
+ return rb_require_string(fname);
}
/*
@@ -828,13 +827,13 @@ rb_f_require_relative(VALUE obj, VALUE fname)
rb_loaderror("cannot infer basepath");
}
base = rb_file_dirname(base);
- return rb_require_safe(rb_file_absolute_path(fname, base), rb_safe_level());
+ return rb_require_string(rb_file_absolute_path(fname, base));
}
typedef int (*feature_func)(const char *feature, const char *ext, int rb, int expanded, const char **fn);
static int
-search_required(VALUE fname, volatile VALUE *path, int safe_level, feature_func rb_feature_p)
+search_required(VALUE fname, volatile VALUE *path, feature_func rb_feature_p)
{
VALUE tmp;
char *ext, *ftptr;
@@ -849,7 +848,7 @@ search_required(VALUE fname, volatile VALUE *path, int safe_level, feature_func
if (loading) *path = rb_filesystem_str_new_cstr(loading);
return 'r';
}
- if ((tmp = rb_find_file_safe(fname, safe_level)) != 0) {
+ if ((tmp = rb_find_file(fname)) != 0) {
ext = strrchr(ftptr = RSTRING_PTR(tmp), '.');
if (!rb_feature_p(ftptr, ext, TRUE, TRUE, &loading) || loading)
*path = tmp;
@@ -865,7 +864,7 @@ search_required(VALUE fname, volatile VALUE *path, int safe_level, feature_func
tmp = rb_str_subseq(fname, 0, ext - RSTRING_PTR(fname));
#ifdef DLEXT2
OBJ_FREEZE(tmp);
- if (rb_find_file_ext_safe(&tmp, loadable_ext + 1, safe_level)) {
+ if (rb_find_file_ext(&tmp, loadable_ext + 1)) {
ext = strrchr(ftptr = RSTRING_PTR(tmp), '.');
if (!rb_feature_p(ftptr, ext, FALSE, TRUE, &loading) || loading)
*path = tmp;
@@ -874,7 +873,7 @@ search_required(VALUE fname, volatile VALUE *path, int safe_level, feature_func
#else
rb_str_cat2(tmp, DLEXT);
OBJ_FREEZE(tmp);
- if ((tmp = rb_find_file_safe(tmp, safe_level)) != 0) {
+ if ((tmp = rb_find_file(tmp)) != 0) {
ext = strrchr(ftptr = RSTRING_PTR(tmp), '.');
if (!rb_feature_p(ftptr, ext, FALSE, TRUE, &loading) || loading)
*path = tmp;
@@ -887,7 +886,7 @@ search_required(VALUE fname, volatile VALUE *path, int safe_level, feature_func
if (loading) *path = rb_filesystem_str_new_cstr(loading);
return 's';
}
- if ((tmp = rb_find_file_safe(fname, safe_level)) != 0) {
+ if ((tmp = rb_find_file(fname)) != 0) {
ext = strrchr(ftptr = RSTRING_PTR(tmp), '.');
if (!rb_feature_p(ftptr, ext, FALSE, TRUE, &loading) || loading)
*path = tmp;
@@ -900,7 +899,7 @@ search_required(VALUE fname, volatile VALUE *path, int safe_level, feature_func
return 'r';
}
tmp = fname;
- type = rb_find_file_ext_safe(&tmp, loadable_ext, safe_level);
+ type = rb_find_file_ext(&tmp, loadable_ext);
switch (type) {
case 0:
if (ft)
@@ -951,9 +950,9 @@ rb_resolve_feature_path(VALUE klass, VALUE fname)
int found;
VALUE sym;
- fname = rb_get_path_check(fname, 0);
+ fname = rb_get_path(fname);
path = rb_str_encode_ospath(fname);
- found = search_required(path, &path, 0, no_feature_p);
+ found = search_required(path, &path, no_feature_p);
switch (found) {
case 'r':
@@ -977,7 +976,7 @@ rb_resolve_feature_path(VALUE klass, VALUE fname)
* >1: exception
*/
static int
-require_internal(rb_execution_context_t *ec, VALUE fname, int safe, int exception)
+require_internal(rb_execution_context_t *ec, VALUE fname, int exception)
{
volatile int result = -1;
rb_thread_t *th = rb_ec_thread_ptr(ec);
@@ -985,28 +984,22 @@ require_internal(rb_execution_context_t *ec, VALUE fname, int safe, int exceptio
volatile VALUE self = th->top_self;
volatile VALUE errinfo = ec->errinfo;
enum ruby_tag_type state;
- struct {
- int safe;
- } volatile saved;
char *volatile ftptr = 0;
VALUE path;
- fname = rb_get_path_check(fname, safe);
+ fname = rb_get_path(fname);
path = rb_str_encode_ospath(fname);
RUBY_DTRACE_HOOK(REQUIRE_ENTRY, RSTRING_PTR(fname));
EC_PUSH_TAG(ec);
- saved.safe = rb_safe_level();
ec->errinfo = Qnil; /* ensure */
th->top_wrapper = 0;
if ((state = EC_EXEC_TAG()) == TAG_NONE) {
long handle;
int found;
- rb_set_safe_level_force(0);
-
RUBY_DTRACE_HOOK(FIND_REQUIRE_ENTRY, RSTRING_PTR(fname));
- found = search_required(path, &path, safe, rb_feature_p);
+ found = search_required(path, &path, rb_feature_p);
RUBY_DTRACE_HOOK(FIND_REQUIRE_RETURN, RSTRING_PTR(fname));
if (found) {
@@ -1040,7 +1033,6 @@ require_internal(rb_execution_context_t *ec, VALUE fname, int safe, int exceptio
th->top_wrapper = wrapper;
if (ftptr) load_unlock(RSTRING_PTR(path), !state);
- rb_set_safe_level_force(saved.safe);
if (state) {
if (exception) {
/* usually state == TAG_RAISE only, except for
@@ -1069,10 +1061,10 @@ require_internal(rb_execution_context_t *ec, VALUE fname, int safe, int exceptio
}
int
-rb_require_internal(VALUE fname, int safe)
+rb_require_internal(VALUE fname)
{
rb_execution_context_t *ec = GET_EC();
- return require_internal(ec, fname, safe, 1);
+ return require_internal(ec, fname, 1);
}
int
@@ -1081,7 +1073,7 @@ ruby_require_internal(const char *fname, unsigned int len)
struct RString fake;
VALUE str = rb_setup_fake_str(&fake, fname, len, 0);
rb_execution_context_t *ec = GET_EC();
- int result = require_internal(ec, str, 0, 0);
+ int result = require_internal(ec, str, 0);
rb_set_errinfo(Qnil);
return result == TAG_RETURN ? 1 : result ? -1 : 0;
}
@@ -1089,8 +1081,25 @@ ruby_require_internal(const char *fname, unsigned int len)
VALUE
rb_require_safe(VALUE fname, int safe)
{
+ rb_warn("rb_require_safe will be removed in Ruby 3.0");
+ rb_execution_context_t *ec = GET_EC();
+ int result = require_internal(ec, fname, 1);
+
+ if (result > TAG_RETURN) {
+ EC_JUMP_TAG(ec, result);
+ }
+ if (result < 0) {
+ load_failed(fname);
+ }
+
+ return result ? Qtrue : Qfalse;
+}
+
+VALUE
+rb_require_string(VALUE fname)
+{
rb_execution_context_t *ec = GET_EC();
- int result = require_internal(ec, fname, safe, 1);
+ int result = require_internal(ec, fname, 1);
if (result > TAG_RETURN) {
EC_JUMP_TAG(ec, result);
@@ -1105,8 +1114,7 @@ rb_require_safe(VALUE fname, int safe)
VALUE
rb_require(const char *fname)
{
- VALUE fn = rb_str_new_cstr(fname);
- return rb_require_safe(fn, rb_safe_level());
+ return rb_require_string(rb_str_new_cstr(fname));
}
static int
diff --git a/parse.y b/parse.y
index 9eb7bed..9277897 100644
--- a/parse.y
+++ b/parse.y
@@ -5902,7 +5902,7 @@ yycompile0(VALUE arg)
struct parser_params *p = (struct parser_params *)arg;
VALUE cov = Qfalse;
- if (!compile_for_eval && rb_safe_level() == 0 && !NIL_P(p->ruby_sourcefile_string)) {
+ if (!compile_for_eval && !NIL_P(p->ruby_sourcefile_string)) {
p->debug_lines = debug_lines(p->ruby_sourcefile_string);
if (p->debug_lines && p->ruby_sourceline > 0) {
VALUE str = STR_NEW0();
diff --git a/proc.c b/proc.c
index 762f704..607ccc3 100644
--- a/proc.c
+++ b/proc.c
@@ -2275,27 +2275,6 @@ call_method_data(rb_execution_context_t *ec, const struct METHOD *data,
method_callable_method_entry(data), kw_splat);
}
-static VALUE
-call_method_data_safe(rb_execution_context_t *ec, const struct METHOD *data,
- int argc, const VALUE *argv, VALUE passed_procval,
- int safe, int kw_splat)
-{
- VALUE result = Qnil; /* OK */
- enum ruby_tag_type state;
-
- EC_PUSH_TAG(ec);
- if ((state = EC_EXEC_TAG()) == TAG_NONE) {
- /* result is used only if state == 0, no exceptions is caught. */
- /* otherwise it doesn't matter even if clobbered. */
- NO_CLOBBERED(result) = call_method_data(ec, data, argc, argv, passed_procval, kw_splat);
- }
- EC_POP_TAG();
- rb_set_safe_level_force(safe);
- if (state)
- EC_JUMP_TAG(ec, state);
- return result;
-}
-
VALUE
rb_method_call_with_block_kw(int argc, const VALUE *argv, VALUE method, VALUE passed_procval, int kw_splat)
{
@@ -2306,14 +2285,6 @@ rb_method_call_with_block_kw(int argc, const VALUE *argv, VALUE method, VALUE pa
if (data->recv == Qundef) {
rb_raise(rb_eTypeError, "can't call unbound method; bind first");
}
- if (OBJ_TAINTED(method)) {
- const int safe_level_to_run = RUBY_SAFE_LEVEL_MAX;
- int safe = rb_safe_level();
- if (safe < safe_level_to_run) {
- rb_set_safe_level_force(safe_level_to_run);
- return call_method_data_safe(ec, data, argc, argv, passed_procval, safe, kw_splat);
- }
- }
return call_method_data(ec, data, argc, argv, passed_procval, kw_splat);
}
diff --git a/process.c b/process.c
index 6fa3270..69d362b 100644
--- a/process.c
+++ b/process.c
@@ -1574,16 +1574,6 @@ after_fork_ruby(void)
#include "dln.h"
-static void
-security(const char *str)
-{
- if (rb_env_path_tainted()) {
- if (rb_safe_level() > 0) {
- rb_raise(rb_eSecurityError, "Insecure PATH - %s", str);
- }
- }
-}
-
#if defined(HAVE_WORKING_FORK)
/* try_with_sh and exec_with_sh should be async-signal-safe. Actually it is.*/
@@ -1759,7 +1749,6 @@ proc_spawn_cmd_internal(char **argv, char *prog)
if (!prog)
prog = argv[0];
- security(prog);
prog = dln_find_exe_r(prog, 0, fbuf, sizeof(fbuf));
if (!prog)
return -1;
@@ -2371,7 +2360,6 @@ rb_check_argv(int argc, VALUE *argv)
argv[i] = rb_str_new_frozen(argv[i]);
StringValueCStr(argv[i]);
}
- security(name ? name : RSTRING_PTR(argv[0]));
return prog;
}
diff --git a/ruby.c b/ruby.c
index 02d9028..8df0fcf 100644
--- a/ruby.c
+++ b/ruby.c
@@ -162,7 +162,6 @@ struct ruby_cmdline_options {
#if USE_MJIT
struct mjit_options mjit;
#endif
- int safe_level;
int sflag, xflag;
unsigned int warning: 1;
unsigned int verbose: 1;
@@ -264,7 +263,6 @@ usage(const char *name, int help)
M("-rlibrary", "", "require the library before executing your script"),
M("-s", "", "enable some switch parsing for switches after script name"),
M("-S", "", "look for the script using PATH environment variable"),
- M("-T[level=1]", "", "turn on tainting checks"),
M("-v", "", "print the version number, then turn on verbose mode"),
M("-w", "", "turn warnings on for your script"),
M("-W[level=2]", "", "set warning level; 0=silence, 1=medium, 2=verbose"),
@@ -490,13 +488,7 @@ str_conv_enc(VALUE str, rb_encoding *from, rb_encoding *to)
# define str_conv_enc(str, from, to) (str)
#endif
-void ruby_init_loadpath_safe(int safe_level);
-
-void
-ruby_init_loadpath(void)
-{
- ruby_init_loadpath_safe(0);
-}
+void ruby_init_loadpath(void);
#if defined(LOAD_RELATIVE)
static VALUE
@@ -576,7 +568,7 @@ runtime_libruby_path(void)
VALUE ruby_archlibdir_path, ruby_prefix_path;
void
-ruby_init_loadpath_safe(int safe_level)
+ruby_init_loadpath(void)
{
VALUE load_path, archlibdir = 0;
ID id_initial_load_path_mark;
@@ -659,9 +651,7 @@ ruby_init_loadpath_safe(int safe_level)
load_path = GET_VM()->load_path;
- if (safe_level == 0) {
- ruby_push_include(getenv("RUBYLIB"), identical_path);
- }
+ ruby_push_include(getenv("RUBYLIB"), identical_path);
id_initial_load_path_mark = INITIAL_LOAD_PATH_MARK;
while (*paths) {
@@ -1225,18 +1215,18 @@ proc_options(long argc, char **argv, ruby_cmdline_options_t *opt, int envopt)
goto reswitch;
case 'T':
- {
- size_t numlen;
- int v = 1;
-
- if (*++s) {
- v = scan_oct(s, 2, &numlen);
- if (numlen == 0)
- v = 1;
- s += numlen;
- }
- if (v > opt->safe_level) opt->safe_level = v;
- }
+ {
+ size_t numlen;
+ int v = 1;
+
+ if (*++s) {
+ v = scan_oct(s, 2, &numlen);
+ if (numlen == 0)
+ v = 1;
+ s += numlen;
+ }
+ }
+ rb_warn("ruby -T will be removed in Ruby 3.0");
goto reswitch;
case 'I':
@@ -1576,8 +1566,7 @@ process_options(int argc, char **argv, ruby_cmdline_options_t *opt)
argc -= i;
argv += i;
- if ((opt->features.set & FEATURE_BIT(rubyopt)) &&
- opt->safe_level == 0 && (s = getenv("RUBYOPT"))) {
+ if ((opt->features.set & FEATURE_BIT(rubyopt)) && (s = getenv("RUBYOPT"))) {
VALUE src_enc_name = opt->src.enc.name;
VALUE ext_enc_name = opt->ext.enc.name;
VALUE int_enc_name = opt->intern.enc.name;
@@ -1655,12 +1644,12 @@ process_options(int argc, char **argv, ruby_cmdline_options_t *opt)
translit_char(RSTRING_PTR(opt->script_name), '\\', '/');
#endif
- ruby_gc_set_params(opt->safe_level);
- ruby_init_loadpath_safe(opt->safe_level);
+ ruby_gc_set_params();
+ ruby_init_loadpath();
#if USE_MJIT
if (opt->mjit.on)
- /* Using TMP_RUBY_PREFIX created by ruby_init_loadpath_safe(). */
+ /* Using TMP_RUBY_PREFIX created by ruby_init_loadpath(). */
mjit_init(&opt->mjit);
#endif
@@ -1884,8 +1873,6 @@ process_options(int argc, char **argv, ruby_cmdline_options_t *opt)
rb_gc_register_mark_object(opt->e_script);
}
- rb_set_safe_level(opt->safe_level);
-
{
rb_execution_context_t *ec = GET_EC();
@@ -2282,9 +2269,6 @@ init_ids(ruby_cmdline_options_t *opt)
if (uid != euid) opt->setids |= 1;
if (egid != gid) opt->setids |= 2;
- if (uid && opt->setids) {
- if (opt->safe_level < 1) opt->safe_level = 1;
- }
}
#undef forbid_setid
@@ -2295,8 +2279,6 @@ forbid_setid(const char *s, const ruby_cmdline_options_t *opt)
rb_raise(rb_eSecurityError, "no %s allowed while running setuid", s);
if (opt->setids & 2)
rb_raise(rb_eSecurityError, "no %s allowed while running setgid", s);
- if (opt->safe_level > 0)
- rb_raise(rb_eSecurityError, "no %s allowed in tainted mode", s);
}
static void
diff --git a/safe.c b/safe.c
index 9c668e3..7f340ff 100644
--- a/safe.c
+++ b/safe.c
@@ -28,18 +28,21 @@
int
ruby_safe_level_2_warning(void)
{
+ rb_warn("rb_safe_level_2_warning will be removed in Ruby 3.0");
return 2;
}
int
rb_safe_level(void)
{
+ rb_warn("rb_safe_level will be removed in Ruby 3.0");
return GET_VM()->safe_level_;
}
void
rb_set_safe_level_force(int safe)
{
+ rb_warn("rb_set_safe_level_force will be removed in Ruby 3.0");
GET_VM()->safe_level_ = safe;
}
@@ -48,6 +51,7 @@ rb_set_safe_level(int level)
{
rb_vm_t *vm = GET_VM();
+ rb_warn("rb_set_safe_level will be removed in Ruby 3.0");
if (level > SAFE_LEVEL_MAX) {
rb_raise(rb_eArgError, "$SAFE=2 to 4 are obsolete");
}
@@ -68,28 +72,47 @@ rb_set_safe_level(int level)
static VALUE
safe_getter(ID _x, VALUE *_y)
{
- return INT2NUM(rb_safe_level());
+ rb_warn("$SAFE will become a normal global variable in Ruby 3.0");
+ return INT2NUM(GET_VM()->safe_level_);
}
static void
safe_setter(VALUE val, ID _x, VALUE *_y)
{
int level = NUM2INT(val);
- rb_set_safe_level(level);
+ rb_vm_t *vm = GET_VM();
+
+ rb_warn("$SAFE will become a normal global variable in Ruby 3.0");
+ if (level > SAFE_LEVEL_MAX) {
+ rb_raise(rb_eArgError, "$SAFE=2 to 4 are obsolete");
+ }
+ else if (level < 0) {
+ rb_raise(rb_eArgError, "$SAFE should be >= 0");
+ }
+ else {
+ int line;
+ const char *path = rb_source_location_cstr(&line);
+
+ if (0) fprintf(stderr, "%s:%d $SAFE %d -> %d\n",
+ path ? path : "-", line, vm->safe_level_, level);
+
+ vm->safe_level_ = level;
+ }
}
void
rb_secure(int level)
{
- if (level <= rb_safe_level()) {
+ rb_warn("rb_secure will be removed in Ruby 3.0");
+ if (level <= GET_VM()->safe_level_) {
ID caller_name = rb_frame_callee();
if (caller_name) {
rb_raise(rb_eSecurityError, "Insecure operation `%"PRIsVALUE"' at level %d",
- rb_id2str(caller_name), rb_safe_level());
+ rb_id2str(caller_name), GET_VM()->safe_level_);
}
else {
rb_raise(rb_eSecurityError, "Insecure operation at level %d",
- rb_safe_level());
+ GET_VM()->safe_level_);
}
}
}
@@ -97,11 +120,13 @@ rb_secure(int level)
void
rb_secure_update(VALUE obj)
{
+ rb_warn("rb_secure_update will be removed in Ruby 3.0");
}
void
rb_insecure_operation(void)
{
+ rb_warn("rb_insecure_operation will be removed in Ruby 3.0");
ID caller_name = rb_frame_callee();
if (caller_name) {
rb_raise(rb_eSecurityError, "Insecure operation - %"PRIsVALUE,
@@ -115,6 +140,7 @@ rb_insecure_operation(void)
void
rb_check_safe_obj(VALUE x)
{
+ rb_warn("rb_check_safe_obj will be removed in Ruby 3.0");
if (rb_safe_level() > 0 && OBJ_TAINTED(x)) {
rb_insecure_operation();
}
diff --git a/signal.c b/signal.c
index 8fb4306..82aeb81 100644
--- a/signal.c
+++ b/signal.c
@@ -1024,7 +1024,7 @@ sig_do_nothing(int sig)
#endif
static int
-signal_exec(VALUE cmd, int safe, int sig)
+signal_exec(VALUE cmd, int sig)
{
rb_execution_context_t *ec = GET_EC();
volatile rb_atomic_t old_interrupt_mask = ec->interrupt_mask;
@@ -1043,7 +1043,7 @@ signal_exec(VALUE cmd, int safe, int sig)
EC_PUSH_TAG(ec);
if ((state = EC_EXEC_TAG()) == TAG_NONE) {
VALUE signum = INT2NUM(sig);
- rb_eval_cmd(cmd, rb_ary_new3(1, signum), safe);
+ rb_eval_cmd(cmd, rb_ary_new3(1, signum), 0);
}
EC_POP_TAG();
ec = GET_EC();
@@ -1063,7 +1063,7 @@ rb_vm_trap_exit(rb_vm_t *vm)
if (trap_exit) {
vm->trap_list.cmd[0] = 0;
- signal_exec(trap_exit, vm->trap_list.safe[0], 0);
+ signal_exec(trap_exit, 0);
}
}
@@ -1083,7 +1083,6 @@ rb_signal_exec(rb_thread_t *th, int sig)
{
rb_vm_t *vm = GET_VM();
VALUE cmd = vm->trap_list.cmd[sig];
- int safe = vm->trap_list.safe[sig];
if (cmd == 0) {
switch (sig) {
@@ -1116,7 +1115,7 @@ rb_signal_exec(rb_thread_t *th, int sig)
rb_threadptr_signal_exit(th);
}
else {
- return signal_exec(cmd, safe, sig);
+ return signal_exec(cmd, sig);
}
return FALSE;
}
@@ -1302,7 +1301,6 @@ trap(int sig, sighandler_t func, VALUE command)
}
ACCESS_ONCE(VALUE, vm->trap_list.cmd[sig]) = command;
- vm->trap_list.safe[sig] = rb_safe_level();
return oldcmd;
}
diff --git a/spec/ruby/language/predefined_spec.rb b/spec/ruby/language/predefined_spec.rb
index 90ea8c6..cec6bc8 100644
--- a/spec/ruby/language/predefined_spec.rb
+++ b/spec/ruby/language/predefined_spec.rb
@@ -771,8 +771,6 @@ __LINE__ String The current line number in the source file. [r/
$LOAD_PATH Array A synonym for $:. [r/o]
$-p Object Set to true if the -p option (which puts an implicit while gets . . . end
loop around your program) is present on the command line. [r/o]
-$SAFE Fixnum The current safe level. This variable’s value may never be
- reduced by assignment. [thread] (Not implemented in Rubinius)
$VERBOSE Object Set to true if the -v, --version, -W, or -w option is specified on the com-
mand line. Set to false if no option, or -W1 is given. Set to nil if -W0
was specified. Setting this option to true causes the interpreter and some
diff --git a/spec/ruby/language/safe_spec.rb b/spec/ruby/language/safe_spec.rb
index be150df..53ab4f9 100644
--- a/spec/ruby/language/safe_spec.rb
+++ b/spec/ruby/language/safe_spec.rb
@@ -1,137 +1,138 @@
require_relative '../spec_helper'
describe "The $SAFE variable" do
-
- ruby_version_is "2.6" do
- after :each do
- $SAFE = 0
+ ruby_version_is ""..."2.7" do
+ ruby_version_is "2.6" do
+ after :each do
+ $SAFE = 0
+ end
end
- end
- it "is 0 by default" do
- $SAFE.should == 0
- proc {
+ it "is 0 by default" do
$SAFE.should == 0
- }.call
- end
+ proc {
+ $SAFE.should == 0
+ }.call
+ end
- it "can be set to 0" do
- proc {
- $SAFE = 0
- $SAFE.should == 0
- }.call
- end
+ it "can be set to 0" do
+ proc {
+ $SAFE = 0
+ $SAFE.should == 0
+ }.call
+ end
- it "can be set to 1" do
- proc {
- $SAFE = 1
- $SAFE.should == 1
- }.call
- end
+ it "can be set to 1" do
+ proc {
+ $SAFE = 1
+ $SAFE.should == 1
+ }.call
+ end
- [2, 3, 4].each do |n|
- it "cannot be set to #{n}" do
+ [2, 3, 4].each do |n|
+ it "cannot be set to #{n}" do
+ -> {
+ proc {
+ $SAFE = n
+ }.call
+ }.should raise_error(ArgumentError, /\$SAFE=2 to 4 are obsolete/)
+ end
+ end
+
+ ruby_version_is ""..."2.6" do
+ it "cannot be set to values below 0" do
+ -> {
+ proc {
+ $SAFE = -100
+ }.call
+ }.should raise_error(SecurityError, /tried to downgrade safe level from 0 to -100/)
+ end
+ end
+
+ ruby_version_is "2.6" do
+ it "raises ArgumentError when set to values below 0" do
+ -> {
+ proc {
+ $SAFE = -100
+ }.call
+ }.should raise_error(ArgumentError, "$SAFE should be >= 0")
+ end
+ end
+
+ it "cannot be set to values above 4" do
-> {
proc {
- $SAFE = n
+ $SAFE = 100
}.call
}.should raise_error(ArgumentError, /\$SAFE=2 to 4 are obsolete/)
end
- end
- ruby_version_is ""..."2.6" do
- it "cannot be set to values below 0" do
- -> {
+ ruby_version_is ""..."2.6" do
+ it "cannot be manually lowered" do
proc {
- $SAFE = -100
+ $SAFE = 1
+ -> {
+ $SAFE = 0
+ }.should raise_error(SecurityError, /tried to downgrade safe level from 1 to 0/)
}.call
- }.should raise_error(SecurityError, /tried to downgrade safe level from 0 to -100/)
- end
- end
+ end
- ruby_version_is "2.6" do
- it "raises ArgumentError when set to values below 0" do
- -> {
+ it "is automatically lowered when leaving a proc" do
+ $SAFE.should == 0
proc {
- $SAFE = -100
+ $SAFE = 1
}.call
- }.should raise_error(ArgumentError, "$SAFE should be >= 0")
- end
- end
-
- it "cannot be set to values above 4" do
- -> {
- proc {
- $SAFE = 100
- }.call
- }.should raise_error(ArgumentError, /\$SAFE=2 to 4 are obsolete/)
- end
+ $SAFE.should == 0
+ end
- ruby_version_is ""..."2.6" do
- it "cannot be manually lowered" do
- proc {
- $SAFE = 1
+ it "is automatically lowered when leaving a lambda" do
+ $SAFE.should == 0
-> {
- $SAFE = 0
- }.should raise_error(SecurityError, /tried to downgrade safe level from 1 to 0/)
- }.call
+ $SAFE = 1
+ }.call
+ $SAFE.should == 0
+ end
end
- it "is automatically lowered when leaving a proc" do
- $SAFE.should == 0
- proc {
+ ruby_version_is "2.6" do
+ it "can be manually lowered" do
$SAFE = 1
- }.call
- $SAFE.should == 0
- end
+ $SAFE = 0
+ $SAFE.should == 0
+ end
- it "is automatically lowered when leaving a lambda" do
- $SAFE.should == 0
- -> {
+ it "is not Proc local" do
+ $SAFE.should == 0
+ proc {
+ $SAFE = 1
+ }.call
+ $SAFE.should == 1
+ end
+
+ it "is not lambda local" do
+ $SAFE.should == 0
+ -> {
+ $SAFE = 1
+ }.call
+ $SAFE.should == 1
+ end
+
+ it "is global like regular global variables" do
+ Thread.new { $SAFE }.value.should == 0
$SAFE = 1
- }.call
- $SAFE.should == 0
+ Thread.new { $SAFE }.value.should == 1
+ end
end
- end
- ruby_version_is "2.6" do
- it "can be manually lowered" do
- $SAFE = 1
- $SAFE = 0
- $SAFE.should == 0
+ it "can be read when default from Thread#safe_level" do
+ Thread.current.safe_level.should == 0
end
- it "is not Proc local" do
- $SAFE.should == 0
+ it "can be read when modified from Thread#safe_level" do
proc {
$SAFE = 1
+ Thread.current.safe_level.should == 1
}.call
- $SAFE.should == 1
end
-
- it "is not lambda local" do
- $SAFE.should == 0
- -> {
- $SAFE = 1
- }.call
- $SAFE.should == 1
- end
-
- it "is global like regular global variables" do
- Thread.new { $SAFE }.value.should == 0
- $SAFE = 1
- Thread.new { $SAFE }.value.should == 1
- end
- end
-
- it "can be read when default from Thread#safe_level" do
- Thread.current.safe_level.should == 0
- end
-
- it "can be read when modified from Thread#safe_level" do
- proc {
- $SAFE = 1
- Thread.current.safe_level.should == 1
- }.call
end
end
diff --git a/spec/ruby/optional/capi/string_spec.rb b/spec/ruby/optional/capi/string_spec.rb
index 1cfd590..53d28f7 100644
--- a/spec/ruby/optional/capi/string_spec.rb
+++ b/spec/ruby/optional/capi/string_spec.rb
@@ -558,20 +558,22 @@ describe "C-API String function" do
end
describe "SafeStringValue" do
- it "raises for tained string when $SAFE is 1" do
- begin
- Thread.new {
- $SAFE = 1
- -> {
- @s.SafeStringValue("str".taint)
- }.should raise_error(SecurityError)
- }.join
- ensure
- $SAFE = 0
+ ruby_version_is ''...'2.7' do
+ it "raises for tained string when $SAFE is 1" do
+ begin
+ Thread.new {
+ $SAFE = 1
+ -> {
+ @s.SafeStringValue("str".taint)
+ }.should raise_error(SecurityError)
+ }.join
+ ensure
+ $SAFE = 0
+ end
end
- end
- it_behaves_like :string_value_macro, :SafeStringValue
+ it_behaves_like :string_value_macro, :SafeStringValue
+ end
end
describe "rb_str_modify_expand" do
diff --git a/test/net/imap/test_imap_response_parser.rb b/test/net/imap/test_imap_response_parser.rb
index ed31a03..5c2d545 100644
--- a/test/net/imap/test_imap_response_parser.rb
+++ b/test/net/imap/test_imap_response_parser.rb
@@ -20,19 +20,6 @@ class IMAPResponseParserTest < Test::Unit::TestCase
end
end
- def test_flag_list_safe
- parser = Net::IMAP::ResponseParser.new
- response = lambda {
- $SAFE = 1
- parser.parse(<<EOF.gsub(/\n/, "\r\n").taint)
-* LIST (\\HasChildren) "." "INBOX"
-EOF
- }.call
- assert_equal [:Haschildren], response.data.attr
- ensure
- $SAFE = 0
- end
-
def test_flag_list_too_many_flags
parser = Net::IMAP::ResponseParser.new
assert_nothing_raised do
diff --git a/test/pathname/test_pathname.rb b/test/pathname/test_pathname.rb
index 39c792d..4d480a5 100644
--- a/test/pathname/test_pathname.rb
+++ b/test/pathname/test_pathname.rb
@@ -1467,16 +1467,6 @@ class TestPathname < Test::Unit::TestCase
assert(File.fnmatch("*.*", Pathname.new("bar.baz")))
end
- def test_file_join
- assert_equal("foo/bar", File.join(Pathname.new("foo"), Pathname.new("bar")))
- lambda {
- $SAFE = 1
- assert_equal("foo/bar", File.join(Pathname.new("foo"), Pathname.new("bar").taint))
- }.call
- ensure
- $SAFE = 0
- end
-
def test_relative_path_from_casefold
assert_separately([], <<-'end;') # do
module File::Constants
diff --git a/test/readline/test_readline.rb b/test/readline/test_readline.rb
index 4e82d46..f874354 100644
--- a/test/readline/test_readline.rb
+++ b/test/readline/test_readline.rb
@@ -41,21 +41,6 @@ module BasetestReadline
assert_equal("> ", stdout.read(2))
assert_equal(1, Readline::HISTORY.length)
assert_equal("hello", Readline::HISTORY[0])
-
- # Work around lack of SecurityError in Reline
- # test mode with tainted prompt
- return if kind_of?(TestRelineAsReadline)
-
- Thread.start {
- $SAFE = 1
- assert_raise(SecurityError) do
- replace_stdio(stdin.path, stdout.path) do
- Readline.readline("> ".taint)
- end
- end
- }.join
- ensure
- $SAFE = 0
end
end
diff --git a/test/ruby/test_alias.rb b/test/ruby/test_alias.rb
index e81636f..33fb82e 100644
--- a/test/ruby/test_alias.rb
+++ b/test/ruby/test_alias.rb
@@ -47,12 +47,6 @@ class TestAlias < Test::Unit::TestCase
assert_raise(NoMethodError) { x.quux }
end
- class C
- def m
- $SAFE
- end
- end
-
def test_nonexistmethod
assert_raise(NameError){
Class.new{
diff --git a/test/ruby/test_file.rb b/test/ruby/test_file.rb
index f984a8f..5599040 100644
--- a/test/ruby/test_file.rb
+++ b/test/ruby/test_file.rb
@@ -471,18 +471,6 @@ class TestFile < Test::Unit::TestCase
end
end
- def test_untainted_path
- bug5374 = '[ruby-core:39745]'
- cwd = ("./"*40+".".taint).dup.untaint
- in_safe = proc {|safe| $SAFE = safe; File.stat(cwd)}
- assert_not_send([cwd, :tainted?])
- (0..1).each do |level|
- assert_nothing_raised(SecurityError, bug5374) {in_safe[level]}
- end
- ensure
- $SAFE = 0
- end
-
if /(bcc|ms|cyg)win|mingw|emx/ =~ RUBY_PLATFORM
def test_long_unc
feature3399 = '[ruby-core:30623]'
diff --git a/test/ruby/test_optimization.rb b/test/ruby/test_optimization.rb
index f26b31f..b42314b 100644
--- a/test/ruby/test_optimization.rb
+++ b/test/ruby/test_optimization.rb
@@ -714,17 +714,6 @@ class TestRubyOptimization < Test::Unit::TestCase
END
end
- def test_block_parameter_should_restore_safe_level
- assert_separately [], <<-END
- #
- def foo &b
- $SAFE = 1
- b.call
- end
- assert_equal 1, foo{$SAFE}
- END
- end
-
def test_peephole_optimization_without_trace
assert_separately [], <<-END
RubyVM::InstructionSequence.compile_option = {trace_instruction: false}
diff --git a/test/ruby/test_proc.rb b/test/ruby/test_proc.rb
index 5c12043..0e0b5c7 100644
--- a/test/ruby/test_proc.rb
+++ b/test/ruby/test_proc.rb
@@ -157,45 +157,6 @@ class TestProc < Test::Unit::TestCase
assert_equal(12, Proc.new{|a,&b| b.call(a)}.call(12) {|x| x})
end
- def test_safe
- safe = $SAFE
- c = Class.new
- x = c.new
-
- p = proc {
- $SAFE += 1
- proc {$SAFE}
- }.call
-
- assert_equal(safe + 1, $SAFE)
- assert_equal(safe + 1, p.call)
- assert_equal(safe + 1, $SAFE)
-
- $SAFE = 0
- c.class_eval {define_method(:safe, p)}
- assert_equal(safe, x.safe)
-
- $SAFE = 0
- p = proc {$SAFE += 1}
- assert_equal(safe + 1, p.call)
- assert_equal(safe + 1, $SAFE)
-
- $SAFE = 0
- c.class_eval {define_method(:inc, p)}
- assert_equal(safe + 1, proc {x.inc; $SAFE}.call)
- assert_equal(safe + 1, $SAFE)
-
- $SAFE = 0
- assert_equal(safe + 1, proc {x.method(:inc).call; $SAFE}.call)
- assert_equal(safe + 1, $SAFE)
-
- $SAFE = 0
- assert_equal(safe + 1, proc {x.method(:inc).to_proc.call; $SAFE}.call)
- assert_equal(safe + 1, $SAFE)
- ensure
- $SAFE = 0
- end
-
def m2
"OK"
end
diff --git a/test/ruby/test_require.rb b/test/ruby/test_require.rb
index 560ce3f..e21ed88 100644
--- a/test/ruby/test_require.rb
+++ b/test/ruby/test_require.rb
@@ -398,13 +398,6 @@ class TestRequire < Test::Unit::TestCase
assert_separately([], <<-INPUT)
abs_dir = "#{ abs_dir }"
- $: << abs_dir.taint
- $SAFE = 1
- assert_raise(SecurityError) {require "#{ file }"}
- INPUT
-
- assert_separately([], <<-INPUT)
- abs_dir = "#{ abs_dir }"
$: << abs_dir << 'elsewhere'.taint
assert_nothing_raised {require "#{ file }"}
INPUT
diff --git a/test/ruby/test_rubyoptions.rb b/test/ruby/test_rubyoptions.rb
index 22ea6b5..27a9434 100644
--- a/test/ruby/test_rubyoptions.rb
+++ b/test/ruby/test_rubyoptions.rb
@@ -79,14 +79,6 @@ class TestRubyOptions < Test::Unit::TestCase
ENV['RUBYOPT'] = save_rubyopt
end
- def test_safe_level
- assert_in_out_err(%w(-T -e) + [""], "", [],
- /no -e allowed in tainted mode \(SecurityError\)/)
-
- assert_in_out_err(%w(-T4 -S foo.rb), "", [],
- /no -S allowed in tainted mode \(SecurityError\)/)
- end
-
def test_debug
assert_in_out_err(["--disable-gems", "-de", "p $DEBUG"], "", %w(true), [])
@@ -326,12 +318,6 @@ class TestRubyOptions < Test::Unit::TestCase
ENV['RUBYOPT'] = '-e "p 1"'
assert_in_out_err([], "", [], /invalid switch in RUBYOPT: -e \(RuntimeError\)/)
- ENV['RUBYOPT'] = '-T1'
- assert_in_out_err(["--disable-gems"], "", [], /no program input from stdin allowed in tainted mode \(SecurityError\)/)
-
- ENV['RUBYOPT'] = '-T4'
- assert_in_out_err(["--disable-gems"], "", [], /no program input from stdin allowed in tainted mode \(SecurityError\)/)
-
ENV['RUBYOPT'] = '-Eus-ascii -KN'
assert_in_out_err(%w(-Eutf-8 -KU), "p '\u3042'") do |r, e|
assert_equal("\"\u3042\"", r.join.force_encoding(Encoding::UTF_8))
diff --git a/test/ruby/test_thread.rb b/test/ruby/test_thread.rb
index e0efb7b..adfad7e 100644
--- a/test/ruby/test_thread.rb
+++ b/test/ruby/test_thread.rb
@@ -533,23 +533,6 @@ class TestThread < Test::Unit::TestCase
waiter&.kill&.join
end
- def test_safe_level
- ok = false
- t = Thread.new do
- EnvUtil.suppress_warning do
- $SAFE = 1
- end
- ok = true
- sleep
- end
- Thread.pass until ok
- assert_equal($SAFE, Thread.current.safe_level)
- assert_equal($SAFE, t.safe_level)
- ensure
- $SAFE = 0
- t&.kill&.join
- end
-
def test_thread_local
t = Thread.new { sleep }
diff --git a/test/test_tempfile.rb b/test/test_tempfile.rb
index 7c911a1..6b087f9 100644
--- a/test/test_tempfile.rb
+++ b/test/test_tempfile.rb
@@ -31,17 +31,6 @@ class TestTempfile < Test::Unit::TestCase
assert_equal "hello world", File.read(path)
end
- def test_saves_in_dir_tmpdir_by_default
- t = tempfile("foo")
- assert_equal Dir.tmpdir, File.dirname(t.path)
- bug3733 = '[ruby-dev:42089]'
- assert_nothing_raised(SecurityError, bug3733) {
- proc {$SAFE = 1; File.expand_path(Dir.tmpdir)}.call
- }
- ensure
- $SAFE = 0
- end
-
def test_saves_in_given_directory
subdir = File.join(Dir.tmpdir, "tempfile-test-#{rand}")
Dir.mkdir(subdir)
diff --git a/test/test_tmpdir.rb b/test/test_tmpdir.rb
index 42bcbc0..c599dcf 100644
--- a/test/test_tmpdir.rb
+++ b/test/test_tmpdir.rb
@@ -11,19 +11,6 @@ class TestTmpdir < Test::Unit::TestCase
assert_equal(tmpdir_org, Dir.tmpdir)
end
- def test_tmpdir_modifiable_safe
- Thread.new {
- $SAFE = 1
- tmpdir = Dir.tmpdir
- assert_equal(false, tmpdir.frozen?)
- tmpdir_org = tmpdir.dup
- tmpdir << "foo"
- assert_equal(tmpdir_org, Dir.tmpdir)
- }.join
- ensure
- $SAFE = 0
- end
-
def test_world_writable
skip "no meaning on this platform" if /mswin|mingw/ =~ RUBY_PLATFORM
Dir.mktmpdir do |tmpdir|
diff --git a/test/win32ole/test_win32ole.rb b/test/win32ole/test_win32ole.rb
index 7dda36c..3941780 100644
--- a/test/win32ole/test_win32ole.rb
+++ b/test/win32ole/test_win32ole.rb
@@ -176,39 +176,6 @@ if defined?(WIN32OLE)
}
end
- def test_s_new_exc_svr_tainted
- th = Thread.start {
- $SAFE = 1
- svr = "Scripting.Dictionary"
- svr.taint
- Thread.current.report_on_exception = false
- WIN32OLE.new(svr)
- }
- exc = assert_raise(SecurityError) {
- th.join
- }
- assert_match(/insecure object creation - `Scripting.Dictionary'/, exc.message)
- ensure
- $SAFE = 0
- end
-
- def test_s_new_exc_host_tainted
- th = Thread.start {
- $SAFE = 1
- svr = "Scripting.Dictionary"
- host = "localhost"
- host.taint
- Thread.current.report_on_exception = false
- WIN32OLE.new(svr, host)
- }
- exc = assert_raise(SecurityError) {
- th.join
- }
- assert_match(/insecure object creation - `localhost'/, exc.message)
- ensure
- $SAFE = 0
- end
-
def test_s_new_DCOM
rshell = WIN32OLE.new("Shell.Application")
assert_instance_of(WIN32OLE, rshell)
@@ -234,22 +201,6 @@ if defined?(WIN32OLE)
}
end
- def test_s_coonect_exc_tainted
- th = Thread.start {
- $SAFE = 1
- svr = "winmgmts:"
- svr.taint
- Thread.current.report_on_exception = false
- WIN32OLE.connect(svr)
- }
- exc = assert_raise(SecurityError) {
- th.join
- }
- assert_match(/insecure connection - `winmgmts:'/, exc.message)
- ensure
- $SAFE = 0
- end
-
def test_invoke_accept_symbol_hash_key
fso = WIN32OLE.new('Scripting.FileSystemObject')
afolder = fso.getFolder(".")
diff --git a/test/win32ole/test_win32ole_event.rb b/test/win32ole/test_win32ole_event.rb
index d8e1625..742bff4 100644
--- a/test/win32ole/test_win32ole_event.rb
+++ b/test/win32ole/test_win32ole_event.rb
@@ -401,21 +401,6 @@ if defined?(WIN32OLE_EVENT)
message_loop
assert(h2.ev != "")
end
-
- def test_s_new_exc_tainted
- th = Thread.new {
- $SAFE=1
- str = 'ConnectionEvents'
- str.taint
- WIN32OLE_EVENT.new(@db, str)
- }
- exc = assert_raise(SecurityError) {
- th.join
- }
- assert_match(/insecure event creation - `ConnectionEvents'/, exc.message)
- ensure
- $SAFE = 0
- end
end
end
end
diff --git a/thread.c b/thread.c
index 15dea98..52d89a0 100644
--- a/thread.c
+++ b/thread.c
@@ -3112,7 +3112,8 @@ rb_thread_stop_p(VALUE thread)
static VALUE
rb_thread_safe_level(VALUE thread)
{
- return UINT2NUM(rb_safe_level());
+ rb_warn("Thread#safe_level will be removed in Ruby 3.0");
+ return UINT2NUM(GET_VM()->safe_level_);
}
/*
diff --git a/tool/lib/leakchecker.rb b/tool/lib/leakchecker.rb
index 26ece93..57e2866 100644
--- a/tool/lib/leakchecker.rb
+++ b/tool/lib/leakchecker.rb
@@ -16,16 +16,11 @@ class LeakChecker
check_tempfile_leak(test_name),
check_env(test_name),
check_encodings(test_name),
- check_safe(test_name),
check_verbose(test_name),
]
GC.start if leaks.any?
end
- def check_safe test_name
- puts "#{test_name}: $SAFE == #{$SAFE}" unless $SAFE == 0
- end
-
def check_verbose test_name
puts "#{test_name}: $VERBOSE == #{$VERBOSE}" unless @old_verbose == $VERBOSE
end
diff --git a/transcode.c b/transcode.c
index 86ca57b..8a6c535 100644
--- a/transcode.c
+++ b/transcode.c
@@ -375,7 +375,7 @@ load_transcoder_entry(transcoder_entry_t *entry)
rb_str_set_len(fn, total_len);
FL_UNSET(fn, FL_TAINT);
OBJ_FREEZE(fn);
- rb_require_safe(fn, rb_safe_level());
+ rb_require_string(fn);
}
if (entry->transcoder)
diff --git a/variable.c b/variable.c
index afa6331..825f2d6 100644
--- a/variable.c
+++ b/variable.c
@@ -1805,7 +1805,6 @@ struct autoload_const {
VALUE ad; /* autoload_data_i */
VALUE value;
ID id;
- int safe_level;
rb_const_flag_t flag;
};
@@ -1999,7 +1998,6 @@ rb_autoload_str(VALUE mod, ID id, VALUE file)
ac->mod = mod;
ac->id = id;
ac->value = Qundef;
- ac->safe_level = rb_safe_level();
ac->flag = CONST_PUBLIC;
ac->ad = ad;
list_add_tail(&ele->constants, &ac->cnode);
@@ -2039,27 +2037,12 @@ autoload_delete(VALUE mod, ID id)
}
static VALUE
-autoload_provided(VALUE arg)
-{
- const char **p = (const char **)arg;
- return rb_feature_provided(*p, p);
-}
-
-static VALUE
-reset_safe(VALUE safe)
-{
- rb_set_safe_level_force((int)safe);
- return safe;
-}
-
-static VALUE
check_autoload_required(VALUE mod, ID id, const char **loadingpath)
{
VALUE file;
VALUE load = autoload_data(mod, id);
struct autoload_data_i *ele;
const char *loading;
- int safe;
if (!load || !(ele = get_autoload_data(load, 0))) {
return 0;
@@ -2081,9 +2064,7 @@ check_autoload_required(VALUE mod, ID id, const char **loadingpath)
}
loading = RSTRING_PTR(file);
- safe = rb_safe_level();
- rb_set_safe_level_force(0);
- if (!rb_ensure(autoload_provided, (VALUE)&loading, reset_safe, (VALUE)safe)) {
+ if (!rb_feature_provided(loading, &loading)) {
return load;
}
if (loadingpath && loading) {
@@ -2186,12 +2167,10 @@ autoload_reset(VALUE arg)
/* At the last, move a value defined in autoload to constant table */
if (RTEST(state->result)) {
struct autoload_const *next;
- int safe_backup = rb_safe_level();
list_for_each_safe(&ele->constants, ac, next, cnode) {
if (ac->value != Qundef) {
- rb_ensure(autoload_const_set, (VALUE)ac,
- reset_safe, (VALUE)safe_backup);
+ autoload_const_set((VALUE)ac);
}
}
}
diff --git a/vm_core.h b/vm_core.h
index ea2e7a2..0946928 100644
--- a/vm_core.h
+++ b/vm_core.h
@@ -619,7 +619,6 @@ typedef struct rb_vm_struct {
/* signal */
struct {
VALUE cmd[RUBY_NSIG];
- unsigned char safe[RUBY_NSIG];
} trap_list;
/* hook */
diff --git a/vm_eval.c b/vm_eval.c
index 4c73d73..8b557fa 100644
--- a/vm_eval.c
+++ b/vm_eval.c
@@ -1777,19 +1777,13 @@ rb_eval_string_wrap(const char *str, int *pstate)
}
VALUE
-rb_eval_cmd(VALUE cmd, VALUE arg, int level)
+rb_eval_cmd(VALUE cmd, VALUE arg, int _level)
{
enum ruby_tag_type state;
volatile VALUE val = Qnil; /* OK */
- const int VAR_NOCLOBBERED(current_safe_level) = rb_safe_level();
rb_execution_context_t * volatile ec = GET_EC();
- if (OBJ_TAINTED(cmd)) {
- level = RUBY_SAFE_LEVEL_MAX;
- }
-
EC_PUSH_TAG(ec);
- rb_set_safe_level_force(level);
if ((state = EC_EXEC_TAG()) == TAG_NONE) {
if (!RB_TYPE_P(cmd, T_STRING)) {
val = rb_funcallv(cmd, idCall, RARRAY_LENINT(arg),
@@ -1801,7 +1795,6 @@ rb_eval_cmd(VALUE cmd, VALUE arg, int level)
}
EC_POP_TAG();
- rb_set_safe_level_force(current_safe_level);
if (state) EC_JUMP_TAG(ec, state);
return val;
}