From 56736ca88371ddcea279cdad96aaebdb7366e185 Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Tue, 26 Aug 2008 15:22:00 +0000 Subject: [PATCH] #1217: libt/shttpd: "shttpd crash in decide_what_to_do()" --- third-party/shttpd/config.h | 1 + third-party/shttpd/log.c | 64 ++++++++++++++++++++++--------------- third-party/shttpd/shttpd.c | 21 +++++++----- 3 files changed, 53 insertions(+), 33 deletions(-) diff --git a/third-party/shttpd/config.h b/third-party/shttpd/config.h index cbe1f8ebd..8ecd334df 100644 --- a/third-party/shttpd/config.h +++ b/third-party/shttpd/config.h @@ -15,6 +15,7 @@ #define CONFIG_FILE "shttpd.conf" /* Configuration file */ #define HTPASSWD ".htpasswd" /* Passwords file name */ #define URI_MAX 16384 /* Default max request size */ +#define IO_BUFSIZE 65536 /* IO buffer size */ #define LISTENING_PORTS "80" /* Default listening ports */ #define INDEX_FILES "index.html,index.htm,index.php,index.cgi" #define CGI_EXT "cgi,pl,php" /* Default CGI extensions */ diff --git a/third-party/shttpd/log.c b/third-party/shttpd/log.c index 8c506f423..ec9d86207 100644 --- a/third-party/shttpd/log.c +++ b/third-party/shttpd/log.c @@ -16,8 +16,6 @@ void _shttpd_elog(int flags, struct conn *c, const char *fmt, ...) { - char date[64], buf[URI_MAX]; - int len; FILE *fp = c == NULL ? NULL : c->ctx->error_log; va_list ap; @@ -29,23 +27,29 @@ _shttpd_elog(int flags, struct conn *c, const char *fmt, ...) va_end(ap); } - strftime(date, sizeof(date), "%a %b %d %H:%M:%S %Y", - localtime(&_shttpd_current_time)); - - len = _shttpd_snprintf(buf, sizeof(buf), - "[%s] [error] [client %s] \"%s\" ", - date, c ? inet_ntoa(c->sa.u.sin.sin_addr) : "-", - c && c->request ? c->request : "-"); - - va_start(ap, fmt); - (void) vsnprintf(buf + len, sizeof(buf) - len, fmt, ap); - va_end(ap); - - buf[sizeof(buf) - 1] = '\0'; - if (fp != NULL && (flags & (E_FATAL | E_LOG))) { + char date[64]; + char *buf = malloc( URI_MAX ); + int len; + + strftime(date, sizeof(date), "%a %b %d %H:%M:%S %Y", + localtime(&_shttpd_current_time)); + + len = _shttpd_snprintf(buf, URI_MAX, + "[%s] [error] [client %s] \"%s\" ", + date, c ? inet_ntoa(c->sa.u.sin.sin_addr) : "-", + c && c->request ? c->request : "-"); + + va_start(ap, fmt); + (void) vsnprintf(buf + len, URI_MAX - len, fmt, ap); + va_end(ap); + + buf[URI_MAX - 1] = '\0'; + (void) fprintf(fp, "%s\n", buf); (void) fflush(fp); + + free(buf); } if (flags & E_FATAL) @@ -57,10 +61,18 @@ _shttpd_log_access(FILE *fp, const struct conn *c) { static const struct vec dash = {"-", 1}; - const struct vec *user = &c->ch.user.v_vec; - const struct vec *referer = &c->ch.referer.v_vec; - const struct vec *user_agent = &c->ch.useragent.v_vec; - char date[64], buf[URI_MAX], *q1 = "\"", *q2 = "\""; + const struct vec *user; + const struct vec *referer; + const struct vec *user_agent; + char date[64], *buf, *q1, *q2; + + if (fp == NULL) + return; + + user = &c->ch.user.v_vec; + referer = &c->ch.referer.v_vec; + user_agent = &c->ch.useragent.v_vec; + q1 = q2 = "\""; if (user->len == 0) user = ‐ @@ -78,7 +90,9 @@ _shttpd_log_access(FILE *fp, const struct conn *c) (void) strftime(date, sizeof(date), "%d/%b/%Y:%H:%M:%S", localtime(&c->birth_time)); - (void) _shttpd_snprintf(buf, sizeof(buf), + buf = malloc(URI_MAX); + + (void) _shttpd_snprintf(buf, URI_MAX, "%s - %.*s [%s %+05d] \"%s\" %d %lu %s%.*s%s %s%.*s%s", inet_ntoa(c->sa.u.sin.sin_addr), user->len, user->ptr, date, _shttpd_tz_offset, c->request ? c->request : "-", @@ -86,8 +100,8 @@ _shttpd_log_access(FILE *fp, const struct conn *c) q1, referer->len, referer->ptr, q1, q2, user_agent->len, user_agent->ptr, q2); - if (fp != NULL) { - (void) fprintf(fp, "%s\n", buf); - (void) fflush(fp); - } + (void) fprintf(fp, "%s\n", buf); + (void) fflush(fp); + + free(buf); } diff --git a/third-party/shttpd/shttpd.c b/third-party/shttpd/shttpd.c index f75b160fb..00e060236 100644 --- a/third-party/shttpd/shttpd.c +++ b/third-party/shttpd/shttpd.c @@ -533,7 +533,8 @@ get_path_info(struct conn *c, char *path, struct stat *stp) static void decide_what_to_do(struct conn *c) { - char path[URI_MAX], buf[1024], *root; + char *path; + const char *root; struct vec alias_uri, alias_path; struct stat st; int rc; @@ -548,16 +549,17 @@ decide_what_to_do(struct conn *c) remove_double_dots(c->uri); root = c->ctx->options[OPT_ROOT]; - if (strlen(c->uri) + strlen(root) >= sizeof(path)) { + if (strlen(c->uri) + strlen(root) >= URI_MAX) { _shttpd_send_server_error(c, 400, "URI is too long"); return; } - (void) _shttpd_snprintf(path, sizeof(path), "%s%s", root, c->uri); + path = malloc( URI_MAX ); + (void) _shttpd_snprintf(path, URI_MAX, "%s%s", root, c->uri); /* User may use the aliases - check URI for mount point */ if (is_alias(c->ctx, c->uri, &alias_uri, &alias_path) != NULL) { - (void) _shttpd_snprintf(path, sizeof(path), "%.*s%s", + (void) _shttpd_snprintf(path, URI_MAX, "%.*s%s", alias_path.len, alias_path.ptr, c->uri + alias_uri.len); DBG(("using alias %.*s -> %.*s", alias_uri.len, alias_uri.ptr, alias_path.len, alias_path.ptr)); @@ -612,11 +614,12 @@ decide_what_to_do(struct conn *c) } else if (get_path_info(c, path, &st) != 0) { _shttpd_send_server_error(c, 404, "Not Found"); } else if (S_ISDIR(st.st_mode) && path[strlen(path) - 1] != '/') { + char buf[1024]; (void) _shttpd_snprintf(buf, sizeof(buf), "Moved Permanently\r\nLocation: %s/", c->uri); _shttpd_send_server_error(c, 301, buf); } else if (S_ISDIR(st.st_mode) && - find_index_file(c, path, sizeof(path) - 1, &st) == -1 && + find_index_file(c, path, URI_MAX - 1, &st) == -1 && !IS_TRUE(c->ctx, OPT_DIR_LIST)) { _shttpd_send_server_error(c, 403, "Directory Listing Denied"); } else if (S_ISDIR(st.st_mode) && IS_TRUE(c->ctx, OPT_DIR_LIST)) { @@ -655,6 +658,8 @@ decide_what_to_do(struct conn *c) } else { _shttpd_send_server_error(c, 500, "Internal Error"); } + + free(path); } static int @@ -781,7 +786,7 @@ add_socket(struct worker *worker, int sock, int is_ssl) (void) closesocket(sock); SSL_free(ssl); #endif /* NO_SSL */ - } else if ((c = calloc(1, sizeof(*c) + 2 * URI_MAX)) == NULL) { + } else if ((c = calloc(1, sizeof(*c) + 2 * IO_BUFSIZE)) == NULL) { #if !defined(NO_SSL) if (ssl) SSL_free(ssl); @@ -808,8 +813,8 @@ add_socket(struct worker *worker, int sock, int is_ssl) /* Set IO buffers */ c->loc.io.buf = (char *) (c + 1); - c->rem.io.buf = c->loc.io.buf + URI_MAX; - c->loc.io.size = c->rem.io.size = URI_MAX; + c->rem.io.buf = c->loc.io.buf + IO_BUFSIZE; + c->loc.io.size = c->rem.io.size = IO_BUFSIZE; #if !defined(NO_SSL) if (is_ssl) {