Can't start ruby with RUBYOPT=-T4

e$B1sF#$H?=$7$^$9!#e(B

e$B0J2<$N5sF0$O0U?^E*$G$7$g$&$+!#e(B

$ RUBYOPT=-T4 ./ruby
./ruby: Insecure: can’t set constant (SecurityError)

$ ./ruby -v
ruby 1.9.0 (2008-04-15 revision 16040) [i686-linux]

e$B<B32$O$J$$5$$b$7$^$9$,!"$4Js9p$^$G!#e(B

e$B1sF#$G$9!#e(B

2008/04/16 0:00 Yusuke ENDOH [email protected]:

e$B0J2<$N5sF0$O0U?^E*$G$7$g$&$+!#e(B

$ RUBYOPT=-T4 ./ruby
./ruby: Insecure: can’t set constant (SecurityError)

$ ./ruby -v
ruby 1.9.0 (2008-04-15 revision 16040) [i686-linux]

r16050 e$B$G=$@5$7$F$$$?$@$$$?$h$&$G$9$,!"$=$NI{:nMQ$Ge(B RUBYOPT=-T1
e$B$G$bI8=F~NO$+$i%W%m%0%i%$rN.$79~$a$k$h$&$K$J$C$?$h$&$G$9!#e(B

$ RUBYOPT=-T1 ./ruby
p 1
1

$ ./ruby -v
ruby 1.9.0 (2008-04-16 revision 16050) [i686-linux]

