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:
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
1
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();
|
||||
|
|
|
@ -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);
|
||||
|
|
6
error.c
6
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
|
||||
|
|
1
eval.c
1
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));
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)\
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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")",
|
||||
|
|
|
@ -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 */
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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
64
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);
|
||||
}
|
||||
|
||||
|
|
10
gc.c
10
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 */
|
||||
|
|
2
hash.c
2
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, '=');
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
3
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;
|
||||
}
|
||||
|
|
10
iseq.c
10
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);
|
||||
|
||||
|
|
|
@ -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'
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
20
lib/erb.rb
20
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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
68
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, 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
|
||||
|
|
2
parse.y
2
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();
|
||||
|
|
29
proc.c
29
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);
|
||||
}
|
||||
|
||||
|
|
12
process.c
12
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;
|
||||
}
|
||||
|
||||
|
|
54
ruby.c
54
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;
|
||||
{
|
||||
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
36
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();
|
||||
}
|
||||
|
|
10
signal.c
10
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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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{
|
||||
|
|
|
@ -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]'
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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 }
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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|
|
||||
|
|
|
@ -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(".")
|
||||
|
|
|
@ -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
|
||||
|
|
3
thread.c
3
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_);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
25
variable.c
25
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);
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -619,7 +619,6 @@ typedef struct rb_vm_struct {
|
|||
/* signal */
|
||||
struct {
|
||||
VALUE cmd[RUBY_NSIG];
|
||||
unsigned char safe[RUBY_NSIG];
|
||||
} trap_list;
|
||||
|
||||
/* hook */
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue