CAN-2005-2337.diff [plain text]
--- eval.c.orig 2004-12-18 11:07:29.000000000 +0900
+++ eval.c 2005-09-21 16:53:31.127896405 +0900
@@ -254,2 +254,7 @@
+#define NOEX_TAINTED 8
+#define NOEX_SAFE(n) ((n) >> 4)
+#define NOEX_WITH(n, v) ((n) | (v) << 4)
+#define NOEX_WITH_SAFE(n) NOEX_WITH(n, ruby_safe_level)
+
void
@@ -346,3 +351,3 @@
rb_clear_cache_by_id(mid);
- body = NEW_METHOD(node, noex);
+ body = NEW_METHOD(node, NOEX_WITH_SAFE(noex));
st_insert(RCLASS(klass)->m_tbl, mid, (st_data_t)body);
@@ -5458,3 +5463,3 @@
static VALUE
-rb_call0(klass, recv, id, oid, argc, argv, body, nosuper)
+rb_call0(klass, recv, id, oid, argc, argv, body, flags)
VALUE klass, recv;
@@ -5465,3 +5470,3 @@
NODE *body; /* OK */
- int nosuper;
+ int flags;
{
@@ -5472,2 +5477,3 @@
TMP_PROTECT;
+ volatile int safe = -1;
@@ -5493,3 +5499,3 @@
ruby_frame->orig_func = oid;
- ruby_frame->last_class = nosuper?0:klass;
+ ruby_frame->last_class = (flags & NOEX_UNDEF)?0:klass;
ruby_frame->self = recv;
@@ -5555,3 +5561,2 @@
PUSH_SCOPE();
-
if (body->nd_rval) {
@@ -5574,5 +5579,12 @@
+ if (NOEX_SAFE(flags) > ruby_safe_level) {
+ if (!(flags&NOEX_TAINTED) && ruby_safe_level == 0 && NOEX_SAFE(flags) > 2) {
+ rb_raise(rb_eSecurityError, "calling insecure method: %s",
+ rb_id2name(id));
+ }
+ safe = ruby_safe_level;
+ ruby_safe_level = NOEX_SAFE(flags);
+ }
PUSH_VARS();
PUSH_TAG(PROT_FUNC);
-
if ((state = EXEC_TAG()) == 0) {
@@ -5655,2 +5667,3 @@
}
+ if (safe >= 0) ruby_safe_level = safe;
POP_TAG();
@@ -5742,3 +5755,3 @@
- return rb_call0(klass, recv, mid, id, argc, argv, body, noex & NOEX_NOSUPER);
+ return rb_call0(klass, recv, mid, id, argc, argv, body, noex);
}
@@ -8532,2 +8545,3 @@
ID id, oid;
+ int safe_level;
NODE *body;
@@ -8579,2 +8593,3 @@
data->oid = oid;
+ data->safe_level = NOEX_WITH_SAFE(0);
OBJ_INFECT(method, klass);
@@ -8663,2 +8678,3 @@
data->oid = orig->oid;
+ data->safe_level = NOEX_WITH_SAFE(0);
OBJ_INFECT(method, obj);
@@ -8784,4 +8800,3 @@
struct METHOD *data;
- int state;
- volatile int safe = -1;
+ int safe;
@@ -8791,15 +8806,11 @@
}
- PUSH_ITER(rb_block_given_p()?ITER_PRE:ITER_NOT);
- PUSH_TAG(PROT_NONE);
if (OBJ_TAINTED(method)) {
- safe = ruby_safe_level;
- if (ruby_safe_level < 4) ruby_safe_level = 4;
+ safe = NOEX_WITH(data->safe_level, 4)|NOEX_TAINTED;
}
- if ((state = EXEC_TAG()) == 0) {
- result = rb_call0(data->klass,data->recv,data->id,data->oid,argc,argv,data->body,0);
+ else {
+ safe = data->safe_level;
}
- POP_TAG();
+ PUSH_ITER(rb_block_given_p()?ITER_PRE:ITER_NOT);
+ result = rb_call0(data->klass,data->recv,data->id,data->oid,argc,argv,data->body,safe);
POP_ITER();
- if (safe >= 0) ruby_safe_level = safe;
- if (state) JUMP_TAG(state);
return result;