From oz@nixil.net  Fri Oct 21 21:39:55 2005
Return-Path: <oz@nixil.net>
Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125])
	by hub.freebsd.org (Postfix) with ESMTP id F41A416A41F
	for <FreeBSD-gnats-submit@freebsd.org>; Fri, 21 Oct 2005 21:39:54 +0000 (GMT)
	(envelope-from oz@nixil.net)
Received: from nixil.net (nixil.net [161.58.222.1])
	by mx1.FreeBSD.org (Postfix) with ESMTP id E7A7343D7B
	for <FreeBSD-gnats-submit@freebsd.org>; Fri, 21 Oct 2005 21:39:44 +0000 (GMT)
	(envelope-from oz@nixil.net)
Received: from nixil.net (localhost [127.0.0.1])
	by nixil.net (8.13.1/8.13.1) with ESMTP id j9LLdh41068292
	(version=TLSv1/SSLv3 cipher=EDH-RSA-DES-CBC3-SHA bits=168 verify=NOT)
	for <FreeBSD-gnats-submit@freebsd.org>; Fri, 21 Oct 2005 15:39:43 -0600 (MDT)
Received: (from oz@localhost)
	by nixil.net (8.13.1/8.13.1/Submit) id j9LLdhS6068291;
	Fri, 21 Oct 2005 15:39:43 -0600 (MDT)
Message-Id: <200510212139.j9LLdhS6068291@nixil.net>
Date: Fri, 21 Oct 2005 15:39:43 -0600 (MDT)
From: Phil Oleson <oz@nixil.net>
Reply-To: Phil Oleson <oz@nixil.net>
To: FreeBSD-gnats-submit@freebsd.org
Cc:
Subject: [PATCH] ruby18 & ruby16 - Security Vulnerability
X-Send-Pr-Version: 3.113
X-GNATS-Notify:

>Number:         87816
>Category:       ports
>Synopsis:       [PATCH] ruby18 & ruby16 - Security Vulnerability
>Confidential:   no
>Severity:       critical
>Priority:       high
>Responsible:    sem
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          update
>Submitter-Id:   current-users
>Arrival-Date:   Fri Oct 21 21:40:16 GMT 2005
>Closed-Date:    Fri Oct 28 11:01:00 GMT 2005
>Last-Modified:  Fri Oct 28 11:01:00 GMT 2005
>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:
Responsible-Changed-From-To: freebsd-ports-bugs->knu 
Responsible-Changed-By: mnag 
Responsible-Changed-When: Fri Oct 21 21:52:08 GMT 2005 
Responsible-Changed-Why:  
Over to maintainer. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=87816 

From: Sergey Matveychuk <sem@FreeBSD.org>
To: bug-followup@FreeBSD.org,  oz@nixil.net
Cc:  
Subject: Re: ports/87816: [PATCH] ruby18 & ruby16 - Security Vulnerability
Date: Thu, 27 Oct 2005 21:52:05 +0400

 I think implementing this with PATCHFILES will be better.
 
 -- 
 Sem.
Responsible-Changed-From-To: knu->sem 
Responsible-Changed-By: sem 
Responsible-Changed-When: Thu Oct 27 18:21:30 GMT 2005 
Responsible-Changed-Why:  
knu is MIA. I take it. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=87816 
State-Changed-From-To: open->closed 
State-Changed-By: sem 
State-Changed-When: Fri Oct 28 11:00:59 GMT 2005 
State-Changed-Why:  
Committed, thanks! 

http://www.freebsd.org/cgi/query-pr.cgi?pr=87816 
>Unformatted:
