Security Fix (CAN-2003-0020): Apache does not filter terminal escape sequences from its error logs, which could make it easier for attackers to insert those sequences into terminal emulators containing vulnerabilities related to escape sequences. Index: src/include/httpd.h --- src/include/httpd.h.orig 2003-10-24 18:11:40.000000000 +0200 +++ src/include/httpd.h 2004-05-12 10:04:43.000000000 +0200 @@ -1028,6 +1028,8 @@ API_EXPORT(char *) ap_construct_server(pool *p, const char *hostname, unsigned port, const request_rec *r); API_EXPORT(char *) ap_escape_logitem(pool *p, const char *str); +API_EXPORT(size_t) ap_escape_errorlog_item(char *dest, const char *source, + size_t buflen); API_EXPORT(char *) ap_escape_shell_cmd(pool *p, const char *s); API_EXPORT(int) ap_count_dirs(const char *path); Index: src/main/http_log.c --- src/main/http_log.c.orig 2003-02-03 18:13:21.000000000 +0100 +++ src/main/http_log.c 2004-05-12 10:04:43.000000000 +0200 @@ -314,6 +314,9 @@ const char *fmt, va_list args) { char errstr[MAX_STRING_LEN]; +#ifndef AP_UNSAFE_ERROR_LOG_UNESCAPED + char scratch[MAX_STRING_LEN]; +#endif size_t len; int save_errno = errno; FILE *logf; @@ -445,7 +448,14 @@ } #endif +#ifndef AP_UNSAFE_ERROR_LOG_UNESCAPED + if (ap_vsnprintf(scratch, sizeof(scratch) - len, fmt, args)) { + len += ap_escape_errorlog_item(errstr + len, scratch, + sizeof(errstr) - len); + } +#else len += ap_vsnprintf(errstr + len, sizeof(errstr) - len, fmt, args); +#endif /* NULL if we are logging to syslog */ if (logf) { Index: src/main/util.c --- src/main/util.c.orig 2003-02-03 18:13:23.000000000 +0100 +++ src/main/util.c 2004-05-12 10:04:43.000000000 +0200 @@ -1520,6 +1520,69 @@ return ret; } +API_EXPORT(size_t) ap_escape_errorlog_item(char *dest, const char *source, + 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); +} API_EXPORT(char *) ap_escape_shell_cmd(pool *p, const char *str) {