[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Patch for fixing CAN-2004-0940 in apache 1.3



Hi Debian Security team!

I prepared a patch for fixing a mod_include buffer overflow in Ubuntu
and was asked by Fabio to upload a fixed sid version as well
(1.3.31-7).

Please also see

  http://www.apacheweek.com/features/security-13

(first item).

The patch is from the stable upstream release 1.3.33, I tested this on
a local apache installation without apparent regressions.

Please find attached the interdiff that was used for 1.3.31-7; you can
remove the "Uploaders:" change; the "patch" patch should give no
problems, just the changelog patch will probably fail due to a
different woody version.

Unfortunately I do not have time to prepare an updated woody package.

Thanks for your work and have a nice day!

Martin

-- 
Martin Pitt                       http://www.piware.de
Ubuntu Developer            http://www.ubuntulinux.org
Debian GNU/Linux Developer       http://www.debian.org
diff -u apache-1.3.31/debian/changelog apache-1.3.31/debian/changelog
--- apache-1.3.31/debian/changelog
+++ apache-1.3.31/debian/changelog
@@ -1,3 +1,13 @@
+apache (1.3.31-7) unstable; urgency=high
+
+  * SECURITY UPDATE to fix a buffer overflow in mod_include
+  * added patch 000_stolen_from_HEAD_CAN-2004-0940, backported from upstream
+    CVS (CAN-2004-0940)
+  * Same security update as for Ubuntu, Fabio asked me to upload and add
+    myself to Uploaders.
+
+ -- Martin Pitt <mpitt@debian.org>  Fri, 29 Oct 2004 10:18:38 +0200
+
 apache (1.3.31-6) unstable; urgency=medium
 
   * (Fabio M. Di Nitto)
diff -u apache-1.3.31/debian/control apache-1.3.31/debian/control
--- apache-1.3.31/debian/control
+++ apache-1.3.31/debian/control
@@ -2,7 +2,7 @@
 Section: web
 Priority: optional
 Maintainer: Debian Apache Maintainers <debian-apache@lists.debian.org>
-Uploaders: Tollef Fog Heen <tfheen@debian.org>, Thom May <thom@debian.org>, Fabio M. Di Nitto <fabbione@fabbione.net>, Matthew Wilcox <willy@debian.org>, Amaya Rodrigo Sastre <amaya@debian.org>
+Uploaders: Tollef Fog Heen <tfheen@debian.org>, Thom May <thom@debian.org>, Fabio M. Di Nitto <fabbione@fabbione.net>, Matthew Wilcox <willy@debian.org>, Amaya Rodrigo Sastre <amaya@debian.org>, Martin Pitt <mpitt@debian.org>
 Standards-Version: 3.6.1
 Build-Depends: debhelper (>= 4.1.16), sharutils, libdb4.2-dev (>= 4.2.52), libexpat1-dev, imagemagick, libssl-dev, perl (>= 5.8.4-2), libperl-dev (>= 5.8.4-2), libwww-perl, libdevel-symdump-perl, libhtml-parser-perl, po-debconf
 
only in patch2:
unchanged:
--- apache-1.3.31.orig/debian/patches/000_stolen_from_HEAD_CAN-2004-0940
+++ apache-1.3.31/debian/patches/000_stolen_from_HEAD_CAN-2004-0940
@@ -0,0 +1,215 @@
+===================================================================
+RCS file: /home/cvspublic/apache-1.3/src/modules/standard/mod_include.c,v
+retrieving revision 1.140
+retrieving revision 1.141
+diff -u -r1.140 -r1.141
+--- build-tree.orig/apache_1.3.31/src/modules/standard/mod_include.c	2004/02/28 22:19:04	1.140
++++ build-tree/apache_1.3.31/src/modules/standard/mod_include.c		2004/10/22 19:31:08	1.141
+@@ -309,9 +309,10 @@
+  * the tag value is html decoded if dodecode is non-zero
+  */
+ 
+-static char *get_tag(pool *p, FILE *in, char *tag, int tagbuf_len, int dodecode)
++static char *get_tag(request_rec *r, FILE *in, char *tag, int tagbuf_len, int dodecode)
+ {
+     char *t = tag, *tag_val, c, term;
++    pool *p = r->pool;
+ 
+     /* makes code below a little less cluttered */
+     --tagbuf_len;
+@@ -337,7 +338,7 @@
+ 
+     /* find end of tag name */
+     while (1) {
+-        if (t - tag == tagbuf_len) {
++        if (t == tag + tagbuf_len) {
+             *t = '\0';
+             return NULL;
+         }
+@@ -371,16 +372,30 @@
+     term = c;
+     while (1) {
+         GET_CHAR(in, c, NULL, p);
+-        if (t - tag == tagbuf_len) {
++        if (t == tag + tagbuf_len) {
+             *t = '\0';
++            ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,
++                          "mod_include: value length exceeds limit"
++                          " (%d) in %s", tagbuf_len, r->filename);
+             return NULL;
+         }
+-/* Want to accept \" as a valid character within a string. */
++        /* Want to accept \" as a valid character within a string. */
+         if (c == '\\') {
+-            *(t++) = c;         /* Add backslash */
+             GET_CHAR(in, c, NULL, p);
+-            if (c == term) {    /* Only if */
+-                *(--t) = c;     /* Replace backslash ONLY for terminator */
++            /* Insert backslash only if not escaping a terminator char */
++            if (c != term) {
++                *(t++) = '\\';
++                /*
++                 * check to make sure that adding in the backslash won't cause
++                 * an overflow, since we're now 1 character ahead.
++                 */
++                if (t == tag + tagbuf_len) {
++                    *t = '\0';
++                    ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,
++                                  "mod_include: value length exceeds limit"
++                                  " (%d) in %s", tagbuf_len, r->filename);
++                    return NULL;
++                }
+             }
+         }
+         else if (c == term) {
+@@ -395,9 +410,10 @@
+     return ap_pstrdup(p, tag_val);
+ }
+ 
+-static int get_directive(FILE *in, char *dest, size_t len, pool *p)
++static int get_directive(FILE *in, char *dest, size_t len, request_rec *r)
+ {
+     char *d = dest;
++    pool *p = r->pool;
+     char c;
+ 
+     /* make room for nul terminator */
+@@ -413,6 +429,9 @@
+     /* now get directive */
+     while (1) {
+ 	if (d == len + dest) {
++            ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,
++                          "mod_include: directive length exceeds limit"
++                          " (%d) in %s", len+1, r->filename);
+ 	    return 1;
+ 	}
+         *d++ = ap_tolower(c);
+@@ -616,7 +635,7 @@
+     char *tag_val;
+ 
+     while (1) {
+-        if (!(tag_val = get_tag(r->pool, in, tag, sizeof(tag), 1))) {
++        if (!(tag_val = get_tag(r, in, tag, sizeof(tag), 1))) {
+             return 1;
+         }
+         if (!strcmp(tag, "file") || !strcmp(tag, "virtual")) {
+@@ -839,7 +858,7 @@
+     char parsed_string[MAX_STRING_LEN];
+ 
+     while (1) {
+-        if (!(tag_val = get_tag(r->pool, in, tag, sizeof(tag), 1))) {
++        if (!(tag_val = get_tag(r, in, tag, sizeof(tag), 1))) {
+             return 1;
+         }
+         if (!strcmp(tag, "cmd")) {
+@@ -890,7 +909,7 @@
+     encode = E_ENTITY;
+ 
+     while (1) {
+-        if (!(tag_val = get_tag(r->pool, in, tag, sizeof(tag), 1))) {
++        if (!(tag_val = get_tag(r, in, tag, sizeof(tag), 1))) {
+             return 1;
+         }
+         if (!strcmp(tag, "var")) {
+@@ -952,7 +971,7 @@
+         return DECLINED;
+     }
+     while (1) {
+-        if (!(tag_val = get_tag(r->pool, in, tag, sizeof(tag), 1))) {
++        if (!(tag_val = get_tag(r, in, tag, sizeof(tag), 1))) {
+             break;
+         }
+         if (strnEQ(tag, "sub", 3)) {
+@@ -985,7 +1004,7 @@
+     table *env = r->subprocess_env;
+ 
+     while (1) {
+-        if (!(tag_val = get_tag(r->pool, in, tag, sizeof(tag), 0))) {
++        if (!(tag_val = get_tag(r, in, tag, sizeof(tag), 0))) {
+             return 1;
+         }
+         if (!strcmp(tag, "errmsg")) {
+@@ -1101,7 +1120,7 @@
+     char parsed_string[MAX_STRING_LEN];
+ 
+     while (1) {
+-        if (!(tag_val = get_tag(r->pool, in, tag, sizeof(tag), 1))) {
++        if (!(tag_val = get_tag(r, in, tag, sizeof(tag), 1))) {
+             return 1;
+         }
+         else if (!strcmp(tag, "done")) {
+@@ -1141,7 +1160,7 @@
+     char parsed_string[MAX_STRING_LEN];
+ 
+     while (1) {
+-        if (!(tag_val = get_tag(r->pool, in, tag, sizeof(tag), 1))) {
++        if (!(tag_val = get_tag(r, in, tag, sizeof(tag), 1))) {
+             return 1;
+         }
+         else if (!strcmp(tag, "done")) {
+@@ -1917,7 +1936,7 @@
+ 
+     expr = NULL;
+     while (1) {
+-        tag_val = get_tag(r->pool, in, tag, sizeof(tag), 0);
++        tag_val = get_tag(r, in, tag, sizeof(tag), 0);
+         if (!tag_val || *tag == '\0') {
+             return 1;
+         }
+@@ -1960,7 +1979,7 @@
+ 
+     expr = NULL;
+     while (1) {
+-        tag_val = get_tag(r->pool, in, tag, sizeof(tag), 0);
++        tag_val = get_tag(r, in, tag, sizeof(tag), 0);
+         if (!tag_val || *tag == '\0') {
+             return 1;
+         }
+@@ -2007,7 +2026,7 @@
+ {
+     char tag[MAX_STRING_LEN];
+ 
+-    if (!get_tag(r->pool, in, tag, sizeof(tag), 1)) {
++    if (!get_tag(r, in, tag, sizeof(tag), 1)) {
+         return 1;
+     }
+     else if (!strcmp(tag, "done")) {
+@@ -2035,7 +2054,7 @@
+ {
+     char tag[MAX_STRING_LEN];
+ 
+-    if (!get_tag(r->pool, in, tag, sizeof(tag), 1)) {
++    if (!get_tag(r, in, tag, sizeof(tag), 1)) {
+         return 1;
+     }
+     else if (!strcmp(tag, "done")) {
+@@ -2065,7 +2084,7 @@
+ 
+     var = (char *) NULL;
+     while (1) {
+-        if (!(tag_val = get_tag(r->pool, in, tag, sizeof(tag), 1))) {
++        if (!(tag_val = get_tag(r, in, tag, sizeof(tag), 1))) {
+             return 1;
+         }
+         else if (!strcmp(tag, "done")) {
+@@ -2102,7 +2121,7 @@
+     table_entry *elts = (table_entry *) arr->elts;
+     int i;
+ 
+-    if (!(tag_val = get_tag(r->pool, in, tag, sizeof(tag), 1))) {
++    if (!(tag_val = get_tag(r, in, tag, sizeof(tag), 1))) {
+         return 1;
+     }
+     else if (!strcmp(tag, "done")) {
+@@ -2173,10 +2192,7 @@
+ 
+     while (1) {
+         if (!find_string(f, STARTING_SEQUENCE, r, printing)) {
+-            if (get_directive(f, directive, sizeof(directive), r->pool)) {
+-		ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,
+-			    "mod_include: error reading directive in %s",
+-			    r->filename);
++            if (get_directive(f, directive, sizeof(directive), r)) {
+ 		ap_rputs(error, r);
+                 return;
+             }

Attachment: signature.asc
Description: Digital signature


Reply to: