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");
|
rb_raise(rb_eArgError, "nul-separated glob pattern is deprecated");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
rb_check_safe_obj(str);
|
|
||||||
rb_enc_check(str, rb_enc_from_encoding(rb_usascii_encoding()));
|
rb_enc_check(str, rb_enc_from_encoding(rb_usascii_encoding()));
|
||||||
}
|
}
|
||||||
ary = rb_ary_new();
|
ary = rb_ary_new();
|
||||||
|
|
|
@ -654,7 +654,7 @@ load_encoding(const char *name)
|
||||||
ruby_verbose = Qfalse;
|
ruby_verbose = Qfalse;
|
||||||
ruby_debug = Qfalse;
|
ruby_debug = Qfalse;
|
||||||
errinfo = rb_errinfo();
|
errinfo = rb_errinfo();
|
||||||
loaded = rb_require_internal(enclib, rb_safe_level());
|
loaded = rb_require_internal(enclib);
|
||||||
ruby_verbose = verbose;
|
ruby_verbose = verbose;
|
||||||
ruby_debug = debug;
|
ruby_debug = debug;
|
||||||
rb_set_errinfo(errinfo);
|
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;
|
if (!FL_ABLE(obj)) return;
|
||||||
rb_check_frozen_internal(obj);
|
rb_check_frozen_internal(obj);
|
||||||
if (!FL_ABLE(orig)) return;
|
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
|
void
|
||||||
|
|
1
eval.c
1
eval.c
|
@ -204,7 +204,6 @@ rb_ec_cleanup(rb_execution_context_t *ec, volatile int ex)
|
||||||
th = th0;
|
th = th0;
|
||||||
errs[1] = ec->errinfo;
|
errs[1] = ec->errinfo;
|
||||||
if (THROW_DATA_P(ec->errinfo)) ec->errinfo = Qnil;
|
if (THROW_DATA_P(ec->errinfo)) ec->errinfo = Qnil;
|
||||||
rb_set_safe_level_force(0);
|
|
||||||
ruby_init_stack(&errs[STACK_UPPER(errs, 0, 1)]);
|
ruby_init_stack(&errs[STACK_UPPER(errs, 0, 1)]);
|
||||||
|
|
||||||
SAVE_ROOT_JMPBUF(th, rb_ec_teardown(ec));
|
SAVE_ROOT_JMPBUF(th, rb_ec_teardown(ec));
|
||||||
|
|
|
@ -219,7 +219,6 @@ etc_getpwnam(VALUE obj, VALUE nam)
|
||||||
struct passwd *pwd;
|
struct passwd *pwd;
|
||||||
const char *p = StringValueCStr(nam);
|
const char *p = StringValueCStr(nam);
|
||||||
|
|
||||||
rb_check_safe_obj(nam);
|
|
||||||
pwd = getpwnam(p);
|
pwd = getpwnam(p);
|
||||||
if (pwd == 0) rb_raise(rb_eArgError, "can't find user for %"PRIsVALUE, nam);
|
if (pwd == 0) rb_raise(rb_eArgError, "can't find user for %"PRIsVALUE, nam);
|
||||||
return setup_passwd(pwd);
|
return setup_passwd(pwd);
|
||||||
|
@ -463,7 +462,6 @@ etc_getgrnam(VALUE obj, VALUE nam)
|
||||||
struct group *grp;
|
struct group *grp;
|
||||||
const char *p = StringValueCStr(nam);
|
const char *p = StringValueCStr(nam);
|
||||||
|
|
||||||
rb_check_safe_obj(nam);
|
|
||||||
grp = getgrnam(p);
|
grp = getgrnam(p);
|
||||||
if (grp == 0) rb_raise(rb_eArgError, "can't find group for %"PRIsVALUE, nam);
|
if (grp == 0) rb_raise(rb_eArgError, "can't find group for %"PRIsVALUE, nam);
|
||||||
return setup_group(grp);
|
return setup_group(grp);
|
||||||
|
|
|
@ -1483,7 +1483,6 @@ prompt(int argc, VALUE *argv, VALUE io)
|
||||||
if (argc > 0 && !NIL_P(argv[0])) {
|
if (argc > 0 && !NIL_P(argv[0])) {
|
||||||
VALUE str = argv[0];
|
VALUE str = argv[0];
|
||||||
StringValueCStr(str);
|
StringValueCStr(str);
|
||||||
rb_check_safe_obj(str);
|
|
||||||
rb_io_write(io, str);
|
rb_io_write(io, str);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,8 +67,6 @@ ossl_rand_add(VALUE self, VALUE str, VALUE entropy)
|
||||||
static VALUE
|
static VALUE
|
||||||
ossl_rand_load_file(VALUE self, VALUE filename)
|
ossl_rand_load_file(VALUE self, VALUE filename)
|
||||||
{
|
{
|
||||||
rb_check_safe_obj(filename);
|
|
||||||
|
|
||||||
if(!RAND_load_file(StringValueCStr(filename), -1)) {
|
if(!RAND_load_file(StringValueCStr(filename), -1)) {
|
||||||
ossl_raise(eRandomError, NULL);
|
ossl_raise(eRandomError, NULL);
|
||||||
}
|
}
|
||||||
|
@ -86,8 +84,6 @@ ossl_rand_load_file(VALUE self, VALUE filename)
|
||||||
static VALUE
|
static VALUE
|
||||||
ossl_rand_write_file(VALUE self, VALUE filename)
|
ossl_rand_write_file(VALUE self, VALUE filename)
|
||||||
{
|
{
|
||||||
rb_check_safe_obj(filename);
|
|
||||||
|
|
||||||
if (RAND_write_file(StringValueCStr(filename)) == -1) {
|
if (RAND_write_file(StringValueCStr(filename)) == -1) {
|
||||||
ossl_raise(eRandomError, NULL);
|
ossl_raise(eRandomError, NULL);
|
||||||
}
|
}
|
||||||
|
@ -164,8 +160,6 @@ ossl_rand_pseudo_bytes(VALUE self, VALUE len)
|
||||||
static VALUE
|
static VALUE
|
||||||
ossl_rand_egd(VALUE self, VALUE filename)
|
ossl_rand_egd(VALUE self, VALUE filename)
|
||||||
{
|
{
|
||||||
rb_check_safe_obj(filename);
|
|
||||||
|
|
||||||
if (RAND_egd(StringValueCStr(filename)) == -1) {
|
if (RAND_egd(StringValueCStr(filename)) == -1) {
|
||||||
ossl_raise(eRandomError, NULL);
|
ossl_raise(eRandomError, NULL);
|
||||||
}
|
}
|
||||||
|
@ -186,8 +180,6 @@ ossl_rand_egd_bytes(VALUE self, VALUE filename, VALUE len)
|
||||||
{
|
{
|
||||||
int n = NUM2INT(len);
|
int n = NUM2INT(len);
|
||||||
|
|
||||||
rb_check_safe_obj(filename);
|
|
||||||
|
|
||||||
if (RAND_egd_bytes(StringValueCStr(filename), n) == -1) {
|
if (RAND_egd_bytes(StringValueCStr(filename), n) == -1) {
|
||||||
ossl_raise(eRandomError, NULL);
|
ossl_raise(eRandomError, NULL);
|
||||||
}
|
}
|
||||||
|
|
|
@ -304,7 +304,6 @@ ossl_x509store_add_file(VALUE self, VALUE file)
|
||||||
char *path = NULL;
|
char *path = NULL;
|
||||||
|
|
||||||
if(file != Qnil){
|
if(file != Qnil){
|
||||||
rb_check_safe_obj(file);
|
|
||||||
path = StringValueCStr(file);
|
path = StringValueCStr(file);
|
||||||
}
|
}
|
||||||
GetX509Store(self, store);
|
GetX509Store(self, store);
|
||||||
|
@ -340,7 +339,6 @@ ossl_x509store_add_path(VALUE self, VALUE dir)
|
||||||
char *path = NULL;
|
char *path = NULL;
|
||||||
|
|
||||||
if(dir != Qnil){
|
if(dir != Qnil){
|
||||||
rb_check_safe_obj(dir);
|
|
||||||
path = StringValueCStr(dir);
|
path = StringValueCStr(dir);
|
||||||
}
|
}
|
||||||
GetX509Store(self, store);
|
GetX509Store(self, store);
|
||||||
|
|
|
@ -95,7 +95,6 @@ static char **readline_attempted_completion_function(const char *text,
|
||||||
|
|
||||||
#define OutputStringValue(str) do {\
|
#define OutputStringValue(str) do {\
|
||||||
StringValueCStr(str);\
|
StringValueCStr(str);\
|
||||||
rb_check_safe_obj(str);\
|
|
||||||
(str) = rb_str_conv_enc((str), rb_enc_get(str), rb_locale_encoding());\
|
(str) = rb_str_conv_enc((str), rb_enc_get(str), rb_locale_encoding());\
|
||||||
} while (0)\
|
} 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))) {
|
else if (!NIL_P(tmp = rb_check_string_type(arg))) {
|
||||||
arg = tmp;
|
arg = tmp;
|
||||||
str:
|
str:
|
||||||
rb_check_safe_obj(arg);
|
|
||||||
ptr = RSTRING_PTR(arg);
|
ptr = RSTRING_PTR(arg);
|
||||||
if (str_to_int(ptr, RSTRING_LEN(arg), &ret) == -1)
|
if (str_to_int(ptr, RSTRING_LEN(arg), &ret) == -1)
|
||||||
rb_raise(rb_eSocket, "%s: %s", errmsg, ptr);
|
rb_raise(rb_eSocket, "%s: %s", errmsg, ptr);
|
||||||
|
|
|
@ -503,10 +503,6 @@ str_is_number(const char *p)
|
||||||
#define str_equal(ptr, len, name) \
|
#define str_equal(ptr, len, name) \
|
||||||
((ptr)[0] == name[0] && \
|
((ptr)[0] == name[0] && \
|
||||||
rb_strlen_lit(name) == (len) && memcmp(ptr, name, len) == 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*
|
static char*
|
||||||
host_str(VALUE host, char *hbuf, size_t hbuflen, int *flags_ptr)
|
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;
|
const char *name;
|
||||||
size_t len;
|
size_t len;
|
||||||
|
|
||||||
SafeStringValueCStr(host);
|
StringValueCStr(host);
|
||||||
RSTRING_GETMEM(host, name, len);
|
RSTRING_GETMEM(host, name, len);
|
||||||
if (!len || str_equal(name, len, "<any>")) {
|
if (!len || str_equal(name, len, "<any>")) {
|
||||||
make_inetaddr(INADDR_ANY, hbuf, hbuflen);
|
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;
|
const char *serv;
|
||||||
size_t len;
|
size_t len;
|
||||||
|
|
||||||
SafeStringValueCStr(port);
|
StringValueCStr(port);
|
||||||
RSTRING_GETMEM(port, serv, len);
|
RSTRING_GETMEM(port, serv, len);
|
||||||
if (len >= pbuflen) {
|
if (len >= pbuflen) {
|
||||||
rb_raise(rb_eArgError, "service name too long (%"PRIuSIZE")",
|
rb_raise(rb_eArgError, "service name too long (%"PRIuSIZE")",
|
||||||
|
|
|
@ -39,7 +39,6 @@ unixsock_path_value(VALUE path)
|
||||||
#endif
|
#endif
|
||||||
if (isstr) {
|
if (isstr) {
|
||||||
if (RSTRING_LEN(name) == 0 || RSTRING_PTR(name)[0] == '\0') {
|
if (RSTRING_LEN(name) == 0 || RSTRING_PTR(name)[0] == '\0') {
|
||||||
rb_check_safe_obj(name);
|
|
||||||
return name; /* ignore encoding */
|
return name; /* ignore encoding */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -162,7 +162,6 @@ static VALUE mSyslog_open(int argc, VALUE *argv, VALUE self)
|
||||||
ident = rb_gv_get("$0");
|
ident = rb_gv_get("$0");
|
||||||
}
|
}
|
||||||
ident_ptr = StringValueCStr(ident);
|
ident_ptr = StringValueCStr(ident);
|
||||||
rb_check_safe_obj(ident);
|
|
||||||
syslog_ident = strdup(ident_ptr);
|
syslog_ident = strdup(ident_ptr);
|
||||||
|
|
||||||
if (NIL_P(opt)) {
|
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);
|
rb_scan_args(argc, argv, "1*", &svr_name, &others);
|
||||||
StringValue(svr_name);
|
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 */
|
/* get CLSID from OLE server name */
|
||||||
pBuf = ole_vstr2wc(svr_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);
|
rb_scan_args(argc, argv, "11*:", &svr_name, &host, &others, &opts);
|
||||||
|
|
||||||
StringValue(svr_name);
|
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)) {
|
if (!NIL_P(host)) {
|
||||||
StringValue(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);
|
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)) {
|
if(!RB_TYPE_P(itf, T_NIL)) {
|
||||||
pitf = StringValuePtr(itf);
|
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);
|
hr = find_iid(ole, pitf, &iid, &pTypeInfo);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
64
file.c
64
file.c
|
@ -195,15 +195,11 @@ check_path_encoding(VALUE str)
|
||||||
}
|
}
|
||||||
|
|
||||||
VALUE
|
VALUE
|
||||||
rb_get_path_check_to_string(VALUE obj, int level)
|
rb_get_path_check_to_string(VALUE obj)
|
||||||
{
|
{
|
||||||
VALUE tmp;
|
VALUE tmp;
|
||||||
ID to_path;
|
ID to_path;
|
||||||
|
|
||||||
if (insecure_obj_p(obj, level)) {
|
|
||||||
rb_insecure_operation();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (RB_TYPE_P(obj, T_STRING)) {
|
if (RB_TYPE_P(obj, T_STRING)) {
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
@ -214,38 +210,28 @@ rb_get_path_check_to_string(VALUE obj, int level)
|
||||||
}
|
}
|
||||||
|
|
||||||
VALUE
|
VALUE
|
||||||
rb_get_path_check_convert(VALUE obj, VALUE tmp, int level)
|
rb_get_path_check_convert(VALUE obj)
|
||||||
{
|
{
|
||||||
tmp = file_path_convert(tmp);
|
obj = file_path_convert(obj);
|
||||||
if (obj != tmp && insecure_obj_p(tmp, level)) {
|
|
||||||
rb_insecure_operation();
|
|
||||||
}
|
|
||||||
|
|
||||||
check_path_encoding(tmp);
|
check_path_encoding(obj);
|
||||||
if (!rb_str_to_cstr(tmp)) {
|
if (!rb_str_to_cstr(obj)) {
|
||||||
rb_raise(rb_eArgError, "path name contains null byte");
|
rb_raise(rb_eArgError, "path name contains null byte");
|
||||||
}
|
}
|
||||||
|
|
||||||
return rb_str_new4(tmp);
|
return rb_str_new4(obj);
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
VALUE
|
VALUE
|
||||||
rb_get_path_no_checksafe(VALUE obj)
|
rb_get_path_no_checksafe(VALUE obj)
|
||||||
{
|
{
|
||||||
return rb_get_path_check(obj, 0);
|
return rb_get_path(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
VALUE
|
VALUE
|
||||||
rb_get_path(VALUE obj)
|
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
|
VALUE
|
||||||
|
@ -6290,13 +6276,14 @@ copy_path_class(VALUE path, VALUE orig)
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
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
|
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);
|
const char *f = StringValueCStr(*filep);
|
||||||
VALUE fname = *filep, load_path, tmp;
|
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] == '~') {
|
if (f[0] == '~') {
|
||||||
fname = file_expand_path_1(fname);
|
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);
|
f = RSTRING_PTR(fname);
|
||||||
*filep = fname;
|
*filep = fname;
|
||||||
expanded = 1;
|
expanded = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (expanded || rb_is_absolute_path(f) || is_explicit_relative(f)) {
|
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);
|
if (!expanded) fname = file_expand_path_1(fname);
|
||||||
fnlen = RSTRING_LEN(fname);
|
fnlen = RSTRING_LEN(fname);
|
||||||
for (i=0; ext[i]; i++) {
|
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++) {
|
for (i = 0; i < RARRAY_LEN(load_path); i++) {
|
||||||
VALUE str = RARRAY_AREF(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;
|
if (RSTRING_LEN(str) == 0) continue;
|
||||||
rb_file_expand_path_internal(fname, str, 0, 0, tmp);
|
rb_file_expand_path_internal(fname, str, 0, 0, tmp);
|
||||||
if (rb_file_load_ok(RSTRING_PTR(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
|
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
|
VALUE
|
||||||
rb_find_file_safe(VALUE path, int safe_level)
|
rb_find_file(VALUE path)
|
||||||
{
|
{
|
||||||
VALUE tmp, load_path;
|
VALUE tmp, load_path;
|
||||||
const char *f = StringValueCStr(path);
|
const char *f = StringValueCStr(path);
|
||||||
|
@ -6376,18 +6358,12 @@ rb_find_file_safe(VALUE path, int safe_level)
|
||||||
|
|
||||||
if (f[0] == '~') {
|
if (f[0] == '~') {
|
||||||
tmp = file_expand_path_1(path);
|
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);
|
path = copy_path_class(tmp, path);
|
||||||
f = RSTRING_PTR(path);
|
f = RSTRING_PTR(path);
|
||||||
expanded = 1;
|
expanded = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (expanded || rb_is_absolute_path(f) || is_explicit_relative(f)) {
|
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 (!rb_file_load_ok(f)) return 0;
|
||||||
if (!expanded)
|
if (!expanded)
|
||||||
path = copy_path_class(file_expand_path_1(path), path);
|
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());
|
rb_enc_associate_index(tmp, rb_usascii_encindex());
|
||||||
for (i = 0; i < RARRAY_LEN(load_path); i++) {
|
for (i = 0; i < RARRAY_LEN(load_path); i++) {
|
||||||
VALUE str = RARRAY_AREF(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) {
|
if (RSTRING_LEN(str) > 0) {
|
||||||
rb_file_expand_path_internal(path, str, 0, 0, tmp);
|
rb_file_expand_path_internal(path, str, 0, 0, tmp);
|
||||||
f = RSTRING_PTR(tmp);
|
f = RSTRING_PTR(tmp);
|
||||||
|
@ -6417,10 +6393,6 @@ rb_find_file_safe(VALUE path, int safe_level)
|
||||||
}
|
}
|
||||||
|
|
||||||
found:
|
found:
|
||||||
if (safe_level >= 1 && !fpath_check(tmp)) {
|
|
||||||
rb_raise(rb_eSecurityError, "loading from unsafe file %"PRIsVALUE, tmp);
|
|
||||||
}
|
|
||||||
|
|
||||||
return copy_path_class(tmp, path);
|
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;
|
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);
|
OBJ_FREEZE(block);
|
||||||
|
|
||||||
if (st_lookup(finalizer_table, obj, &data)) {
|
if (st_lookup(finalizer_table, obj, &data)) {
|
||||||
|
@ -3291,7 +3291,6 @@ run_single_final(VALUE final, VALUE objid)
|
||||||
const int level = OBJ_TAINTED(cmd) ?
|
const int level = OBJ_TAINTED(cmd) ?
|
||||||
RUBY_SAFE_LEVEL_MAX : FIX2INT(RARRAY_AREF(final, 0));
|
RUBY_SAFE_LEVEL_MAX : FIX2INT(RARRAY_AREF(final, 0));
|
||||||
|
|
||||||
rb_set_safe_level_force(level);
|
|
||||||
return rb_check_funcall(cmd, idCall, 1, &objid);
|
return rb_check_funcall(cmd, idCall, 1, &objid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3305,15 +3304,12 @@ run_finalizer(rb_objspace_t *objspace, VALUE obj, VALUE table)
|
||||||
VALUE objid;
|
VALUE objid;
|
||||||
rb_control_frame_t *cfp;
|
rb_control_frame_t *cfp;
|
||||||
long finished;
|
long finished;
|
||||||
int safe;
|
|
||||||
} saved;
|
} saved;
|
||||||
rb_execution_context_t * volatile ec = GET_EC();
|
rb_execution_context_t * volatile ec = GET_EC();
|
||||||
#define RESTORE_FINALIZER() (\
|
#define RESTORE_FINALIZER() (\
|
||||||
ec->cfp = saved.cfp, \
|
ec->cfp = saved.cfp, \
|
||||||
rb_set_safe_level_force(saved.safe), \
|
|
||||||
rb_set_errinfo(saved.errinfo))
|
rb_set_errinfo(saved.errinfo))
|
||||||
|
|
||||||
saved.safe = rb_safe_level();
|
|
||||||
saved.errinfo = rb_errinfo();
|
saved.errinfo = rb_errinfo();
|
||||||
saved.objid = rb_obj_id(obj);
|
saved.objid = rb_obj_id(obj);
|
||||||
saved.cfp = ec->cfp;
|
saved.cfp = ec->cfp;
|
||||||
|
@ -9389,10 +9385,8 @@ gc_set_initial_pages(void)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void
|
void
|
||||||
ruby_gc_set_params(int safe_level)
|
ruby_gc_set_params(void)
|
||||||
{
|
{
|
||||||
if (safe_level > 0) return;
|
|
||||||
|
|
||||||
/* RUBY_GC_HEAP_FREE_SLOTS */
|
/* RUBY_GC_HEAP_FREE_SLOTS */
|
||||||
if (get_envparam_size("RUBY_GC_HEAP_FREE_SLOTS", &gc_params.heap_free_slots, 0)) {
|
if (get_envparam_size("RUBY_GC_HEAP_FREE_SLOTS", &gc_params.heap_free_slots, 0)) {
|
||||||
/* ok */
|
/* ok */
|
||||||
|
|
2
hash.c
2
hash.c
|
@ -5719,7 +5719,6 @@ env_has_value(VALUE dmy, VALUE obj)
|
||||||
|
|
||||||
obj = rb_check_string_type(obj);
|
obj = rb_check_string_type(obj);
|
||||||
if (NIL_P(obj)) return Qnil;
|
if (NIL_P(obj)) return Qnil;
|
||||||
rb_check_safe_obj(obj);
|
|
||||||
env = GET_ENVIRON(environ);
|
env = GET_ENVIRON(environ);
|
||||||
while (*env) {
|
while (*env) {
|
||||||
char *s = strchr(*env, '=');
|
char *s = strchr(*env, '=');
|
||||||
|
@ -5750,7 +5749,6 @@ env_rassoc(VALUE dmy, VALUE obj)
|
||||||
|
|
||||||
obj = rb_check_string_type(obj);
|
obj = rb_check_string_type(obj);
|
||||||
if (NIL_P(obj)) return Qnil;
|
if (NIL_P(obj)) return Qnil;
|
||||||
rb_check_safe_obj(obj);
|
|
||||||
env = GET_ENVIRON(environ);
|
env = GET_ENVIRON(environ);
|
||||||
while (*env) {
|
while (*env) {
|
||||||
char *s = strchr(*env, '=');
|
char *s = strchr(*env, '=');
|
||||||
|
|
|
@ -459,7 +459,8 @@ int rb_provided(const char*);
|
||||||
int rb_feature_provided(const char *, const char **);
|
int rb_feature_provided(const char *, const char **);
|
||||||
void rb_provide(const char*);
|
void rb_provide(const char*);
|
||||||
VALUE rb_f_require(VALUE, VALUE);
|
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(VALUE, int, const VALUE*);
|
||||||
void rb_obj_call_init_kw(VALUE, int, const VALUE*, int);
|
void rb_obj_call_init_kw(VALUE, int, const VALUE*, int);
|
||||||
VALUE rb_class_new_instance(int, const VALUE*, VALUE);
|
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_s_absolute_path(int, const VALUE *);
|
||||||
VALUE rb_file_absolute_path(VALUE, VALUE);
|
VALUE rb_file_absolute_path(VALUE, VALUE);
|
||||||
VALUE rb_file_dirname(VALUE fname);
|
VALUE rb_file_dirname(VALUE fname);
|
||||||
int rb_find_file_ext_safe(VALUE*, const char* const*, int);
|
int rb_find_file_ext_safe(VALUE*, const char* const*, int); /* Remove in 3.0 */
|
||||||
VALUE rb_find_file_safe(VALUE, int);
|
VALUE rb_find_file_safe(VALUE, int); /* Remove in 3.0 */
|
||||||
int rb_find_file_ext(VALUE*, const char* const*);
|
int rb_find_file_ext(VALUE*, const char* const*);
|
||||||
VALUE rb_find_file(VALUE);
|
VALUE rb_find_file(VALUE);
|
||||||
VALUE rb_file_directory_p(VALUE,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))
|
#define StringValueCStr(v) rb_string_value_cstr(&(v))
|
||||||
|
|
||||||
void rb_check_safe_obj(VALUE);
|
void rb_check_safe_obj(VALUE);
|
||||||
#define SafeStringValue(v) do {\
|
#define SafeStringValue(v) StringValue(v)
|
||||||
StringValue(v);\
|
|
||||||
rb_check_safe_obj(v);\
|
|
||||||
} while (0)
|
|
||||||
#if GCC_VERSION_SINCE(4,4,0)
|
#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))
|
# define Check_SafeStr(v) rb_check_safe_str((VALUE)(v))
|
||||||
#else
|
#else
|
||||||
# define rb_check_safe_str(x) [<"rb_check_safe_str() 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 SafeStringValue() instead">]
|
# define Check_SafeStr(v) [<"Check_SafeStr() is obsolete; use StringValue() instead">]
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
VALUE rb_str_export(VALUE);
|
VALUE rb_str_export(VALUE);
|
||||||
#define ExportStringValue(v) do {\
|
#define ExportStringValue(v) do {\
|
||||||
SafeStringValue(v);\
|
StringValue(v);\
|
||||||
(v) = rb_str_export(v);\
|
(v) = rb_str_export(v);\
|
||||||
} while (0)
|
} while (0)
|
||||||
VALUE rb_str_export_locale(VALUE);
|
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))
|
#define FilePathValue(v) (RB_GC_GUARD(v) = rb_get_path(v))
|
||||||
|
|
||||||
VALUE rb_get_path_no_checksafe(VALUE);
|
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
|
#define RUBY_SAFE_LEVEL_MAX 1
|
||||||
void rb_secure(int);
|
void rb_secure(int);
|
||||||
int rb_safe_level(void);
|
int rb_safe_level(void);
|
||||||
|
|
|
@ -1570,9 +1570,8 @@ void rb_file_const(const char*, VALUE);
|
||||||
int rb_file_load_ok(const char *);
|
int rb_file_load_ok(const char *);
|
||||||
VALUE rb_file_expand_path_fast(VALUE, VALUE);
|
VALUE rb_file_expand_path_fast(VALUE, VALUE);
|
||||||
VALUE rb_file_expand_path_internal(VALUE, VALUE, int, int, 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_to_string(VALUE);
|
||||||
VALUE rb_get_path_check_convert(VALUE, VALUE, int);
|
VALUE rb_get_path_check_convert(VALUE);
|
||||||
VALUE rb_get_path_check(VALUE, int);
|
|
||||||
void Init_File(void);
|
void Init_File(void);
|
||||||
int ruby_is_fd_loadable(int fd);
|
int ruby_is_fd_loadable(int fd);
|
||||||
|
|
||||||
|
@ -1604,7 +1603,7 @@ void rb_gc_writebarrier_remember(VALUE obj);
|
||||||
#else
|
#else
|
||||||
#define rb_gc_writebarrier_remember(obj) 0
|
#define rb_gc_writebarrier_remember(obj) 0
|
||||||
#endif
|
#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);
|
void rb_copy_wb_protected_attribute(VALUE dest, VALUE obj);
|
||||||
|
|
||||||
#if defined(HAVE_MALLOC_USABLE_SIZE) || defined(HAVE_MALLOC_SIZE) || defined(_WIN32)
|
#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 */
|
/* load.c */
|
||||||
VALUE rb_get_expanded_load_path(void);
|
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*));
|
NORETURN(void rb_load_fail(VALUE, const char*));
|
||||||
|
|
||||||
/* loadpath.c */
|
/* loadpath.c */
|
||||||
|
|
3
io.c
3
io.c
|
@ -12839,9 +12839,6 @@ opt_i_get(ID id, VALUE *var)
|
||||||
static VALUE
|
static VALUE
|
||||||
argf_inplace_mode_set(VALUE argf, VALUE val)
|
argf_inplace_mode_set(VALUE argf, VALUE val)
|
||||||
{
|
{
|
||||||
if (rb_safe_level() >= 1 && OBJ_TAINTED(val))
|
|
||||||
rb_insecure_operation();
|
|
||||||
|
|
||||||
if (!RTEST(val)) {
|
if (!RTEST(val)) {
|
||||||
ARGF.inplace = Qfalse;
|
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;
|
VALUE src, file = Qnil, path = Qnil, line = INT2FIX(1), opt = Qnil;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
rb_secure(1);
|
|
||||||
|
|
||||||
i = rb_scan_args(argc, argv, "1*:", &src, NULL, &opt);
|
i = rb_scan_args(argc, argv, "1*:", &src, NULL, &opt);
|
||||||
if (i > 4+NIL_P(opt)) rb_error_arity(argc, 1, 5);
|
if (i > 4+NIL_P(opt)) rb_error_arity(argc, 1, 5);
|
||||||
switch (i) {
|
switch (i) {
|
||||||
|
@ -1225,7 +1223,6 @@ iseqw_s_compile_file(int argc, VALUE *argv, VALUE self)
|
||||||
rb_compile_option_t option;
|
rb_compile_option_t option;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
rb_secure(1);
|
|
||||||
i = rb_scan_args(argc, argv, "1*:", &file, NULL, &opt);
|
i = rb_scan_args(argc, argv, "1*:", &file, NULL, &opt);
|
||||||
if (i > 1+NIL_P(opt)) rb_error_arity(argc, 1, 2);
|
if (i > 1+NIL_P(opt)) rb_error_arity(argc, 1, 2);
|
||||||
switch (i) {
|
switch (i) {
|
||||||
|
@ -1292,7 +1289,6 @@ static VALUE
|
||||||
iseqw_s_compile_option_set(VALUE self, VALUE opt)
|
iseqw_s_compile_option_set(VALUE self, VALUE opt)
|
||||||
{
|
{
|
||||||
rb_compile_option_t option;
|
rb_compile_option_t option;
|
||||||
rb_secure(1);
|
|
||||||
make_compile_option(&option, opt);
|
make_compile_option(&option, opt);
|
||||||
COMPILE_OPTION_DEFAULT = option;
|
COMPILE_OPTION_DEFAULT = option;
|
||||||
return opt;
|
return opt;
|
||||||
|
@ -1344,7 +1340,6 @@ rb_iseqw_to_iseq(VALUE iseqw)
|
||||||
static VALUE
|
static VALUE
|
||||||
iseqw_eval(VALUE self)
|
iseqw_eval(VALUE self)
|
||||||
{
|
{
|
||||||
rb_secure(1);
|
|
||||||
return rb_iseq_eval(iseqw_check(self));
|
return rb_iseq_eval(iseqw_check(self));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1579,7 +1574,6 @@ static VALUE
|
||||||
iseqw_to_a(VALUE self)
|
iseqw_to_a(VALUE self)
|
||||||
{
|
{
|
||||||
const rb_iseq_t *iseq = iseqw_check(self);
|
const rb_iseq_t *iseq = iseqw_check(self);
|
||||||
rb_secure(1);
|
|
||||||
return iseq_data_to_ary(iseq);
|
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;
|
const char *indent_str;
|
||||||
long indent_len;
|
long indent_len;
|
||||||
|
|
||||||
rb_secure(1);
|
|
||||||
|
|
||||||
size = body->iseq_size;
|
size = body->iseq_size;
|
||||||
|
|
||||||
indent_len = RSTRING_LEN(indent);
|
indent_len = RSTRING_LEN(indent);
|
||||||
|
@ -2438,8 +2430,6 @@ iseqw_s_of(VALUE klass, VALUE body)
|
||||||
{
|
{
|
||||||
const rb_iseq_t *iseq = NULL;
|
const rb_iseq_t *iseq = NULL;
|
||||||
|
|
||||||
rb_secure(1);
|
|
||||||
|
|
||||||
if (rb_obj_is_proc(body)) {
|
if (rb_obj_is_proc(body)) {
|
||||||
iseq = vm_proc_iseq(body);
|
iseq = vm_proc_iseq(body);
|
||||||
|
|
||||||
|
|
|
@ -5,11 +5,6 @@
|
||||||
|
|
||||||
require 'continuation'
|
require 'continuation'
|
||||||
|
|
||||||
if $SAFE > 0
|
|
||||||
STDERR.print "-r debug.rb is not available in safe mode\n"
|
|
||||||
exit 1
|
|
||||||
end
|
|
||||||
|
|
||||||
require 'tracer'
|
require 'tracer'
|
||||||
require 'pp'
|
require 'pp'
|
||||||
|
|
||||||
|
|
|
@ -160,8 +160,6 @@ require_relative 'eq'
|
||||||
# # The object that handles requests on the server
|
# # The object that handles requests on the server
|
||||||
# FRONT_OBJECT=TimeServer.new
|
# FRONT_OBJECT=TimeServer.new
|
||||||
#
|
#
|
||||||
# $SAFE = 1 # disable eval() and friends
|
|
||||||
#
|
|
||||||
# DRb.start_service(URI, FRONT_OBJECT)
|
# DRb.start_service(URI, FRONT_OBJECT)
|
||||||
# # Wait for the drb server thread to finish before exiting.
|
# # Wait for the drb server thread to finish before exiting.
|
||||||
# DRb.thread.join
|
# DRb.thread.join
|
||||||
|
@ -245,8 +243,6 @@ require_relative 'eq'
|
||||||
#
|
#
|
||||||
# FRONT_OBJECT=LoggerFactory.new("/tmp/dlog")
|
# FRONT_OBJECT=LoggerFactory.new("/tmp/dlog")
|
||||||
#
|
#
|
||||||
# $SAFE = 1 # disable eval() and friends
|
|
||||||
#
|
|
||||||
# DRb.start_service(URI, FRONT_OBJECT)
|
# DRb.start_service(URI, FRONT_OBJECT)
|
||||||
# DRb.thread.join
|
# DRb.thread.join
|
||||||
#
|
#
|
||||||
|
@ -286,10 +282,7 @@ require_relative 'eq'
|
||||||
# ro.instance_eval("`rm -rf *`")
|
# ro.instance_eval("`rm -rf *`")
|
||||||
#
|
#
|
||||||
# The dangers posed by instance_eval and friends are such that a
|
# The dangers posed by instance_eval and friends are such that a
|
||||||
# DRbServer should generally be run with $SAFE set to at least
|
# DRbServer should only be used when clients are trusted.
|
||||||
# level 1. This will disable eval() and related calls on strings
|
|
||||||
# passed across the wire. The sample usage code given above follows
|
|
||||||
# this practice.
|
|
||||||
#
|
#
|
||||||
# A DRbServer can be configured with an access control list to
|
# A DRbServer can be configured with an access control list to
|
||||||
# selectively allow or deny access from specified IP addresses. The
|
# selectively allow or deny access from specified IP addresses. The
|
||||||
|
@ -1362,7 +1355,6 @@ module DRb
|
||||||
@@argc_limit = 256
|
@@argc_limit = 256
|
||||||
@@load_limit = 0xffffffff
|
@@load_limit = 0xffffffff
|
||||||
@@verbose = false
|
@@verbose = false
|
||||||
@@safe_level = 0
|
|
||||||
|
|
||||||
# Set the default value for the :argc_limit option.
|
# Set the default value for the :argc_limit option.
|
||||||
#
|
#
|
||||||
|
@ -1392,11 +1384,8 @@ module DRb
|
||||||
@@idconv = idconv
|
@@idconv = idconv
|
||||||
end
|
end
|
||||||
|
|
||||||
# Set the default safe level to +level+. The default safe level is 0
|
def self.default_safe_level(level) # :nodoc:
|
||||||
#
|
# Remove in Ruby 3.0
|
||||||
# See #new for more information.
|
|
||||||
def self.default_safe_level(level)
|
|
||||||
@@safe_level = level
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Set the default value of the :verbose option.
|
# Set the default value of the :verbose option.
|
||||||
|
@ -1418,7 +1407,6 @@ module DRb
|
||||||
:tcp_acl => @@acl,
|
:tcp_acl => @@acl,
|
||||||
:load_limit => @@load_limit,
|
:load_limit => @@load_limit,
|
||||||
:argc_limit => @@argc_limit,
|
:argc_limit => @@argc_limit,
|
||||||
:safe_level => @@safe_level
|
|
||||||
}
|
}
|
||||||
default_config.update(hash)
|
default_config.update(hash)
|
||||||
end
|
end
|
||||||
|
@ -1452,10 +1440,6 @@ module DRb
|
||||||
# :argc_limit :: the maximum number of arguments to a remote
|
# :argc_limit :: the maximum number of arguments to a remote
|
||||||
# method accepted by the server. Defaults to
|
# method accepted by the server. Defaults to
|
||||||
# 256.
|
# 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
|
# The default values of these options can be modified on
|
||||||
# a class-wide basis by the class methods #default_argc_limit,
|
# a class-wide basis by the class methods #default_argc_limit,
|
||||||
# #default_load_limit, #default_acl, #default_id_conv,
|
# #default_load_limit, #default_acl, #default_id_conv,
|
||||||
|
@ -1487,7 +1471,6 @@ module DRb
|
||||||
|
|
||||||
@front = front
|
@front = front
|
||||||
@idconv = @config[:idconv]
|
@idconv = @config[:idconv]
|
||||||
@safe_level = @config[:safe_level]
|
|
||||||
|
|
||||||
@grp = ThreadGroup.new
|
@grp = ThreadGroup.new
|
||||||
@thread = run
|
@thread = run
|
||||||
|
@ -1514,11 +1497,10 @@ module DRb
|
||||||
# The configuration of this DRbServer
|
# The configuration of this DRbServer
|
||||||
attr_reader :config
|
attr_reader :config
|
||||||
|
|
||||||
# The safe level for this server. This is a number corresponding to
|
def safe_level # :nodoc:
|
||||||
# $SAFE.
|
# Remove in Ruby 3.0
|
||||||
#
|
0
|
||||||
# The default safe_level is 0
|
end
|
||||||
attr_reader :safe_level
|
|
||||||
|
|
||||||
# Set whether to operate in verbose mode.
|
# Set whether to operate in verbose mode.
|
||||||
#
|
#
|
||||||
|
@ -1652,7 +1634,6 @@ module DRb
|
||||||
class InvokeMethod # :nodoc:
|
class InvokeMethod # :nodoc:
|
||||||
def initialize(drb_server, client)
|
def initialize(drb_server, client)
|
||||||
@drb_server = drb_server
|
@drb_server = drb_server
|
||||||
@safe_level = drb_server.safe_level
|
|
||||||
@client = client
|
@client = client
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -1661,33 +1642,10 @@ module DRb
|
||||||
@succ = false
|
@succ = false
|
||||||
setup_message
|
setup_message
|
||||||
|
|
||||||
if $SAFE < @safe_level
|
if @block
|
||||||
info = Thread.current['DRb']
|
@result = perform_with_block
|
||||||
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
|
|
||||||
else
|
else
|
||||||
if @block
|
@result = perform_without_block
|
||||||
@result = perform_with_block
|
|
||||||
else
|
|
||||||
@result = perform_without_block
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
@succ = true
|
@succ = true
|
||||||
case @result
|
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:
|
# There are several settings you can change when you use ERB:
|
||||||
# * the nature of the tags that are recognized;
|
# * 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.
|
# * the binding used to resolve local variables in the template.
|
||||||
#
|
#
|
||||||
# See the ERB.new and ERB#result methods for more detail.
|
# 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_.
|
# 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
|
# 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,
|
# the completed template when run.
|
||||||
# ERB code will be run in a separate thread with <b>$SAFE</b> set to the
|
|
||||||
# provided level.
|
|
||||||
#
|
#
|
||||||
# If _trim_mode_ is passed a String containing one or more of the following
|
# If _trim_mode_ is passed a String containing one or more of the following
|
||||||
# modifiers, ERB will adjust its code generation as listed:
|
# 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.
|
# Complex initializer for $SAFE deprecation at [Feature #14256]. Use keyword arguments to pass trim_mode or eoutvar.
|
||||||
if safe_level != NOT_GIVEN
|
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)
|
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
|
end
|
||||||
if legacy_trim_mode != NOT_GIVEN
|
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
|
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
|
eoutvar = legacy_eoutvar
|
||||||
end
|
end
|
||||||
|
|
||||||
@safe_level = safe_level
|
|
||||||
compiler = make_compiler(trim_mode)
|
compiler = make_compiler(trim_mode)
|
||||||
set_eoutvar(compiler, eoutvar)
|
set_eoutvar(compiler, eoutvar)
|
||||||
@src, @encoding, @frozen_string = *compiler.compile(str)
|
@src, @encoding, @frozen_string = *compiler.compile(str)
|
||||||
|
@ -908,17 +902,7 @@ class ERB
|
||||||
unless @_init.equal?(self.class.singleton_class)
|
unless @_init.equal?(self.class.singleton_class)
|
||||||
raise ArgumentError, "not initialized"
|
raise ArgumentError, "not initialized"
|
||||||
end
|
end
|
||||||
if @safe_level
|
eval(@src, b, (@filename || '(erb)'), @lineno)
|
||||||
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
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Render a template on a new toplevel binding with local variables specified
|
# Render a template on a new toplevel binding with local variables specified
|
||||||
|
|
|
@ -831,9 +831,6 @@ module Net
|
||||||
end
|
end
|
||||||
|
|
||||||
def mailfrom(from_addr)
|
def mailfrom(from_addr)
|
||||||
if $SAFE > 0
|
|
||||||
raise SecurityError, 'tainted from_addr' if from_addr.tainted?
|
|
||||||
end
|
|
||||||
getok("MAIL FROM:<#{from_addr}>")
|
getok("MAIL FROM:<#{from_addr}>")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -859,9 +856,6 @@ module Net
|
||||||
end
|
end
|
||||||
|
|
||||||
def rcptto(to_addr)
|
def rcptto(to_addr)
|
||||||
if $SAFE > 0
|
|
||||||
raise SecurityError, 'tainted to_addr' if to_addr.tainted?
|
|
||||||
end
|
|
||||||
getok("RCPT TO:<#{to_addr}>")
|
getok("RCPT TO:<#{to_addr}>")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -98,10 +98,6 @@ class Tempfile < DelegateClass(File)
|
||||||
#
|
#
|
||||||
# The temporary file will be placed in the directory as specified
|
# The temporary file will be placed in the directory as specified
|
||||||
# by the +tmpdir+ parameter. By default, this is +Dir.tmpdir+.
|
# 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 = Tempfile.new('hello', '/home/aisaka')
|
||||||
# file.path # => something like: "/home/aisaka/hello2843-8392-92849382--0"
|
# file.path # => something like: "/home/aisaka/hello2843-8392-92849382--0"
|
||||||
|
|
|
@ -19,22 +19,18 @@ class Dir
|
||||||
# Returns the operating system's temporary file path.
|
# Returns the operating system's temporary file path.
|
||||||
|
|
||||||
def self.tmpdir
|
def self.tmpdir
|
||||||
if $SAFE > 0
|
tmp = nil
|
||||||
@@systmpdir.dup
|
[ENV['TMPDIR'], ENV['TMP'], ENV['TEMP'], @@systmpdir, '/tmp', '.'].each do |dir|
|
||||||
else
|
next if !dir
|
||||||
tmp = nil
|
dir = File.expand_path(dir)
|
||||||
[ENV['TMPDIR'], ENV['TMP'], ENV['TEMP'], @@systmpdir, '/tmp', '.'].each do |dir|
|
if stat = File.stat(dir) and stat.directory? and stat.writable? and
|
||||||
next if !dir
|
(!stat.world_writable? or stat.sticky?)
|
||||||
dir = File.expand_path(dir)
|
tmp = dir
|
||||||
if stat = File.stat(dir) and stat.directory? and stat.writable? and
|
break
|
||||||
(!stat.world_writable? or stat.sticky?)
|
end rescue nil
|
||||||
tmp = dir
|
|
||||||
break
|
|
||||||
end rescue nil
|
|
||||||
end
|
|
||||||
raise ArgumentError, "could not find a temporary directory" unless tmp
|
|
||||||
tmp
|
|
||||||
end
|
end
|
||||||
|
raise ArgumentError, "could not find a temporary directory" unless tmp
|
||||||
|
tmp
|
||||||
end
|
end
|
||||||
|
|
||||||
# Dir.mktmpdir creates a temporary directory.
|
# 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
|
UNUSABLE_CHARS = [File::SEPARATOR, File::ALT_SEPARATOR, File::PATH_SEPARATOR, ":"].uniq.join("").freeze
|
||||||
|
|
||||||
def create(basename, tmpdir=nil, max_try: nil, **opts)
|
def create(basename, tmpdir=nil, max_try: nil, **opts)
|
||||||
if $SAFE > 0 and tmpdir.tainted?
|
origdir = tmpdir
|
||||||
tmpdir = '/tmp'
|
tmpdir ||= tmpdir()
|
||||||
else
|
|
||||||
origdir = tmpdir
|
|
||||||
tmpdir ||= tmpdir()
|
|
||||||
end
|
|
||||||
n = nil
|
n = nil
|
||||||
prefix, suffix = basename
|
prefix, suffix = basename
|
||||||
prefix = (String.try_convert(prefix) or
|
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 expanded_load_path = vm->expanded_load_path;
|
||||||
VALUE ary;
|
VALUE ary;
|
||||||
long i;
|
long i;
|
||||||
int level = rb_safe_level();
|
|
||||||
|
|
||||||
ary = rb_ary_tmp_new(RARRAY_LEN(load_path));
|
ary = rb_ary_tmp_new(RARRAY_LEN(load_path));
|
||||||
for (i = 0; i < RARRAY_LEN(load_path); ++i) {
|
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);
|
as_str = path = RARRAY_AREF(load_path, i);
|
||||||
is_string = RB_TYPE_P(path, T_STRING) ? 1 : 0;
|
is_string = RB_TYPE_P(path, T_STRING) ? 1 : 0;
|
||||||
non_cache = !is_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);
|
as_cstr = RSTRING_PTR(as_str);
|
||||||
|
|
||||||
if (!non_cache) {
|
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. */
|
/* Freeze only string object. We expand other objects every time. */
|
||||||
if (is_string)
|
if (is_string)
|
||||||
rb_str_freeze(path);
|
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);
|
expanded_path = rb_check_realpath(Qnil, as_str);
|
||||||
if (NIL_P(expanded_path)) expanded_path = as_str;
|
if (NIL_P(expanded_path)) expanded_path = as_str;
|
||||||
rb_ary_push(ary, rb_fstring(expanded_path));
|
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);
|
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);
|
fname = rb_str_encode_ospath(orig_fname);
|
||||||
RUBY_DTRACE_HOOK(LOAD_ENTRY, RSTRING_PTR(orig_fname));
|
RUBY_DTRACE_HOOK(LOAD_ENTRY, RSTRING_PTR(orig_fname));
|
||||||
|
|
||||||
|
@ -809,7 +808,7 @@ load_unlock(const char *ftptr, int done)
|
||||||
VALUE
|
VALUE
|
||||||
rb_f_require(VALUE obj, VALUE fname)
|
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");
|
rb_loaderror("cannot infer basepath");
|
||||||
}
|
}
|
||||||
base = rb_file_dirname(base);
|
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);
|
typedef int (*feature_func)(const char *feature, const char *ext, int rb, int expanded, const char **fn);
|
||||||
|
|
||||||
static int
|
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;
|
VALUE tmp;
|
||||||
char *ext, *ftptr;
|
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);
|
if (loading) *path = rb_filesystem_str_new_cstr(loading);
|
||||||
return 'r';
|
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), '.');
|
ext = strrchr(ftptr = RSTRING_PTR(tmp), '.');
|
||||||
if (!rb_feature_p(ftptr, ext, TRUE, TRUE, &loading) || loading)
|
if (!rb_feature_p(ftptr, ext, TRUE, TRUE, &loading) || loading)
|
||||||
*path = tmp;
|
*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));
|
tmp = rb_str_subseq(fname, 0, ext - RSTRING_PTR(fname));
|
||||||
#ifdef DLEXT2
|
#ifdef DLEXT2
|
||||||
OBJ_FREEZE(tmp);
|
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), '.');
|
ext = strrchr(ftptr = RSTRING_PTR(tmp), '.');
|
||||||
if (!rb_feature_p(ftptr, ext, FALSE, TRUE, &loading) || loading)
|
if (!rb_feature_p(ftptr, ext, FALSE, TRUE, &loading) || loading)
|
||||||
*path = tmp;
|
*path = tmp;
|
||||||
|
@ -874,7 +873,7 @@ search_required(VALUE fname, volatile VALUE *path, int safe_level, feature_func
|
||||||
#else
|
#else
|
||||||
rb_str_cat2(tmp, DLEXT);
|
rb_str_cat2(tmp, DLEXT);
|
||||||
OBJ_FREEZE(tmp);
|
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), '.');
|
ext = strrchr(ftptr = RSTRING_PTR(tmp), '.');
|
||||||
if (!rb_feature_p(ftptr, ext, FALSE, TRUE, &loading) || loading)
|
if (!rb_feature_p(ftptr, ext, FALSE, TRUE, &loading) || loading)
|
||||||
*path = tmp;
|
*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);
|
if (loading) *path = rb_filesystem_str_new_cstr(loading);
|
||||||
return 's';
|
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), '.');
|
ext = strrchr(ftptr = RSTRING_PTR(tmp), '.');
|
||||||
if (!rb_feature_p(ftptr, ext, FALSE, TRUE, &loading) || loading)
|
if (!rb_feature_p(ftptr, ext, FALSE, TRUE, &loading) || loading)
|
||||||
*path = tmp;
|
*path = tmp;
|
||||||
|
@ -900,7 +899,7 @@ search_required(VALUE fname, volatile VALUE *path, int safe_level, feature_func
|
||||||
return 'r';
|
return 'r';
|
||||||
}
|
}
|
||||||
tmp = fname;
|
tmp = fname;
|
||||||
type = rb_find_file_ext_safe(&tmp, loadable_ext, safe_level);
|
type = rb_find_file_ext(&tmp, loadable_ext);
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 0:
|
case 0:
|
||||||
if (ft)
|
if (ft)
|
||||||
|
@ -951,9 +950,9 @@ rb_resolve_feature_path(VALUE klass, VALUE fname)
|
||||||
int found;
|
int found;
|
||||||
VALUE sym;
|
VALUE sym;
|
||||||
|
|
||||||
fname = rb_get_path_check(fname, 0);
|
fname = rb_get_path(fname);
|
||||||
path = rb_str_encode_ospath(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) {
|
switch (found) {
|
||||||
case 'r':
|
case 'r':
|
||||||
|
@ -977,7 +976,7 @@ rb_resolve_feature_path(VALUE klass, VALUE fname)
|
||||||
* >1: exception
|
* >1: exception
|
||||||
*/
|
*/
|
||||||
static int
|
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;
|
volatile int result = -1;
|
||||||
rb_thread_t *th = rb_ec_thread_ptr(ec);
|
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 self = th->top_self;
|
||||||
volatile VALUE errinfo = ec->errinfo;
|
volatile VALUE errinfo = ec->errinfo;
|
||||||
enum ruby_tag_type state;
|
enum ruby_tag_type state;
|
||||||
struct {
|
|
||||||
int safe;
|
|
||||||
} volatile saved;
|
|
||||||
char *volatile ftptr = 0;
|
char *volatile ftptr = 0;
|
||||||
VALUE path;
|
VALUE path;
|
||||||
|
|
||||||
fname = rb_get_path_check(fname, safe);
|
fname = rb_get_path(fname);
|
||||||
path = rb_str_encode_ospath(fname);
|
path = rb_str_encode_ospath(fname);
|
||||||
RUBY_DTRACE_HOOK(REQUIRE_ENTRY, RSTRING_PTR(fname));
|
RUBY_DTRACE_HOOK(REQUIRE_ENTRY, RSTRING_PTR(fname));
|
||||||
|
|
||||||
EC_PUSH_TAG(ec);
|
EC_PUSH_TAG(ec);
|
||||||
saved.safe = rb_safe_level();
|
|
||||||
ec->errinfo = Qnil; /* ensure */
|
ec->errinfo = Qnil; /* ensure */
|
||||||
th->top_wrapper = 0;
|
th->top_wrapper = 0;
|
||||||
if ((state = EC_EXEC_TAG()) == TAG_NONE) {
|
if ((state = EC_EXEC_TAG()) == TAG_NONE) {
|
||||||
long handle;
|
long handle;
|
||||||
int found;
|
int found;
|
||||||
|
|
||||||
rb_set_safe_level_force(0);
|
|
||||||
|
|
||||||
RUBY_DTRACE_HOOK(FIND_REQUIRE_ENTRY, RSTRING_PTR(fname));
|
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));
|
RUBY_DTRACE_HOOK(FIND_REQUIRE_RETURN, RSTRING_PTR(fname));
|
||||||
|
|
||||||
if (found) {
|
if (found) {
|
||||||
|
@ -1040,7 +1033,6 @@ require_internal(rb_execution_context_t *ec, VALUE fname, int safe, int exceptio
|
||||||
th->top_wrapper = wrapper;
|
th->top_wrapper = wrapper;
|
||||||
if (ftptr) load_unlock(RSTRING_PTR(path), !state);
|
if (ftptr) load_unlock(RSTRING_PTR(path), !state);
|
||||||
|
|
||||||
rb_set_safe_level_force(saved.safe);
|
|
||||||
if (state) {
|
if (state) {
|
||||||
if (exception) {
|
if (exception) {
|
||||||
/* usually state == TAG_RAISE only, except for
|
/* 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
|
int
|
||||||
rb_require_internal(VALUE fname, int safe)
|
rb_require_internal(VALUE fname)
|
||||||
{
|
{
|
||||||
rb_execution_context_t *ec = GET_EC();
|
rb_execution_context_t *ec = GET_EC();
|
||||||
return require_internal(ec, fname, safe, 1);
|
return require_internal(ec, fname, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
@ -1081,7 +1073,7 @@ ruby_require_internal(const char *fname, unsigned int len)
|
||||||
struct RString fake;
|
struct RString fake;
|
||||||
VALUE str = rb_setup_fake_str(&fake, fname, len, 0);
|
VALUE str = rb_setup_fake_str(&fake, fname, len, 0);
|
||||||
rb_execution_context_t *ec = GET_EC();
|
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);
|
rb_set_errinfo(Qnil);
|
||||||
return result == TAG_RETURN ? 1 : result ? -1 : 0;
|
return result == TAG_RETURN ? 1 : result ? -1 : 0;
|
||||||
}
|
}
|
||||||
|
@ -1089,8 +1081,25 @@ ruby_require_internal(const char *fname, unsigned int len)
|
||||||
VALUE
|
VALUE
|
||||||
rb_require_safe(VALUE fname, int safe)
|
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();
|
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) {
|
if (result > TAG_RETURN) {
|
||||||
EC_JUMP_TAG(ec, result);
|
EC_JUMP_TAG(ec, result);
|
||||||
|
@ -1105,8 +1114,7 @@ rb_require_safe(VALUE fname, int safe)
|
||||||
VALUE
|
VALUE
|
||||||
rb_require(const char *fname)
|
rb_require(const char *fname)
|
||||||
{
|
{
|
||||||
VALUE fn = rb_str_new_cstr(fname);
|
return rb_require_string(rb_str_new_cstr(fname));
|
||||||
return rb_require_safe(fn, rb_safe_level());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
|
2
parse.y
2
parse.y
|
@ -5902,7 +5902,7 @@ yycompile0(VALUE arg)
|
||||||
struct parser_params *p = (struct parser_params *)arg;
|
struct parser_params *p = (struct parser_params *)arg;
|
||||||
VALUE cov = Qfalse;
|
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);
|
p->debug_lines = debug_lines(p->ruby_sourcefile_string);
|
||||||
if (p->debug_lines && p->ruby_sourceline > 0) {
|
if (p->debug_lines && p->ruby_sourceline > 0) {
|
||||||
VALUE str = STR_NEW0();
|
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);
|
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
|
VALUE
|
||||||
rb_method_call_with_block_kw(int argc, const VALUE *argv, VALUE method, VALUE passed_procval, int kw_splat)
|
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) {
|
if (data->recv == Qundef) {
|
||||||
rb_raise(rb_eTypeError, "can't call unbound method; bind first");
|
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);
|
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"
|
#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)
|
#if defined(HAVE_WORKING_FORK)
|
||||||
|
|
||||||
/* try_with_sh and exec_with_sh should be async-signal-safe. Actually it is.*/
|
/* 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)
|
if (!prog)
|
||||||
prog = argv[0];
|
prog = argv[0];
|
||||||
security(prog);
|
|
||||||
prog = dln_find_exe_r(prog, 0, fbuf, sizeof(fbuf));
|
prog = dln_find_exe_r(prog, 0, fbuf, sizeof(fbuf));
|
||||||
if (!prog)
|
if (!prog)
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -2371,7 +2360,6 @@ rb_check_argv(int argc, VALUE *argv)
|
||||||
argv[i] = rb_str_new_frozen(argv[i]);
|
argv[i] = rb_str_new_frozen(argv[i]);
|
||||||
StringValueCStr(argv[i]);
|
StringValueCStr(argv[i]);
|
||||||
}
|
}
|
||||||
security(name ? name : RSTRING_PTR(argv[0]));
|
|
||||||
return prog;
|
return prog;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
54
ruby.c
54
ruby.c
|
@ -162,7 +162,6 @@ struct ruby_cmdline_options {
|
||||||
#if USE_MJIT
|
#if USE_MJIT
|
||||||
struct mjit_options mjit;
|
struct mjit_options mjit;
|
||||||
#endif
|
#endif
|
||||||
int safe_level;
|
|
||||||
int sflag, xflag;
|
int sflag, xflag;
|
||||||
unsigned int warning: 1;
|
unsigned int warning: 1;
|
||||||
unsigned int verbose: 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("-rlibrary", "", "require the library before executing your script"),
|
||||||
M("-s", "", "enable some switch parsing for switches after script name"),
|
M("-s", "", "enable some switch parsing for switches after script name"),
|
||||||
M("-S", "", "look for the script using PATH environment variable"),
|
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("-v", "", "print the version number, then turn on verbose mode"),
|
||||||
M("-w", "", "turn warnings on for your script"),
|
M("-w", "", "turn warnings on for your script"),
|
||||||
M("-W[level=2]", "", "set warning level; 0=silence, 1=medium, 2=verbose"),
|
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)
|
# define str_conv_enc(str, from, to) (str)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void ruby_init_loadpath_safe(int safe_level);
|
void ruby_init_loadpath(void);
|
||||||
|
|
||||||
void
|
|
||||||
ruby_init_loadpath(void)
|
|
||||||
{
|
|
||||||
ruby_init_loadpath_safe(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(LOAD_RELATIVE)
|
#if defined(LOAD_RELATIVE)
|
||||||
static VALUE
|
static VALUE
|
||||||
|
@ -576,7 +568,7 @@ runtime_libruby_path(void)
|
||||||
VALUE ruby_archlibdir_path, ruby_prefix_path;
|
VALUE ruby_archlibdir_path, ruby_prefix_path;
|
||||||
|
|
||||||
void
|
void
|
||||||
ruby_init_loadpath_safe(int safe_level)
|
ruby_init_loadpath(void)
|
||||||
{
|
{
|
||||||
VALUE load_path, archlibdir = 0;
|
VALUE load_path, archlibdir = 0;
|
||||||
ID id_initial_load_path_mark;
|
ID id_initial_load_path_mark;
|
||||||
|
@ -659,9 +651,7 @@ ruby_init_loadpath_safe(int safe_level)
|
||||||
|
|
||||||
load_path = GET_VM()->load_path;
|
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;
|
id_initial_load_path_mark = INITIAL_LOAD_PATH_MARK;
|
||||||
while (*paths) {
|
while (*paths) {
|
||||||
|
@ -1225,18 +1215,18 @@ proc_options(long argc, char **argv, ruby_cmdline_options_t *opt, int envopt)
|
||||||
goto reswitch;
|
goto reswitch;
|
||||||
|
|
||||||
case 'T':
|
case 'T':
|
||||||
{
|
{
|
||||||
size_t numlen;
|
size_t numlen;
|
||||||
int v = 1;
|
int v = 1;
|
||||||
|
|
||||||
if (*++s) {
|
if (*++s) {
|
||||||
v = scan_oct(s, 2, &numlen);
|
v = scan_oct(s, 2, &numlen);
|
||||||
if (numlen == 0)
|
if (numlen == 0)
|
||||||
v = 1;
|
v = 1;
|
||||||
s += numlen;
|
s += numlen;
|
||||||
}
|
}
|
||||||
if (v > opt->safe_level) opt->safe_level = v;
|
}
|
||||||
}
|
rb_warn("ruby -T will be removed in Ruby 3.0");
|
||||||
goto reswitch;
|
goto reswitch;
|
||||||
|
|
||||||
case 'I':
|
case 'I':
|
||||||
|
@ -1576,8 +1566,7 @@ process_options(int argc, char **argv, ruby_cmdline_options_t *opt)
|
||||||
argc -= i;
|
argc -= i;
|
||||||
argv += i;
|
argv += i;
|
||||||
|
|
||||||
if ((opt->features.set & FEATURE_BIT(rubyopt)) &&
|
if ((opt->features.set & FEATURE_BIT(rubyopt)) && (s = getenv("RUBYOPT"))) {
|
||||||
opt->safe_level == 0 && (s = getenv("RUBYOPT"))) {
|
|
||||||
VALUE src_enc_name = opt->src.enc.name;
|
VALUE src_enc_name = opt->src.enc.name;
|
||||||
VALUE ext_enc_name = opt->ext.enc.name;
|
VALUE ext_enc_name = opt->ext.enc.name;
|
||||||
VALUE int_enc_name = opt->intern.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), '\\', '/');
|
translit_char(RSTRING_PTR(opt->script_name), '\\', '/');
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
ruby_gc_set_params(opt->safe_level);
|
ruby_gc_set_params();
|
||||||
ruby_init_loadpath_safe(opt->safe_level);
|
ruby_init_loadpath();
|
||||||
|
|
||||||
#if USE_MJIT
|
#if USE_MJIT
|
||||||
if (opt->mjit.on)
|
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);
|
mjit_init(&opt->mjit);
|
||||||
#endif
|
#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_gc_register_mark_object(opt->e_script);
|
||||||
}
|
}
|
||||||
|
|
||||||
rb_set_safe_level(opt->safe_level);
|
|
||||||
|
|
||||||
{
|
{
|
||||||
rb_execution_context_t *ec = GET_EC();
|
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 (uid != euid) opt->setids |= 1;
|
||||||
if (egid != gid) opt->setids |= 2;
|
if (egid != gid) opt->setids |= 2;
|
||||||
if (uid && opt->setids) {
|
|
||||||
if (opt->safe_level < 1) opt->safe_level = 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#undef forbid_setid
|
#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);
|
rb_raise(rb_eSecurityError, "no %s allowed while running setuid", s);
|
||||||
if (opt->setids & 2)
|
if (opt->setids & 2)
|
||||||
rb_raise(rb_eSecurityError, "no %s allowed while running setgid", s);
|
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
|
static void
|
||||||
|
|
36
safe.c
36
safe.c
|
@ -28,18 +28,21 @@
|
||||||
int
|
int
|
||||||
ruby_safe_level_2_warning(void)
|
ruby_safe_level_2_warning(void)
|
||||||
{
|
{
|
||||||
|
rb_warn("rb_safe_level_2_warning will be removed in Ruby 3.0");
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
rb_safe_level(void)
|
rb_safe_level(void)
|
||||||
{
|
{
|
||||||
|
rb_warn("rb_safe_level will be removed in Ruby 3.0");
|
||||||
return GET_VM()->safe_level_;
|
return GET_VM()->safe_level_;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
rb_set_safe_level_force(int safe)
|
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;
|
GET_VM()->safe_level_ = safe;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,6 +51,7 @@ rb_set_safe_level(int level)
|
||||||
{
|
{
|
||||||
rb_vm_t *vm = GET_VM();
|
rb_vm_t *vm = GET_VM();
|
||||||
|
|
||||||
|
rb_warn("rb_set_safe_level will be removed in Ruby 3.0");
|
||||||
if (level > SAFE_LEVEL_MAX) {
|
if (level > SAFE_LEVEL_MAX) {
|
||||||
rb_raise(rb_eArgError, "$SAFE=2 to 4 are obsolete");
|
rb_raise(rb_eArgError, "$SAFE=2 to 4 are obsolete");
|
||||||
}
|
}
|
||||||
|
@ -68,28 +72,47 @@ rb_set_safe_level(int level)
|
||||||
static VALUE
|
static VALUE
|
||||||
safe_getter(ID _x, VALUE *_y)
|
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
|
static void
|
||||||
safe_setter(VALUE val, ID _x, VALUE *_y)
|
safe_setter(VALUE val, ID _x, VALUE *_y)
|
||||||
{
|
{
|
||||||
int level = NUM2INT(val);
|
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
|
void
|
||||||
rb_secure(int level)
|
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();
|
ID caller_name = rb_frame_callee();
|
||||||
if (caller_name) {
|
if (caller_name) {
|
||||||
rb_raise(rb_eSecurityError, "Insecure operation `%"PRIsVALUE"' at level %d",
|
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 {
|
else {
|
||||||
rb_raise(rb_eSecurityError, "Insecure operation at level %d",
|
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
|
void
|
||||||
rb_secure_update(VALUE obj)
|
rb_secure_update(VALUE obj)
|
||||||
{
|
{
|
||||||
|
rb_warn("rb_secure_update will be removed in Ruby 3.0");
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
rb_insecure_operation(void)
|
rb_insecure_operation(void)
|
||||||
{
|
{
|
||||||
|
rb_warn("rb_insecure_operation will be removed in Ruby 3.0");
|
||||||
ID caller_name = rb_frame_callee();
|
ID caller_name = rb_frame_callee();
|
||||||
if (caller_name) {
|
if (caller_name) {
|
||||||
rb_raise(rb_eSecurityError, "Insecure operation - %"PRIsVALUE,
|
rb_raise(rb_eSecurityError, "Insecure operation - %"PRIsVALUE,
|
||||||
|
@ -115,6 +140,7 @@ rb_insecure_operation(void)
|
||||||
void
|
void
|
||||||
rb_check_safe_obj(VALUE x)
|
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)) {
|
if (rb_safe_level() > 0 && OBJ_TAINTED(x)) {
|
||||||
rb_insecure_operation();
|
rb_insecure_operation();
|
||||||
}
|
}
|
||||||
|
|
10
signal.c
10
signal.c
|
@ -1024,7 +1024,7 @@ sig_do_nothing(int sig)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static int
|
static int
|
||||||
signal_exec(VALUE cmd, int safe, int sig)
|
signal_exec(VALUE cmd, int sig)
|
||||||
{
|
{
|
||||||
rb_execution_context_t *ec = GET_EC();
|
rb_execution_context_t *ec = GET_EC();
|
||||||
volatile rb_atomic_t old_interrupt_mask = ec->interrupt_mask;
|
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);
|
EC_PUSH_TAG(ec);
|
||||||
if ((state = EC_EXEC_TAG()) == TAG_NONE) {
|
if ((state = EC_EXEC_TAG()) == TAG_NONE) {
|
||||||
VALUE signum = INT2NUM(sig);
|
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_POP_TAG();
|
||||||
ec = GET_EC();
|
ec = GET_EC();
|
||||||
|
@ -1063,7 +1063,7 @@ rb_vm_trap_exit(rb_vm_t *vm)
|
||||||
|
|
||||||
if (trap_exit) {
|
if (trap_exit) {
|
||||||
vm->trap_list.cmd[0] = 0;
|
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();
|
rb_vm_t *vm = GET_VM();
|
||||||
VALUE cmd = vm->trap_list.cmd[sig];
|
VALUE cmd = vm->trap_list.cmd[sig];
|
||||||
int safe = vm->trap_list.safe[sig];
|
|
||||||
|
|
||||||
if (cmd == 0) {
|
if (cmd == 0) {
|
||||||
switch (sig) {
|
switch (sig) {
|
||||||
|
@ -1116,7 +1115,7 @@ rb_signal_exec(rb_thread_t *th, int sig)
|
||||||
rb_threadptr_signal_exit(th);
|
rb_threadptr_signal_exit(th);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return signal_exec(cmd, safe, sig);
|
return signal_exec(cmd, sig);
|
||||||
}
|
}
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
@ -1302,7 +1301,6 @@ trap(int sig, sighandler_t func, VALUE command)
|
||||||
}
|
}
|
||||||
|
|
||||||
ACCESS_ONCE(VALUE, vm->trap_list.cmd[sig]) = command;
|
ACCESS_ONCE(VALUE, vm->trap_list.cmd[sig]) = command;
|
||||||
vm->trap_list.safe[sig] = rb_safe_level();
|
|
||||||
|
|
||||||
return oldcmd;
|
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]
|
$LOAD_PATH Array A synonym for $:. [r/o]
|
||||||
$-p Object Set to true if the -p option (which puts an implicit while gets . . . end
|
$-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]
|
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-
|
$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
|
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
|
was specified. Setting this option to true causes the interpreter and some
|
||||||
|
|
|
@ -1,137 +1,138 @@
|
||||||
require_relative '../spec_helper'
|
require_relative '../spec_helper'
|
||||||
|
|
||||||
describe "The $SAFE variable" do
|
describe "The $SAFE variable" do
|
||||||
|
ruby_version_is ""..."2.7" do
|
||||||
ruby_version_is "2.6" do
|
ruby_version_is "2.6" do
|
||||||
after :each do
|
after :each do
|
||||||
$SAFE = 0
|
$SAFE = 0
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
it "is 0 by default" do
|
it "is 0 by default" do
|
||||||
$SAFE.should == 0
|
|
||||||
proc {
|
|
||||||
$SAFE.should == 0
|
$SAFE.should == 0
|
||||||
}.call
|
proc {
|
||||||
end
|
$SAFE.should == 0
|
||||||
|
}.call
|
||||||
|
end
|
||||||
|
|
||||||
it "can be set to 0" do
|
it "can be set to 0" do
|
||||||
proc {
|
proc {
|
||||||
$SAFE = 0
|
$SAFE = 0
|
||||||
$SAFE.should == 0
|
$SAFE.should == 0
|
||||||
}.call
|
}.call
|
||||||
end
|
end
|
||||||
|
|
||||||
it "can be set to 1" do
|
it "can be set to 1" do
|
||||||
proc {
|
proc {
|
||||||
$SAFE = 1
|
$SAFE = 1
|
||||||
$SAFE.should == 1
|
$SAFE.should == 1
|
||||||
}.call
|
}.call
|
||||||
end
|
end
|
||||||
|
|
||||||
[2, 3, 4].each do |n|
|
[2, 3, 4].each do |n|
|
||||||
it "cannot be set to #{n}" do
|
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 {
|
proc {
|
||||||
$SAFE = n
|
$SAFE = 100
|
||||||
}.call
|
}.call
|
||||||
}.should raise_error(ArgumentError, /\$SAFE=2 to 4 are obsolete/)
|
}.should raise_error(ArgumentError, /\$SAFE=2 to 4 are obsolete/)
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
ruby_version_is ""..."2.6" do
|
ruby_version_is ""..."2.6" do
|
||||||
it "cannot be set to values below 0" do
|
it "cannot be manually lowered" do
|
||||||
-> {
|
|
||||||
proc {
|
proc {
|
||||||
$SAFE = -100
|
$SAFE = 1
|
||||||
|
-> {
|
||||||
|
$SAFE = 0
|
||||||
|
}.should raise_error(SecurityError, /tried to downgrade safe level from 1 to 0/)
|
||||||
}.call
|
}.call
|
||||||
}.should raise_error(SecurityError, /tried to downgrade safe level from 0 to -100/)
|
end
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
ruby_version_is "2.6" do
|
it "is automatically lowered when leaving a proc" do
|
||||||
it "raises ArgumentError when set to values below 0" do
|
$SAFE.should == 0
|
||||||
-> {
|
|
||||||
proc {
|
proc {
|
||||||
$SAFE = -100
|
$SAFE = 1
|
||||||
}.call
|
}.call
|
||||||
}.should raise_error(ArgumentError, "$SAFE should be >= 0")
|
$SAFE.should == 0
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
it "cannot be set to values above 4" do
|
it "is automatically lowered when leaving a lambda" do
|
||||||
-> {
|
$SAFE.should == 0
|
||||||
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
|
|
||||||
-> {
|
-> {
|
||||||
$SAFE = 0
|
$SAFE = 1
|
||||||
}.should raise_error(SecurityError, /tried to downgrade safe level from 1 to 0/)
|
}.call
|
||||||
}.call
|
$SAFE.should == 0
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
it "is automatically lowered when leaving a proc" do
|
ruby_version_is "2.6" do
|
||||||
$SAFE.should == 0
|
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 {
|
proc {
|
||||||
$SAFE = 1
|
$SAFE = 1
|
||||||
|
Thread.current.safe_level.should == 1
|
||||||
}.call
|
}.call
|
||||||
$SAFE.should == 0
|
|
||||||
end
|
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
|
||||||
end
|
end
|
||||||
|
|
|
@ -558,20 +558,22 @@ describe "C-API String function" do
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "SafeStringValue" do
|
describe "SafeStringValue" do
|
||||||
it "raises for tained string when $SAFE is 1" do
|
ruby_version_is ''...'2.7' do
|
||||||
begin
|
it "raises for tained string when $SAFE is 1" do
|
||||||
Thread.new {
|
begin
|
||||||
$SAFE = 1
|
Thread.new {
|
||||||
-> {
|
$SAFE = 1
|
||||||
@s.SafeStringValue("str".taint)
|
-> {
|
||||||
}.should raise_error(SecurityError)
|
@s.SafeStringValue("str".taint)
|
||||||
}.join
|
}.should raise_error(SecurityError)
|
||||||
ensure
|
}.join
|
||||||
$SAFE = 0
|
ensure
|
||||||
|
$SAFE = 0
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
it_behaves_like :string_value_macro, :SafeStringValue
|
it_behaves_like :string_value_macro, :SafeStringValue
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "rb_str_modify_expand" do
|
describe "rb_str_modify_expand" do
|
||||||
|
|
|
@ -20,19 +20,6 @@ class IMAPResponseParserTest < Test::Unit::TestCase
|
||||||
end
|
end
|
||||||
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
|
def test_flag_list_too_many_flags
|
||||||
parser = Net::IMAP::ResponseParser.new
|
parser = Net::IMAP::ResponseParser.new
|
||||||
assert_nothing_raised do
|
assert_nothing_raised do
|
||||||
|
|
|
@ -1467,16 +1467,6 @@ class TestPathname < Test::Unit::TestCase
|
||||||
assert(File.fnmatch("*.*", Pathname.new("bar.baz")))
|
assert(File.fnmatch("*.*", Pathname.new("bar.baz")))
|
||||||
end
|
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
|
def test_relative_path_from_casefold
|
||||||
assert_separately([], <<-'end;') # do
|
assert_separately([], <<-'end;') # do
|
||||||
module File::Constants
|
module File::Constants
|
||||||
|
|
|
@ -41,21 +41,6 @@ module BasetestReadline
|
||||||
assert_equal("> ", stdout.read(2))
|
assert_equal("> ", stdout.read(2))
|
||||||
assert_equal(1, Readline::HISTORY.length)
|
assert_equal(1, Readline::HISTORY.length)
|
||||||
assert_equal("hello", Readline::HISTORY[0])
|
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
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -47,12 +47,6 @@ class TestAlias < Test::Unit::TestCase
|
||||||
assert_raise(NoMethodError) { x.quux }
|
assert_raise(NoMethodError) { x.quux }
|
||||||
end
|
end
|
||||||
|
|
||||||
class C
|
|
||||||
def m
|
|
||||||
$SAFE
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_nonexistmethod
|
def test_nonexistmethod
|
||||||
assert_raise(NameError){
|
assert_raise(NameError){
|
||||||
Class.new{
|
Class.new{
|
||||||
|
|
|
@ -471,18 +471,6 @@ class TestFile < Test::Unit::TestCase
|
||||||
end
|
end
|
||||||
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
|
if /(bcc|ms|cyg)win|mingw|emx/ =~ RUBY_PLATFORM
|
||||||
def test_long_unc
|
def test_long_unc
|
||||||
feature3399 = '[ruby-core:30623]'
|
feature3399 = '[ruby-core:30623]'
|
||||||
|
|
|
@ -714,17 +714,6 @@ class TestRubyOptimization < Test::Unit::TestCase
|
||||||
END
|
END
|
||||||
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
|
def test_peephole_optimization_without_trace
|
||||||
assert_separately [], <<-END
|
assert_separately [], <<-END
|
||||||
RubyVM::InstructionSequence.compile_option = {trace_instruction: false}
|
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})
|
assert_equal(12, Proc.new{|a,&b| b.call(a)}.call(12) {|x| x})
|
||||||
end
|
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
|
def m2
|
||||||
"OK"
|
"OK"
|
||||||
end
|
end
|
||||||
|
|
|
@ -396,13 +396,6 @@ class TestRequire < Test::Unit::TestCase
|
||||||
assert_nothing_raised {require "#{ file }"}
|
assert_nothing_raised {require "#{ file }"}
|
||||||
INPUT
|
INPUT
|
||||||
|
|
||||||
assert_separately([], <<-INPUT)
|
|
||||||
abs_dir = "#{ abs_dir }"
|
|
||||||
$: << abs_dir.taint
|
|
||||||
$SAFE = 1
|
|
||||||
assert_raise(SecurityError) {require "#{ file }"}
|
|
||||||
INPUT
|
|
||||||
|
|
||||||
assert_separately([], <<-INPUT)
|
assert_separately([], <<-INPUT)
|
||||||
abs_dir = "#{ abs_dir }"
|
abs_dir = "#{ abs_dir }"
|
||||||
$: << abs_dir << 'elsewhere'.taint
|
$: << abs_dir << 'elsewhere'.taint
|
||||||
|
|
|
@ -79,14 +79,6 @@ class TestRubyOptions < Test::Unit::TestCase
|
||||||
ENV['RUBYOPT'] = save_rubyopt
|
ENV['RUBYOPT'] = save_rubyopt
|
||||||
end
|
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
|
def test_debug
|
||||||
assert_in_out_err(["--disable-gems", "-de", "p $DEBUG"], "", %w(true), [])
|
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"'
|
ENV['RUBYOPT'] = '-e "p 1"'
|
||||||
assert_in_out_err([], "", [], /invalid switch in RUBYOPT: -e \(RuntimeError\)/)
|
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'
|
ENV['RUBYOPT'] = '-Eus-ascii -KN'
|
||||||
assert_in_out_err(%w(-Eutf-8 -KU), "p '\u3042'") do |r, e|
|
assert_in_out_err(%w(-Eutf-8 -KU), "p '\u3042'") do |r, e|
|
||||||
assert_equal("\"\u3042\"", r.join.force_encoding(Encoding::UTF_8))
|
assert_equal("\"\u3042\"", r.join.force_encoding(Encoding::UTF_8))
|
||||||
|
|
|
@ -533,23 +533,6 @@ class TestThread < Test::Unit::TestCase
|
||||||
waiter&.kill&.join
|
waiter&.kill&.join
|
||||||
end
|
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
|
def test_thread_local
|
||||||
t = Thread.new { sleep }
|
t = Thread.new { sleep }
|
||||||
|
|
||||||
|
|
|
@ -31,17 +31,6 @@ class TestTempfile < Test::Unit::TestCase
|
||||||
assert_equal "hello world", File.read(path)
|
assert_equal "hello world", File.read(path)
|
||||||
end
|
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
|
def test_saves_in_given_directory
|
||||||
subdir = File.join(Dir.tmpdir, "tempfile-test-#{rand}")
|
subdir = File.join(Dir.tmpdir, "tempfile-test-#{rand}")
|
||||||
Dir.mkdir(subdir)
|
Dir.mkdir(subdir)
|
||||||
|
|
|
@ -11,19 +11,6 @@ class TestTmpdir < Test::Unit::TestCase
|
||||||
assert_equal(tmpdir_org, Dir.tmpdir)
|
assert_equal(tmpdir_org, Dir.tmpdir)
|
||||||
end
|
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
|
def test_world_writable
|
||||||
skip "no meaning on this platform" if /mswin|mingw/ =~ RUBY_PLATFORM
|
skip "no meaning on this platform" if /mswin|mingw/ =~ RUBY_PLATFORM
|
||||||
Dir.mktmpdir do |tmpdir|
|
Dir.mktmpdir do |tmpdir|
|
||||||
|
|
|
@ -176,39 +176,6 @@ if defined?(WIN32OLE)
|
||||||
}
|
}
|
||||||
end
|
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
|
def test_s_new_DCOM
|
||||||
rshell = WIN32OLE.new("Shell.Application")
|
rshell = WIN32OLE.new("Shell.Application")
|
||||||
assert_instance_of(WIN32OLE, rshell)
|
assert_instance_of(WIN32OLE, rshell)
|
||||||
|
@ -234,22 +201,6 @@ if defined?(WIN32OLE)
|
||||||
}
|
}
|
||||||
end
|
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
|
def test_invoke_accept_symbol_hash_key
|
||||||
fso = WIN32OLE.new('Scripting.FileSystemObject')
|
fso = WIN32OLE.new('Scripting.FileSystemObject')
|
||||||
afolder = fso.getFolder(".")
|
afolder = fso.getFolder(".")
|
||||||
|
|
|
@ -401,21 +401,6 @@ if defined?(WIN32OLE_EVENT)
|
||||||
message_loop
|
message_loop
|
||||||
assert(h2.ev != "")
|
assert(h2.ev != "")
|
||||||
end
|
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
|
end
|
||||||
end
|
end
|
||||||
|
|
3
thread.c
3
thread.c
|
@ -3112,7 +3112,8 @@ rb_thread_stop_p(VALUE thread)
|
||||||
static VALUE
|
static VALUE
|
||||||
rb_thread_safe_level(VALUE thread)
|
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_tempfile_leak(test_name),
|
||||||
check_env(test_name),
|
check_env(test_name),
|
||||||
check_encodings(test_name),
|
check_encodings(test_name),
|
||||||
check_safe(test_name),
|
|
||||||
check_verbose(test_name),
|
check_verbose(test_name),
|
||||||
]
|
]
|
||||||
GC.start if leaks.any?
|
GC.start if leaks.any?
|
||||||
end
|
end
|
||||||
|
|
||||||
def check_safe test_name
|
|
||||||
puts "#{test_name}: $SAFE == #{$SAFE}" unless $SAFE == 0
|
|
||||||
end
|
|
||||||
|
|
||||||
def check_verbose test_name
|
def check_verbose test_name
|
||||||
puts "#{test_name}: $VERBOSE == #{$VERBOSE}" unless @old_verbose == $VERBOSE
|
puts "#{test_name}: $VERBOSE == #{$VERBOSE}" unless @old_verbose == $VERBOSE
|
||||||
end
|
end
|
||||||
|
|
|
@ -375,7 +375,7 @@ load_transcoder_entry(transcoder_entry_t *entry)
|
||||||
rb_str_set_len(fn, total_len);
|
rb_str_set_len(fn, total_len);
|
||||||
FL_UNSET(fn, FL_TAINT);
|
FL_UNSET(fn, FL_TAINT);
|
||||||
OBJ_FREEZE(fn);
|
OBJ_FREEZE(fn);
|
||||||
rb_require_safe(fn, rb_safe_level());
|
rb_require_string(fn);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (entry->transcoder)
|
if (entry->transcoder)
|
||||||
|
|
25
variable.c
25
variable.c
|
@ -1805,7 +1805,6 @@ struct autoload_const {
|
||||||
VALUE ad; /* autoload_data_i */
|
VALUE ad; /* autoload_data_i */
|
||||||
VALUE value;
|
VALUE value;
|
||||||
ID id;
|
ID id;
|
||||||
int safe_level;
|
|
||||||
rb_const_flag_t flag;
|
rb_const_flag_t flag;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1999,7 +1998,6 @@ rb_autoload_str(VALUE mod, ID id, VALUE file)
|
||||||
ac->mod = mod;
|
ac->mod = mod;
|
||||||
ac->id = id;
|
ac->id = id;
|
||||||
ac->value = Qundef;
|
ac->value = Qundef;
|
||||||
ac->safe_level = rb_safe_level();
|
|
||||||
ac->flag = CONST_PUBLIC;
|
ac->flag = CONST_PUBLIC;
|
||||||
ac->ad = ad;
|
ac->ad = ad;
|
||||||
list_add_tail(&ele->constants, &ac->cnode);
|
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
|
static VALUE
|
||||||
check_autoload_required(VALUE mod, ID id, const char **loadingpath)
|
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);
|
VALUE load = autoload_data(mod, id);
|
||||||
struct autoload_data_i *ele;
|
struct autoload_data_i *ele;
|
||||||
const char *loading;
|
const char *loading;
|
||||||
int safe;
|
|
||||||
|
|
||||||
if (!load || !(ele = get_autoload_data(load, 0))) {
|
if (!load || !(ele = get_autoload_data(load, 0))) {
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -2081,9 +2064,7 @@ check_autoload_required(VALUE mod, ID id, const char **loadingpath)
|
||||||
}
|
}
|
||||||
|
|
||||||
loading = RSTRING_PTR(file);
|
loading = RSTRING_PTR(file);
|
||||||
safe = rb_safe_level();
|
if (!rb_feature_provided(loading, &loading)) {
|
||||||
rb_set_safe_level_force(0);
|
|
||||||
if (!rb_ensure(autoload_provided, (VALUE)&loading, reset_safe, (VALUE)safe)) {
|
|
||||||
return load;
|
return load;
|
||||||
}
|
}
|
||||||
if (loadingpath && loading) {
|
if (loadingpath && loading) {
|
||||||
|
@ -2186,12 +2167,10 @@ autoload_reset(VALUE arg)
|
||||||
/* At the last, move a value defined in autoload to constant table */
|
/* At the last, move a value defined in autoload to constant table */
|
||||||
if (RTEST(state->result)) {
|
if (RTEST(state->result)) {
|
||||||
struct autoload_const *next;
|
struct autoload_const *next;
|
||||||
int safe_backup = rb_safe_level();
|
|
||||||
|
|
||||||
list_for_each_safe(&ele->constants, ac, next, cnode) {
|
list_for_each_safe(&ele->constants, ac, next, cnode) {
|
||||||
if (ac->value != Qundef) {
|
if (ac->value != Qundef) {
|
||||||
rb_ensure(autoload_const_set, (VALUE)ac,
|
autoload_const_set((VALUE)ac);
|
||||||
reset_safe, (VALUE)safe_backup);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -619,7 +619,6 @@ typedef struct rb_vm_struct {
|
||||||
/* signal */
|
/* signal */
|
||||||
struct {
|
struct {
|
||||||
VALUE cmd[RUBY_NSIG];
|
VALUE cmd[RUBY_NSIG];
|
||||||
unsigned char safe[RUBY_NSIG];
|
|
||||||
} trap_list;
|
} trap_list;
|
||||||
|
|
||||||
/* hook */
|
/* hook */
|
||||||
|
|
|
@ -1777,19 +1777,13 @@ rb_eval_string_wrap(const char *str, int *pstate)
|
||||||
}
|
}
|
||||||
|
|
||||||
VALUE
|
VALUE
|
||||||
rb_eval_cmd(VALUE cmd, VALUE arg, int level)
|
rb_eval_cmd(VALUE cmd, VALUE arg, int _level)
|
||||||
{
|
{
|
||||||
enum ruby_tag_type state;
|
enum ruby_tag_type state;
|
||||||
volatile VALUE val = Qnil; /* OK */
|
volatile VALUE val = Qnil; /* OK */
|
||||||
const int VAR_NOCLOBBERED(current_safe_level) = rb_safe_level();
|
|
||||||
rb_execution_context_t * volatile ec = GET_EC();
|
rb_execution_context_t * volatile ec = GET_EC();
|
||||||
|
|
||||||
if (OBJ_TAINTED(cmd)) {
|
|
||||||
level = RUBY_SAFE_LEVEL_MAX;
|
|
||||||
}
|
|
||||||
|
|
||||||
EC_PUSH_TAG(ec);
|
EC_PUSH_TAG(ec);
|
||||||
rb_set_safe_level_force(level);
|
|
||||||
if ((state = EC_EXEC_TAG()) == TAG_NONE) {
|
if ((state = EC_EXEC_TAG()) == TAG_NONE) {
|
||||||
if (!RB_TYPE_P(cmd, T_STRING)) {
|
if (!RB_TYPE_P(cmd, T_STRING)) {
|
||||||
val = rb_funcallv(cmd, idCall, RARRAY_LENINT(arg),
|
val = rb_funcallv(cmd, idCall, RARRAY_LENINT(arg),
|
||||||
|
@ -1801,7 +1795,6 @@ rb_eval_cmd(VALUE cmd, VALUE arg, int level)
|
||||||
}
|
}
|
||||||
EC_POP_TAG();
|
EC_POP_TAG();
|
||||||
|
|
||||||
rb_set_safe_level_force(current_safe_level);
|
|
||||||
if (state) EC_JUMP_TAG(ec, state);
|
if (state) EC_JUMP_TAG(ec, state);
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue