From: Joe Orton Date: Wed, 15 Sep 2004 11:50:43 +0000 (+0000) Subject: Backport from HEAD: X-Git-Tag: 2.0.52~49 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=2831b6f51d6ae71b5566c1d6c2032aba6a2b4f3c;p=thirdparty%2Fapache%2Fhttpd.git Backport from HEAD: * server/util.c (ap_resolve_env): Rewrite to avoid buffer overflows. Submitted by: Andr�� Malo Reviewed by: jorton, mjc git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/APACHE_2_0_BRANCH@105131 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/CHANGES b/CHANGES index 7b39a681b28..d043909616a 100644 --- a/CHANGES +++ b/CHANGES @@ -1,5 +1,9 @@ Changes with Apache 2.0.51 + *) SECURITY: CAN-2004-0747 (cve.mitre.org) + Fix buffer overflow in expansion of environment variables in + configuration file parsing. [André Malo] + *) SECURITY: CAN-2004-0809 (cve.mitre.org) mod_dav_fs: Fix a segfault in the handling of an indirect lock refresh. PR 31183. [Joe Orton] diff --git a/server/util.c b/server/util.c index 4497fdf4ad4..b7070241321 100644 --- a/server/util.c +++ b/server/util.c @@ -722,7 +722,7 @@ static char *substring_conf(apr_pool_t *p, const char *start, int len, *resp++ = '\0'; #if RESOLVE_ENV_PER_TOKEN - return ap_resolve_env(p,result); + return (char *)ap_resolve_env(p,result); #else return result; #endif @@ -782,39 +782,87 @@ AP_DECLARE(char *) ap_getword_conf(apr_pool_t *p, const char **line) */ AP_DECLARE(const char *) ap_resolve_env(apr_pool_t *p, const char * word) { - char tmp[ MAX_STRING_LEN ]; - const char *s, *e; - tmp[0] = '\0'; - - if (!(s=ap_strchr_c(word,'$'))) - return word; - - do { - /* XXX - relies on strncat() to add '\0' - */ - strncat(tmp,word,s - word); - if ((s[1] == '{') && (e=ap_strchr_c(s,'}'))) { - const char *e2 = e; - char *var; - word = e + 1; - var = apr_pstrndup(p, s+2, e2-(s+2)); - e = getenv(var); - if (e) { - strcat(tmp,e); - } else { - strncat(tmp, s, e2-s); - strcat(tmp,"}"); - } - } else { - /* ignore invalid strings */ - word = s+1; - strcat(tmp,"$"); - }; - } while ((s=ap_strchr_c(word,'$'))); - strcat(tmp,word); - - return apr_pstrdup(p,tmp); +# define SMALL_EXPANSION 5 + struct sll { + struct sll *next; + const char *string; + apr_size_t len; + } *result, *current, sresult[SMALL_EXPANSION]; + char *res_buf, *cp; + const char *s, *e, *ep; + unsigned spc; + apr_size_t outlen; + + s = ap_strchr_c(word, '$'); + if (!s) { + return word; + } + + /* well, actually something to do */ + ep = word + strlen(word); + spc = 0; + result = current = &(sresult[spc++]); + current->next = NULL; + current->string = word; + current->len = s - word; + outlen = current->len; + + do { + /* prepare next entry */ + if (current->len) { + current->next = (spc < SMALL_EXPANSION) + ? &(sresult[spc++]) + : (struct sll *)apr_palloc(p, + sizeof(*current->next)); + current = current->next; + current->next = NULL; + current->len = 0; + } + + if (*s == '$') { + if (s[1] == '{' && (e = ap_strchr_c(s, '}'))) { + word = getenv(apr_pstrndup(p, s+2, e-s-2)); + if (word) { + current->string = word; + current->len = strlen(word); + outlen += current->len; + } + else { + current->string = s; + current->len = e - s + 1; + outlen += current->len; + } + s = e + 1; + } + else { + current->string = s++; + current->len = 1; + ++outlen; + } + } + else { + word = s; + s = ap_strchr_c(s, '$'); + current->string = word; + current->len = s ? s - word : ep - word; + outlen += current->len; + } + } while (s && *s); + + /* assemble result */ + res_buf = cp = apr_palloc(p, outlen + 1); + do { + if (result->len) { + memcpy(cp, result->string, result->len); + cp += result->len; + } + result = result->next; + } while (result); + res_buf[outlen] = '\0'; + + return res_buf; } + AP_DECLARE(int) ap_cfg_closefile(ap_configfile_t *cfp) { #ifdef DEBUG