1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00

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.
This commit is contained in:
Jeremy Evans 2019-09-20 19:06:22 -07:00
parent 7b6a8b5b54
commit c5c05460ac
Notes: git 2019-11-18 08:01:15 +09:00
59 changed files with 283 additions and 751 deletions

1
dir.c
View file

@ -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();

View file

@ -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);

View file

@ -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

1
eval.c
View file

@ -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));

View file

@ -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);

View file

@ -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);
}
}

View file

@ -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);
}

View file

@ -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);

View file

@ -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)\

View file

@ -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);

View file

@ -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")",

View file

@ -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 */
}
}

View file

@ -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)) {

View file

@ -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);
}

View file

@ -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 {

64
file.c
View file

@ -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);
}

10
gc.c
View file

@ -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 */

2
hash.c
View file

@ -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, '=');

View file

@ -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);

View file

@ -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);

View file

@ -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 */

3
io.c
View file

@ -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;
}

10
iseq.c
View file

@ -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);

View file

@ -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'

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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"

View file

@ -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

68
load.c
View file

@ -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, safe, 1);
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, 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

View file

@ -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();

29
proc.c
View file

@ -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);
}

View file

@ -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;
}

54
ruby.c
View file

@ -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;
{
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;
}
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

36
safe.c
View file

@ -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();
}

View file

@ -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;
}

View file

@ -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 variables 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

View file

@ -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
$SAFE.should == 0
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
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
ruby_version_is "2.6" do
it "can be manually lowered" do
$SAFE = 1
$SAFE = 0
$SAFE.should == 0
end
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
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
$SAFE.should == 0
end
it "is automatically lowered when leaving a lambda" do
$SAFE.should == 0
-> {
$SAFE = 1
}.call
$SAFE.should == 0
end
end
ruby_version_is "2.6" do
it "can be manually lowered" do
$SAFE = 1
$SAFE = 0
$SAFE.should == 0
end
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
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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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{

View file

@ -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]'

View file

@ -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}

View file

@ -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

View file

@ -396,13 +396,6 @@ class TestRequire < Test::Unit::TestCase
assert_nothing_raised {require "#{ file }"}
INPUT
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

View file

@ -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))

View file

@ -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 }

View file

@ -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)

View file

@ -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|

View file

@ -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(".")

View file

@ -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

View file

@ -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_);
}
/*

View file

@ -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

View file

@ -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)

View file

@ -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);
@ -2038,20 +2036,6 @@ 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)
{
@ -2059,7 +2043,6 @@ check_autoload_required(VALUE mod, ID id, const char **loadingpath)
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);
}
}
}

View file

@ -619,7 +619,6 @@ typedef struct rb_vm_struct {
/* signal */
struct {
VALUE cmd[RUBY_NSIG];
unsigned char safe[RUBY_NSIG];
} trap_list;
/* hook */

View file

@ -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;
}