1.8 e$B$G$Oe(B SecurityError e$B$K$J$j$^$9!#e(B

$ RUBYOPT=-T1 ruby
ruby: no program input from stdin allowed in tainted mode
(SecurityError)

$ ruby -v
ruby 1.8.5 (2006-08-25) [i486-linux]

e$B$J$+$@$G$9!#e(B

At Wed, 16 Apr 2008 12:49:39 +0900,
Yusuke ENDOH wrote in [ruby-dev:34421]:

r16050 e$B$G=$@5$7$F$$$?$@$$$?$h$&$G$9$,!"$=$NI{:nMQ$Ge(B RUBYOPT=-T1
e$B$G$bI8=F~NO$+$i%W%m%0%i%$rN.$79~$a$k$h$&$K$J$C$?$h$&$G$9!#e(B

$ RUBYOPT=-T1 ./ruby
p 1
1

encodinge$B$O>o$Ke(B$SAFE=0e$B$G%m!<%I$9$k$h$&$K$7$h$&$+$H$b;W$$$^$7$?$,!"e(B
e$B$=$N>l9g$ODL>o$N%i%$%V%i%j$H$OJ,$1$J$$$H$^$:$$$+$J$H$$$&5$$b$7$^e(B
e$B$9!#e(B

e$B$b$&0l$D9M$($?$N$,!“e(B-Te$B$N1F6A$re(B
process_optionse$B$NCf$KJD$8$F$7$^$Ce(B
e$B$F!”<B:]$Ke(B$SAFEe$B$K%;%C%H$9$k$N$O:G8e$K2s$9!"$H$$$&J}K!$G$9!#e(B

Index: parse.y

— parse.y (revision 16050)
+++ parse.y (working copy)
@@ -8691,4 +8691,24 @@ rb_gc_mark_parser(void)

NODE*
+rb_parser_add_prelude(VALUE vparser, NODE *node, NODE *prelude)
+{

  • NODE *scope = node;
  • struct parser_params *parser;
  • Data_Get_Struct(vparser, struct parser_params, parser);
  • node = node->nd_body;
  • if (nd_type(node) == NODE_PRELUDE) {
  • node->nd_head = block_append(prelude, node->nd_head);
  • }
  • else {
  • scope->nd_body = NEW_PRELUDE(prelude, scope->nd_body);
  • }
  • return scope;
    +}

+NODE*
rb_parser_append_print(VALUE vparser, NODE *node)
{
Index: ruby.c

— ruby.c (revision 16050)
+++ ruby.c (working copy)
@@ -84,4 +95,6 @@ struct cmdline_options {
int verbose;
int yydebug;

  • int safe_level;
  • unsigned int setids;
    char *script;
    VALUE script_name;
    @@ -93,6 +107,12 @@ struct cmdline_options {
    } enc;
    } src, ext;
    };

+static void init_ids(struct cmdline_options *);
+
+#define cmdline_options_init(opt) (MEMZERO((opt), *(opt), 1), \

  •       init_ids(opt), \
    
  •       (opt)->src.enc.index = src_encoding_index)
    

struct cmdline_arguments {
int argc;
@@ -102,5 +126,6 @@ struct cmdline_arguments {

static NODE *load_file(VALUE, const char *, int, struct cmdline_options
*);
-static void forbid_setid(const char *);
+static void forbid_setid(const char *, struct cmdline_options *);
+#define forbid_setid(s) forbid_setid(s, opt)

static struct {
@@ -328,5 +353,5 @@ DllMain(HINSTANCE dll, DWORD reason, LPV

void
-ruby_init_loadpath(void)
+ruby_init_loadpath_safe(int safe_level)
{
#if defined LOAD_RELATIVE
@@ -378,5 +404,5 @@ ruby_init_loadpath(void)
#define incpush(path) rb_ary_push(rb_load_path,
rubylib_mangled_path2(path))

  • if (rb_safe_level() == 0) {
  • if (safe_level == 0) {
    ruby_incpush(getenv(“RUBYLIB”));
    }
    @@ -406,8 +432,14 @@ ruby_init_loadpath(void)
    incpush(RUBY_RELATIVE(RUBY_ARCHLIB));
  • if (rb_safe_level() == 0) {
  • if (safe_level == 0) {
    incpush(".");
    }
    }

+void
+ruby_init_loadpath(void)
+{

  • ruby_init_loadpath_safe(rb_safe_level());
    +}

struct req_list {
@@ -793,5 +825,5 @@ proc_options(int argc, char **argv, stru
s += numlen;
}

  • rb_set_safe_level(v);
  • if (v > opt->safe_level) opt->safe_level = v;
    }
    goto reswitch;
    @@ -939,4 +975,5 @@ VALUE rb_progname;
    VALUE rb_argv0;
    static int src_encoding_index = -1; /* TODO: VM private */
    +NODE *rb_parser_add_prelude(VALUE vparser, NODE *node, NODE *prelude);

static VALUE
@@ -949,8 +986,8 @@ process_options(VALUE arg)
NODE *tree = 0;
VALUE parser;

  • VALUE iseq;
    rb_encoding *enc;
    const char *s;
    int i = proc_options(argc, argv, opt);
  • int safe;

    argc -= i;
    @@ -958,5 +995,5 @@ process_options(VALUE arg)

    if (!(opt->disable & DISABLE_BIT(rubyopt)) &&

  • rb_safe_level() == 0 && (s = getenv(“RUBYOPT”))) {

  • opt->safe_level == 0 && (s = getenv(“RUBYOPT”))) {
    VALUE src_enc_name = opt->src.enc.name;
    VALUE ext_enc_name = opt->ext.enc.name;
    @@ -975,5 +1012,5 @@ process_options(VALUE arg)
    v = 1;
    }
  •  rb_set_safe_level(v);
    
  •  if (v > opt->safe_level) opt->safe_level = v;
    
    }
    else {
    @@ -1010,5 +1047,5 @@ process_options(VALUE arg)
    }
  • if (rb_safe_level() >= 4) {
  • if (opt->safe_level >= 4) {
    OBJ_TAINT(rb_argv);
    OBJ_TAINT(rb_load_path);
    @@ -1053,7 +1090,5 @@ process_options(VALUE arg)
    process_sflag(opt);
  • ruby_init_loadpath();
  • safe = rb_safe_level();
  • rb_set_safe_level_force(0);
  • ruby_init_loadpath_safe(opt->safe_level);
    ruby_init_gems(!(opt->disable & DISABLE_BIT(gems)));
    parser = rb_parser_new();
    @@ -1092,5 +1127,4 @@ process_options(VALUE arg)
    tree = load_file(parser, opt->script, 1, opt);
    }
  • rb_set_safe_level_force(safe);

    if (!tree) return Qfalse;
    @@ -1099,5 +1133,5 @@ process_options(VALUE arg)
    opt->xflag = 0;

  • if (rb_safe_level() >= 4) {

  • if (opt->safe_level >= 4) {
    FL_UNSET(rb_argv, FL_TAINT);
    FL_UNSET(rb_load_path, FL_TAINT);
    @@ -1116,6 +1150,10 @@ process_options(VALUE arg)
    }
  • return rb_iseq_new(tree, rb_str_new2(""),
  • iseq = rb_iseq_new(tree, rb_str_new2(""),
    opt->script_name, Qfalse, ISEQ_TYPE_TOP);
  • rb_set_safe_level(opt->safe_level);
  • return iseq;
    }

@@ -1274,6 +1318,5 @@ rb_load_file(const char *fname)
struct cmdline_options opt;

  • MEMZERO(&opt, opt, 1);
  • opt.src.enc.index = src_encoding_index;
  • cmdline_options_init(&opt);
    return load_file(rb_parser_new(), fname, 0, &opt);
    }
    @@ -1379,30 +1422,31 @@ ruby_script(const char *name)
    }

-static int uid, euid, gid, egid;

static void
-init_ids(void)
+init_ids(struct cmdline_options *opt)
{

  • uid = (int)getuid();
  • euid = (int)geteuid();
  • gid = (int)getgid();
  • egid = (int)getegid();
  • rb_uid_t uid = getuid();
  • rb_uid_t euid = geteuid();
  • rb_gid_t gid = getgid();
  • rb_gid_t egid = getegid();
    #ifdef VMS
    uid |= gid << 16;
    euid |= egid << 16;
    #endif
  • if (uid && (euid != uid || egid != gid)) {
  • rb_set_safe_level(1);
  • if (euid != uid) opt->setids |= 1;
  • if (egid != gid) opt->setids |= 2;
  • if (uid && opt->setids) {
  • opt->safe_level = 1;
    }
    }

+#undef forbid_setid
static void
-forbid_setid(const char *s)
+forbid_setid(const char *s, struct cmdline_options *opt)
{

  • if (euid != uid)
  • if (opt->setids & 1)
    rb_raise(rb_eSecurityError, “no %s allowed while running
    setuid”, s);
  • if (egid != gid)
  • if (opt->setids & 2)
    rb_raise(rb_eSecurityError, “no %s allowed while running
    setgid”, s);
  • if (rb_safe_level() > 0)
  • if (opt->safe_level > 0)
    rb_raise(rb_eSecurityError, “no %s allowed in tainted mode”,
    s);
    }
    @@ -1429,6 +1473,4 @@ void
    ruby_prog_init(void)
    {
  • init_ids();

  • rb_define_hooked_variable("$VERBOSE", &ruby_verbose, 0,
    verbose_setter);
    rb_define_hooked_variable("$-v", &ruby_verbose, 0, verbose_setter);
    @@ -1497,5 +1539,5 @@ ruby_process_options(int argc, char **ar
    NODE *tree;

  • MEMZERO(&opt, opt, 1);

  • cmdline_options_init(&opt);
    ruby_script(argv[0]); /* for the time being */
    rb_argv0 = rb_progname;
    @@ -1503,5 +1545,4 @@ ruby_process_options(int argc, char **ar
    args.argv = argv;
    args.opt = &opt;
  • opt.src.enc.index = src_encoding_index;
    opt.ext.enc.index = -1;
    tree = (NODE *)rb_vm_call_cfunc(rb_vm_top_self(),