1 /**********************************************************************
2 
3   safe.c -
4 
5   $Author: ko1 $
6   created at: Tue Sep 23 09:44:32 JST 2008
7 
8   Copyright (C) 2008 Yukihiro Matsumoto
9 
10 **********************************************************************/
11 
12 /* safe-level:
13    0 - strings from streams/environment/ARGV are tainted (default)
14    1 - no dangerous operation by tainted value
15 */
16 
17 #define SAFE_LEVEL_MAX RUBY_SAFE_LEVEL_MAX
18 
19 #include "ruby/ruby.h"
20 #include "vm_core.h"
21 
22 /* $SAFE accessor */
23 
24 #undef rb_secure
25 #undef rb_set_safe_level
26 #undef ruby_safe_level_2_warning
27 
28 int
ruby_safe_level_2_warning(void)29 ruby_safe_level_2_warning(void)
30 {
31     return 2;
32 }
33 
34 int
rb_safe_level(void)35 rb_safe_level(void)
36 {
37     return GET_VM()->safe_level_;
38 }
39 
40 void
rb_set_safe_level_force(int safe)41 rb_set_safe_level_force(int safe)
42 {
43     GET_VM()->safe_level_ = safe;
44 }
45 
46 void
rb_set_safe_level(int level)47 rb_set_safe_level(int level)
48 {
49     rb_vm_t *vm = GET_VM();
50 
51     if (level > SAFE_LEVEL_MAX) {
52 	rb_raise(rb_eArgError, "$SAFE=2 to 4 are obsolete");
53     }
54     else if (level < 0) {
55 	rb_raise(rb_eArgError, "$SAFE should be >= 0");
56     }
57     else {
58 	int line;
59 	const char *path = rb_source_location_cstr(&line);
60 
61 	if (0) fprintf(stderr, "%s:%d $SAFE %d -> %d\n",
62 		       path ? path : "-", line, vm->safe_level_, level);
63 
64 	vm->safe_level_ = level;
65     }
66 }
67 
68 static VALUE
safe_getter(void)69 safe_getter(void)
70 {
71     return INT2NUM(rb_safe_level());
72 }
73 
74 static void
safe_setter(VALUE val)75 safe_setter(VALUE val)
76 {
77     int level = NUM2INT(val);
78     rb_set_safe_level(level);
79 }
80 
81 void
rb_secure(int level)82 rb_secure(int level)
83 {
84     if (level <= rb_safe_level()) {
85 	ID caller_name = rb_frame_callee();
86 	if (caller_name) {
87 	    rb_raise(rb_eSecurityError, "Insecure operation `%"PRIsVALUE"' at level %d",
88 		     rb_id2str(caller_name), rb_safe_level());
89 	}
90 	else {
91 	    rb_raise(rb_eSecurityError, "Insecure operation at level %d",
92 		     rb_safe_level());
93 	}
94     }
95 }
96 
97 void
rb_secure_update(VALUE obj)98 rb_secure_update(VALUE obj)
99 {
100 }
101 
102 void
rb_insecure_operation(void)103 rb_insecure_operation(void)
104 {
105     ID caller_name = rb_frame_callee();
106     if (caller_name) {
107 	rb_raise(rb_eSecurityError, "Insecure operation - %"PRIsVALUE,
108 		 rb_id2str(caller_name));
109     }
110     else {
111 	rb_raise(rb_eSecurityError, "Insecure operation: -r");
112     }
113 }
114 
115 void
rb_check_safe_obj(VALUE x)116 rb_check_safe_obj(VALUE x)
117 {
118     if (rb_safe_level() > 0 && OBJ_TAINTED(x)) {
119 	rb_insecure_operation();
120     }
121 }
122 
123 void
Init_safe(void)124 Init_safe(void)
125 {
126     rb_define_virtual_variable("$SAFE", safe_getter, safe_setter);
127 }
128