Ruby Security and Patches

June 26, 2008 – 11:13 pm

This week there was a bit of turmoil in the Ruby community concerning a security leak that was discovered and the released fixes ended up breaking Rails, a major utilizer of the Ruby language.  This was one of the first times that I was actually following the situation as it happened.  Typically, I’m a slower adopter of new software and I wait for later, confirmed stable releases.  But this time I figured… what the heck?  It’s a security issue, let’s upgrade!  Anyway, didn’t work out so hot initially.

What amazed me was how QUICKLY developers from all over identified and FIXED the problem with the security update.  You just have to take a look at this thread to see how angry, productive, excited, helpful, and frustrated folks in the Open Source community can be.  I was pretty entertained, and was happy to try out the patches as they were released.  Ever get a developer-fix on a Microsoft product in under a few days?  Lots of luck…


[The rest of this blog post contains the technical details of what actually went down and how it was fixed. It's even more nerd-tastic.]

So, the longer story:  A security vulnerability was discovered last week by Apple’s security team.  The Ruby maintainers released an updated version that plugged the holes.  Should have been the end of the story.

Folks running the 1.8.6 branch of Ruby (like most Rails developers who aren’t completely immersed in v2.1) were suggested to upgrade to Patch 230.  Unfortunately, that seemed to randomly break Rails (seg-faults and strange errors all over the place).  This is the one that I experienced:

/usr/local/lib/ruby/gems/1.8/gems/actionpack-2.1.0 \
/lib/action_view/helpers/form_tag_helper.rb:431: \
[BUG] Segmentation fault ruby 1.8.6 (2008-06-20) [i686-linux]

After following this thread in the Ruby forum for awhile, a couple folks posted some patches, which seem to fix things.  I ended up using this one by Robert Thau to fix things up.  Here’s a transcript of the diff:

Index: class.c
===================================================================
--- class.c	(revision 17222)
+++ class.c	(revision 17218)
@@ -48,26 +48,13 @@
     return rb_class_boot(super);
 }
 
-struct clone_method_data {
-    st_table *tbl;
-    VALUE klass;
-};
-
 static int
-clone_method(mid, body, data)
+clone_method(mid, body, tbl)
     ID mid;
     NODE *body;
-    struct clone_method_data *data;
+    st_table *tbl;
 {
-    NODE *fbody = body->nd_body;
-
-    if (fbody && nd_type(fbody) == NODE_SCOPE) {
-	VALUE cref = data->klass ?
-	    (VALUE)NEW_NODE(NODE_CREF,data->klass,0,fbody->nd_rval) :
-	    fbody->nd_rval;
-	fbody = NEW_NODE(NODE_SCOPE, fbody->nd_tbl, cref, fbody->nd_next);
-    }
-    st_insert(data->tbl, mid, (st_data_t)NEW_METHOD(fbody, body->nd_noex));
+    st_insert(tbl, mid, (st_data_t)NEW_METHOD(body->nd_body, body->nd_noex));
     return ST_CONTINUE;
 }
 
@@ -78,8 +65,7 @@
 {
     rb_obj_init_copy(clone, orig);
     if (!FL_TEST(CLASS_OF(clone), FL_SINGLETON)) {
-	RBASIC(clone)->klass = RBASIC(orig)->klass;
-	RBASIC(clone)->klass = rb_singleton_class_clone(clone);
+	RBASIC(clone)->klass = rb_singleton_class_clone(orig);
     }
     RCLASS(clone)->super = RCLASS(orig)->super;
     if (RCLASS(orig)->iv_tbl) {
@@ -92,12 +78,9 @@
 	st_delete(RCLASS(clone)->iv_tbl, (st_data_t*)&id, 0);
     }
     if (RCLASS(orig)->m_tbl) {
-	struct clone_method_data data;
-
-	data.tbl = RCLASS(clone)->m_tbl = st_init_numtable();
-	data.klass = (VALUE)clone;
-
-	st_foreach(RCLASS(orig)->m_tbl, clone_method, (st_data_t)&data);
+	RCLASS(clone)->m_tbl = st_init_numtable();
+	st_foreach(RCLASS(orig)->m_tbl, clone_method,
+	  (st_data_t)RCLASS(clone)->m_tbl);
     }
 
     return clone;
@@ -143,22 +126,9 @@
 	if (RCLASS(klass)->iv_tbl) {
 	    clone->iv_tbl = st_copy(RCLASS(klass)->iv_tbl);
 	}
-	{
-	    struct clone_method_data data;
-
-	    data.tbl = clone->m_tbl = st_init_numtable();
-	    switch (TYPE(obj)) {
-	      case T_CLASS:
-	      case T_MODULE:
-		data.klass = obj;
-		break;
-	      default:
-		data.klass = 0;
-		break;
-	    }
-
-	    st_foreach(RCLASS(klass)->m_tbl, clone_method, (st_data_t)&data);
-	}
+	clone->m_tbl = st_init_numtable();
+	st_foreach(RCLASS(klass)->m_tbl, clone_method,
+	  (st_data_t)clone->m_tbl);
 	rb_singleton_class_attached(RBASIC(clone)->klass, (VALUE)clone);
 	FL_SET(clone, FL_SINGLETON);
 	return (VALUE)clone;
Index: ChangeLog
===================================================================
--- ChangeLog	(revision 17222)
+++ ChangeLog	(revision 17218)
@@ -82,11 +82,6 @@
 Fri Jun 13 13:14:31 2008  Yukihiro Matsumoto  <matz@ruby-lang.org>
 
 	* ext/dl/ptr.c (dlmem_each_i): typo fixed.  a patch from IKOMA
-Sun Jun 15 21:06:12 2008  Yukihiro Matsumoto  <matz@ruby-lang.org>
-
-	* class.c (clone_method): should copy cref as well.
-	  [ruby-core:15833]
-
 	  Yoshiki <ikoma@mb.i-chubu.ne.jp> in [ruby-dev:33776].
 
 Fri Jun 13 13:13:23 2008  URABE Shyouhei  <shyouhei@ice.uec.ac.jp>

Also, in case anyone needs it, to apply the diff:

$ cd ruby-1.8.6-release/
$ patch < ../patch.txt 

In the end, both of my typical ruby executables were fine (i686-linux and i686-darwin9.3.0), and happily protected from security vulnerabilities.  Hooray!  The Ruby team has yet to release an official, secure, and Rails-safe version of the 1.8.6 branch.  We’ll see if that’s in the pipeline, or if this is their subtle way of telling people to move onto 1.8.7 (and therefore Rails 2.1).

  1. 2 Responses to “Ruby Security and Patches”

  2. I’m not sure if the word “hooray” is appropriate for a nerd-blog.

    By Steph on Jun 27, 2008

  3. Nerds can be excited about things too! And fixed security vulnerabilities are VERY exciting.

    By Jason on Jun 27, 2008

Post a Comment