Package: ruby1.8
Version: 1.8.2-7sarge2
Severity: grave
Tags: security patch
Justification: user security hole


Japan Vender Status Notes (JVN) announced two vulnerabilities for Ruby.

JVN#13947696:

Some methods have defects that they can call other methods, which
really should be prohibited, in safe level 4.

* Information:
  * http://jvn.jp/jp/JVN%2313947696/index.html (in Japanese)
  * http://www.ipa.go.jp/security/vuln/documents/2006/JVN_13947696_Ruby.html 
(in Japanese)
* Affected versions: All versions and snapshots before Ruby 1.8.4-20060516.

JVN#83768862:

Alias features cannot handle safe levels correclty, so it can be safety
bypass.

* Information:
  * http://jvn.jp/jp/JVN%2383768862/index.html (in Japanese)
  * http://www.ipa.go.jp/security/vuln/documents/2006/JVN_13947696_Ruby.html 
(in Japanese)
* Affected versions: All versions and snapshots before Ruby 1.8.4-20060516.

Since currently the upstream does not plan to release patches,
I've created ones to fix them.  I wish they works, but I have no
confidence (especially for JVN#13947696) and would like to have them reviewed.

alias_safe_level.patch:
  May fix JVN#83768862, based on "eval.c (rb_call0)" part and
  "eval.c (rb_alias)" part for
  http://www.atdot.net/~ko1/w3ml/w3ml.cgi/ruby-cvs/msg/16613
  (and 
http://www.ruby-lang.org/cgi-bin/cvsweb.cgi/ruby/eval.c?cvsroot=src&r1=1.616.2.166&r2=1.616.2.167
 ).

avoid_modifying_untainted_objects.patch:
  May fix JVN#13947696, based on "re.c (rb_reg_initialize)" part for
  http://www.atdot.net/~ko1/w3ml/w3ml.cgi/ruby-cvs/msg/16723
  (and 
http://www.ruby-lang.org/cgi-bin/cvsweb.cgi/ruby/re.c?cvsroot=src&r1=1.114.2.17&r2=1.114.2.18
 ).

avoid_modifying_untainted_objects_2.patch:
  May fix JVN#13947696, based on
  http://www.atdot.net/~ko1/w3ml/w3ml.cgi/ruby-cvs/msg/16724
  (and 
http://www.ruby-lang.org/cgi-bin/cvsweb.cgi/ruby/dir.c?cvsroot=src&r1=1.92.2.32&r2=1.92.2.33
 ).


-- System Information:
Debian Release: 3.1
Architecture: i386 (i686)
Kernel: Linux 2.6.8-3-686
Locale: LANG=ja_JP.eucJP, LC_CTYPE=ja_JP.eucJP (charmap=EUC-JP)

Versions of packages ruby1.8 depends on:
ii  libc6                 2.3.2.ds1-22sarge3 GNU C Library: Shared libraries an
ii  libruby1.8            1.8.2-7sarge2      Libraries necessary to run Ruby 1.

-- no debconf information
--- eval.c.orig Thu Jul 13 01:48:12 2006
+++ eval.c      Thu Jul 13 01:49:37 2006
@@ -2050,7 +2050,8 @@
        }
     }
     st_insert(RCLASS(klass)->m_tbl, name,
-      (st_data_t)NEW_METHOD(NEW_FBODY(body, def, origin), orig->nd_noex));
+             (st_data_t)NEW_METHOD(NEW_FBODY(body, def, origin),
+                                   NOEX_WITH_SAFE(orig->nd_noex)));
     if (singleton) {
        rb_funcall(singleton, singleton_added, 1, ID2SYM(name));
     }
@@ -5561,6 +5562,11 @@
     TMP_PROTECT;
     volatile int safe = -1;
 
+    if (NOEX_SAFE(flags) > ruby_safe_level &&
+       !(flags&NOEX_TAINTED) && ruby_safe_level == 0 && NOEX_SAFE(flags) > 2) {
+       rb_raise(rb_eSecurityError, "calling insecure method: %s",
+                rb_id2name(id));
+    }
     switch (ruby_iter->iter) {
       case ITER_PRE:
        itr = ITER_CUR;
@@ -5664,10 +5670,6 @@
            b2 = body = body->nd_next;
 
            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);
            }
--- re.c.orig	Thu Jul 13 01:48:12 2006
+++ re.c	Thu Jul 13 01:49:45 2006
@@ -1330,6 +1330,8 @@
 {
     struct RRegexp *re = RREGEXP(obj);
 
+    if (!OBJ_TAINTED(obj) && rb_safe_level() >= 4)
+	rb_raise(rb_eSecurityError, "Insecure: can't modify regexp");
     if (re->ptr) re_free_pattern(re->ptr);
     if (re->str) free(re->str);
     re->ptr = 0;
--- dir.c.orig	Thu Jul 13 01:48:12 2006
+++ dir.c	Thu Jul 13 01:49:53 2006
@@ -325,7 +325,17 @@
     rb_raise(rb_eIOError, "closed directory");
 }
 
+static void
+dir_check(dir)
+    VALUE dir;
+{
+    if (!OBJ_TAINTED(dir) && rb_safe_level() >= 4)
+	rb_raise(rb_eSecurityError, "Insecure: operation on untainted Dir");
+    rb_check_frozen(dir);
+}
+
 #define GetDIR(obj, dirp) do {\
+    dir_check(dir);\
     Data_Get_Struct(obj, struct dir_data, dirp);\
     if (dirp->dir == NULL) dir_closed();\
 } while (0)
@@ -535,6 +545,9 @@
 {
     struct dir_data *dirp;
 
+    if (rb_safe_level() >= 4 && !OBJ_TAINTED(dir)) {
+	rb_raise(rb_eSecurityError, "Insecure: can't close");
+    }
     GetDIR(dir, dirp);
     closedir(dirp->dir);
     dirp->dir = NULL;

Reply via email to