$OpenBSD: patch-array_c,v 1.1 2008/07/21 09:40:42 bernd Exp $

Fixes multiple security vulnerabilities.
http://secunia.com/advisories/29794/

Patch against ruby-1.8.6p114 from:
http://blog.phusion.nl/assets/r8ee-security-patch-20080623-2.txt
and
https://launchpad.net/ubuntu/+source/ruby1.8

1.8.6-p229 and 1.8.7-p21 will break rails applications.

--- array.c.orig	Fri Sep  7 09:46:40 2007
+++ array.c	Tue Jul  1 20:47:08 2008
@@ -20,6 +20,7 @@ VALUE rb_cArray;
 static ID id_cmp;
 
 #define ARY_DEFAULT_SIZE 16
+#define	ARY_MAX_SIZE (LONG_MAX / sizeof(VALUE))
 
 void
 rb_mem_clear(mem, size)
@@ -120,7 +121,7 @@ ary_new(klass, len)
     if (len < 0) {
 	rb_raise(rb_eArgError, "negative array size (or size too big)");
     }
-    if (len > 0 && len * sizeof(VALUE) <= len) {
+    if (len > ARY_MAX_SIZE) {
 	rb_raise(rb_eArgError, "array size too big");
     }
     if (len == 0) len++;
@@ -293,7 +294,7 @@ rb_ary_initialize(argc, argv, ary)
     if (len < 0) {
 	rb_raise(rb_eArgError, "negative array size");
     }
-    if (len > 0 && len * (long)sizeof(VALUE) <= len) {
+    if (len > ARY_MAX_SIZE) {
 	rb_raise(rb_eArgError, "array size too big");
     }
     if (len > RARRAY(ary)->aux.capa) {
@@ -359,6 +360,10 @@ rb_ary_store(ary, idx, val)
 	}
     }
 
+    if (idx >= ARY_MAX_SIZE) {
+        rb_raise(rb_eIndexError, "index %ld too big", idx);
+    }
+
     rb_ary_modify(ary);
     if (idx >= RARRAY(ary)->aux.capa) {
 	long new_capa = RARRAY(ary)->aux.capa / 2;
@@ -366,6 +371,9 @@ rb_ary_store(ary, idx, val)
 	if (new_capa < ARY_DEFAULT_SIZE) {
 	    new_capa = ARY_DEFAULT_SIZE;
 	}
+	if (new_capa >= ARY_MAX_SIZE - idx) {
+	    new_capa = (ARY_MAX_SIZE - idx) / 2;
+	}
 	new_capa += idx;
 	if (new_capa * (long)sizeof(VALUE) <= new_capa) {
 	    rb_raise(rb_eArgError, "index too big");
@@ -975,6 +983,9 @@ rb_ary_splice(ary, beg, len, rpl)
     rb_ary_modify(ary);
 
     if (beg >= RARRAY(ary)->len) {
+	if (beg > ARY_MAX_SIZE - rlen) {
+	    rb_raise(rb_eIndexError, "index %ld too big", beg);
+	}
 	len = beg + rlen;
 	if (len >= RARRAY(ary)->aux.capa) {
 	    REALLOC_N(RARRAY(ary)->ptr, VALUE, len);
@@ -2378,7 +2389,7 @@ rb_ary_times(ary, times)
     if (len < 0) {
 	rb_raise(rb_eArgError, "negative argument");
     }
-    if (LONG_MAX/len < RARRAY(ary)->len) {
+    if (ARY_MAX_SIZE/len < RARRAY(ary)->len) {
 	rb_raise(rb_eArgError, "argument too big");
     }
     len *= RARRAY(ary)->len;
