From: André Malo Date: Sun, 14 Dec 2003 17:32:04 +0000 (+0000) Subject: SECURITY [CAN-2003-0020]: escape arbitrary data before writing into the X-Git-Tag: 2.0.49~286 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=0a5fc013c2e2ebad4ecf448c3f25568e0fc968e8;p=thirdparty%2Fapache%2Fhttpd.git SECURITY [CAN-2003-0020]: escape arbitrary data before writing into the errorlog. Reviewed by: Mark J Cox, Erik Abele, Jeff Trawick git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/APACHE_2_0_BRANCH@102059 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/CHANGES b/CHANGES index 649c3cb700b..d61afdfb9ec 100644 --- a/CHANGES +++ b/CHANGES @@ -1,5 +1,8 @@ Changes with Apache 2.0.49 + *) SECURITY [CAN-2003-0020]: Escape arbitrary data before writing + into the errorlog. [André Malo] + *) mod_autoindex / core: Don't fail to show filenames containing special characters like '%'. PR 13598. [André Malo] diff --git a/STATUS b/STATUS index c9c930f35a4..b0f65f5c22b 100644 --- a/STATUS +++ b/STATUS @@ -1,5 +1,5 @@ APACHE 2.0 STATUS: -*-text-*- -Last modified at [$Date: 2003/12/14 16:21:43 $] +Last modified at [$Date: 2003/12/14 17:32:03 $] Release: @@ -62,14 +62,6 @@ Contributors looking for a mission: RELEASE SHOWSTOPPERS: - * core: Escape arbitrary data before writing into the errorlog - [CAN-2003-0020] (2.0 + 1.3) - include/ap_mmn.h: r1.61 - include/httpd.h: r1.203 - server/log.c: r1.136 - server/util.c: r1.143 - +1: nd, erikabele, trawick - PATCHES TO BACKPORT FROM 2.1 [ please place file names and revisions from HEAD here, so it is easy to identify exactly what the proposed changes are! ] diff --git a/include/ap_mmn.h b/include/ap_mmn.h index 97f8ad12bdf..d07d428ae94 100644 --- a/include/ap_mmn.h +++ b/include/ap_mmn.h @@ -114,6 +114,7 @@ * 20020903.2 (2.0.46-dev) add ap_escape_logitem * 20020903.3 (2.0.46-dev) allow_encoded_slashes added to core_dir_config * 20020903.4 (2.0.47-dev) add ap_is_recursion_limit_exceeded() + * 20020903.5 (2.0.49-dev) add ap_escape_errorlog_item() */ #define MODULE_MAGIC_COOKIE 0x41503230UL /* "AP20" */ @@ -121,7 +122,7 @@ #ifndef MODULE_MAGIC_NUMBER_MAJOR #define MODULE_MAGIC_NUMBER_MAJOR 20020903 #endif -#define MODULE_MAGIC_NUMBER_MINOR 4 /* 0...n */ +#define MODULE_MAGIC_NUMBER_MINOR 5 /* 0...n */ /** * Determine if the server's current MODULE_MAGIC_NUMBER is at least a diff --git a/include/httpd.h b/include/httpd.h index e5b8b5b2a44..4d50a5e5d19 100644 --- a/include/httpd.h +++ b/include/httpd.h @@ -1371,11 +1371,21 @@ AP_DECLARE(char *) ap_escape_html(apr_pool_t *p, const char *s); /** * Escape a string for logging * @param p The pool to allocate from - * @param s The string to escape + * @param str The string to escape * @return The escaped string */ AP_DECLARE(char *) ap_escape_logitem(apr_pool_t *p, const char *str); +/** + * Escape a string for logging into the error log (without a pool) + * @param dest The buffer to write to + * @param source The string to escape + * @param buflen The buffer size for the escaped string (including \0) + * @return The len of the escaped string (always < maxlen) + */ +AP_DECLARE(apr_size_t) ap_escape_errorlog_item(char *dest, const char *source, + apr_size_t buflen); + /** * Construct a full hostname * @param p The pool to allocate from diff --git a/server/log.c b/server/log.c index 41dbb5b1aa2..19842d3fe93 100644 --- a/server/log.c +++ b/server/log.c @@ -401,7 +401,7 @@ static void log_error_core(const char *file, int line, int level, const request_rec *r, apr_pool_t *pool, const char *fmt, va_list args) { - char errstr[MAX_STRING_LEN]; + char errstr[MAX_STRING_LEN], scratch[MAX_STRING_LEN]; apr_size_t len, errstrlen; apr_file_t *logf = NULL; const char *referer; @@ -536,12 +536,17 @@ static void log_error_core(const char *file, int line, int level, errstr[len] = '\0'; } } + errstrlen = len; - len += apr_vsnprintf(errstr + len, MAX_STRING_LEN - len, fmt, args); + if (apr_vsnprintf(scratch, MAX_STRING_LEN - len, fmt, args)) { + len += ap_escape_errorlog_item(errstr + len, scratch, + MAX_STRING_LEN - len); + } - if (r && (referer = apr_table_get(r->headers_in, "Referer"))) { + if ( r && (referer = apr_table_get(r->headers_in, "Referer")) + && ap_escape_errorlog_item(scratch, referer, MAX_STRING_LEN - len)) { len += apr_snprintf(errstr + len, MAX_STRING_LEN - len, - ", referer: %s", referer); + ", referer: %s", scratch); } /* NULL if we are logging to syslog */ diff --git a/server/util.c b/server/util.c index 251eacd6a77..c1623679f89 100644 --- a/server/util.c +++ b/server/util.c @@ -1837,6 +1837,70 @@ AP_DECLARE(char *) ap_escape_logitem(apr_pool_t *p, const char *str) return ret; } +AP_DECLARE(apr_size_t) ap_escape_errorlog_item(char *dest, const char *source, + apr_size_t buflen) +{ + unsigned char *d, *ep; + const unsigned char *s; + + if (!source || !buflen) { /* be safe */ + return 0; + } + + d = (unsigned char *)dest; + s = (const unsigned char *)source; + ep = d + buflen - 1; + + for (; d < ep && *s; ++s) { + + if (TEST_CHAR(*s, T_ESCAPE_LOGITEM)) { + *d++ = '\\'; + if (d >= ep) { + --d; + break; + } + + switch(*s) { + case '\b': + *d++ = 'b'; + break; + case '\n': + *d++ = 'n'; + break; + case '\r': + *d++ = 'r'; + break; + case '\t': + *d++ = 't'; + break; + case '\v': + *d++ = 'v'; + break; + case '\\': + *d++ = *s; + break; + case '"': /* no need for this in error log */ + d[-1] = *s; + break; + default: + if (d >= ep - 2) { + ep = --d; /* break the for loop as well */ + break; + } + c2x(*s, d); + *d = 'x'; + d += 3; + } + } + else { + *d++ = *s; + } + } + *d = '\0'; + + return (d - (unsigned char *)dest); +} + AP_DECLARE(int) ap_is_directory(apr_pool_t *p, const char *path) { apr_finfo_t finfo;