Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 21 Oct 2005 15:39:43 -0600 (MDT)
From:      Phil Oleson <oz@nixil.net>
To:        FreeBSD-gnats-submit@FreeBSD.org
Subject:   ports/87816: [PATCH] ruby18 & ruby16 - Security Vulnerability
Message-ID:  <200510212139.j9LLdhS6068291@nixil.net>
Resent-Message-ID: <200510212140.j9LLeHV1099426@freefall.freebsd.org>

next in thread | raw e-mail | index | archive | help

>Number:         87816
>Category:       ports
>Synopsis:       [PATCH] ruby18 & ruby16 - Security Vulnerability
>Confidential:   no
>Severity:       critical
>Priority:       high
>Responsible:    freebsd-ports-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          update
>Submitter-Id:   current-users
>Arrival-Date:   Fri Oct 21 21:40:16 GMT 2005
>Closed-Date:
>Last-Modified:
>Originator:     Phil Oleson
>Release:        FreeBSD 4.7-RELEASE-p28 i386
>Organization:
N/A
>Environment:
System: FreeBSD nixil.net 4.7-RELEASE-p28 FreeBSD 4.7-RELEASE-p28 #42: Tue Jun 21 10:33:20 MDT 2005 root@fc2:/usr/src/sys/compile/nixil i386

>Description:
	Patches to fix CAN-2005-2337 for ruby18 & ruby16
	ref: http://www.ruby-lang.org/en/20051003.html
>How-To-Repeat:
	N/A
>Fix:

--- patch-ruby18 begins here ---
diff -ruN ruby18.orig/Makefile ruby18/Makefile
--- ruby18.orig/Makefile	Sun Jul  3 04:26:31 2005
+++ ruby18/Makefile	Fri Oct 21 15:24:51 2005
@@ -7,7 +7,7 @@
 
 PORTNAME=	ruby
 PORTVERSION=	${RUBY_PORTVERSION}
-PORTREVISION=	4
+PORTREVISION=	5
 CATEGORIES=	lang ruby ipv6
 MASTER_SITES=		${MASTER_SITE_RUBY}
 MASTER_SITE_SUBDIR=	${MASTER_SITE_SUBDIR_RUBY}
diff -ruN ruby18.orig/files/patch-eval.c ruby18/files/patch-eval.c
--- ruby18.orig/files/patch-eval.c	Wed Dec 31 17:00:00 1969
+++ ruby18/files/patch-eval.c	Fri Oct 21 15:24:20 2005
@@ -0,0 +1,100 @@
+--- 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;
--- patch-ruby18 ends here ---

--- patch-ruby16 begins here ---
diff -ruN ruby16.orig/Makefile ruby16/Makefile
--- ruby16.orig/Makefile	Fri Oct 21 15:28:45 2005
+++ ruby16/Makefile	Fri Oct 21 15:31:11 2005
@@ -7,7 +7,7 @@
 
 PORTNAME=	ruby
 PORTVERSION=	${RUBY_PORTVERSION}
-PORTREVISION=	1
+PORTREVISION=	2
 CATEGORIES=	lang ruby ipv6
 MASTER_SITES=		${MASTER_SITE_RUBY}
 MASTER_SITE_SUBDIR=	${MASTER_SITE_SUBDIR_RUBY}
diff -ruN ruby16.orig/files/patch-eval.c ruby16/files/patch-eval.c
--- ruby16.orig/files/patch-eval.c	Wed Dec 31 17:00:00 1969
+++ ruby16/files/patch-eval.c	Fri Oct 21 15:29:15 2005
@@ -0,0 +1,105 @@
+--- /tmp/eval.c	2005-09-21 01:37:35.144705141 +0900
++++ eval.c	2005-09-21 01:32:05.458758905 +0900
+@@ -244,2 +244,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
+@@ -259,3 +264,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, body);
+@@ -4350,3 +4356,3 @@
+ static VALUE
+-rb_call0(klass, recv, id, argc, argv, body, nosuper)
++rb_call0(klass, recv, id, argc, argv, body, flags)
+     VALUE klass, recv;
+@@ -4356,3 +4362,3 @@
+     NODE *body;			/* OK */
+-    int nosuper;
++    int flags;
+ {
+@@ -4363,2 +4369,3 @@
+     TMP_PROTECT;
++    volatile int safe = -1;
+ 
+@@ -4382,3 +4389,3 @@
+     ruby_frame->last_func = id;
+-    ruby_frame->last_class = nosuper?0:klass;
++    ruby_frame->last_class = (flags & NOEX_UNDEF)?0:klass;
+     ruby_frame->self = recv;
+@@ -4446,3 +4453,2 @@
+ 	    PUSH_SCOPE();
+-
+ 	    if (body->nd_rval) {
+@@ -4466,5 +4472,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) {
+@@ -4552,2 +4565,3 @@
+ 	    }
++	    if (safe >= 0) ruby_safe_level = safe;
+ 	    POP_TAG();
+@@ -4639,3 +4653,3 @@
+ 
+-    return rb_call0(klass, recv, id, argc, argv, body, noex & NOEX_UNDEF);
++    return rb_call0(klass, recv, id, argc, argv, body, noex);
+ }
+@@ -6632,2 +6648,3 @@
+     ID id, oid;
++    int safe_level;
+     NODE *body;
+@@ -6674,2 +6691,3 @@
+     data->oid = oid;
++    data->safe_level = NOEX_WITH_SAFE(0);
+     OBJ_INFECT(method, klass);
+@@ -6694,2 +6712,3 @@
+     data->oid = orig->oid;
++    data->safe_level = NOEX_WITH_SAFE(0);
+     OBJ_INFECT(method, obj);
+@@ -6745,18 +6764,14 @@
+     struct METHOD *data;
+-    int state;
+-    volatile int safe = ruby_safe_level;
++    int safe;
+ 
+     Data_Get_Struct(method, struct METHOD, data);
+-    PUSH_ITER(rb_block_given_p()?ITER_PRE:ITER_NOT);
+-    PUSH_TAG(PROT_NONE);
+-    if (OBJ_TAINTED(method) && ruby_safe_level < 4) {
+-	ruby_safe_level = 4;
++    if (OBJ_TAINTED(method)) {
++        safe = NOEX_WITH(data->safe_level, 4)|NOEX_TAINTED;
+     }
+-    if ((state = EXEC_TAG()) == 0) {
+-	result = rb_call0(data->klass,data->recv,data->id,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,argc,argv,data->body,safe);
+     POP_ITER();
+-    ruby_safe_level = safe;
+-    if (state) JUMP_TAG(state);
+     return result;
+@@ -6826,2 +6841,5 @@
+ 	return INT2FIX(0);
++      case NODE_BMETHOD:
++      case NODE_DMETHOD:
++       return proc_arity(method);
+       default:
--- patch-ruby16 ends here ---


>Release-Note:
>Audit-Trail:
>Unformatted:



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200510212139.j9LLdhS6068291>