Author: Eygene Ryabinkin Backport of the SQUID-2012:1 (CVE-2012-5643) vulnerability patch to squid-2.7 --- tools/cachemgr.c.orig 2008-06-25 02:55:11.000000000 +0400 +++ tools/cachemgr.c 2013-01-07 00:19:49.503854125 +0400 @@ -509,12 +509,15 @@ munge_action_line(const char *_buf, cach if ((p = strchr(x, '\n'))) *p = '\0'; action = xstrtok(&x, '\t'); + if (!action) { + xfree(buf); + return ""; + } description = xstrtok(&x, '\t'); if (!description) description = action; - if (!action) - return ""; snprintf(html, sizeof(html), " %s", menu_url(req, action), description); + xfree(buf); return html; } @@ -690,12 +693,12 @@ process_request(cachemgr_request * req) return 0; } if (!check_target_acl(req->hostname, req->port)) { - snprintf(buf, 1024, "target %s:%d not allowed in cachemgr.conf\n", req->hostname, req->port); + snprintf(buf, sizeof(buf), "target %s:%d not allowed in cachemgr.conf\n", req->hostname, req->port); error_html(buf); return 1; } if ((s = socket(PF_INET, SOCK_STREAM, 0)) < 0) { - snprintf(buf, 1024, "socket: %s\n", xstrerror()); + snprintf(buf, sizeof(buf), "socket: %s\n", xstrerror()); error_html(buf); return 1; } @@ -707,13 +710,15 @@ process_request(cachemgr_request * req) } else if (safe_inet_addr(req->hostname, &S.sin_addr)) (void) 0; else { - snprintf(buf, 1024, "Unknown host: %s\n", req->hostname); + close(s); + snprintf(buf, sizeof(buf), "Unknown host: %s\n", req->hostname); error_html(buf); return 1; } S.sin_port = htons(req->port); if (connect(s, (struct sockaddr *) &S, sizeof(struct sockaddr_in)) < 0) { - snprintf(buf, 1024, "connect: %s\n", xstrerror()); + close(s); + snprintf(buf, sizeof(buf), "connect: %s\n", xstrerror()); error_html(buf); return 1; } @@ -764,19 +769,45 @@ static char * read_post_request(void) { char *s; + uint64_t len; + char *endptr; + size_t bufLen; char *buf; - int len; + size_t readLen; + if ((s = getenv("REQUEST_METHOD")) == NULL) return NULL; if (0 != strcasecmp(s, "POST")) return NULL; if ((s = getenv("CONTENT_LENGTH")) == NULL) return NULL; - if ((len = atoi(s)) <= 0) - return NULL; - buf = xmalloc(len + 1); - fread(buf, len, 1, stdin); - buf[len] = '\0'; + if (*s == '-') // negative length content huh? + return NULL; + + endptr = s + strlen(s); + if ((len = strtoll(s, &endptr, 10)) <= 0) + return NULL; + + // limit the input to something reasonable. + // 4KB should be enough for the GET/POST data length, but may be extended. + bufLen = (len < 4096 ? len : 4095); + buf = (char *)xmalloc(bufLen + 1); + + readLen = fread(buf, 1, bufLen, stdin); + if (readLen == 0) { + xfree(buf); + return NULL; + } + buf[readLen] = '\0'; + len -= readLen; + + // purge the remainder of the request entity + while (len > 0 && readLen) { + char temp[65535]; + readLen = fread(temp, 1, 65535, stdin); + len -= readLen; + } + return buf; } @@ -886,26 +917,38 @@ decode_pub_auth(cachemgr_request * req) buf = xstrdup(base64_decode(req->pub_auth)); debug(3) fprintf(stderr, "cmgr: length ok\n"); /* parse ( a lot of memory leaks, but that is cachemgr style :) */ - if ((host_name = strtok(buf, "|")) == NULL) + if ((host_name = strtok(buf, "|")) == NULL) { + xfree(buf); return; + } debug(3) fprintf(stderr, "cmgr: decoded host: '%s'\n", host_name); - if ((time_str = strtok(NULL, "|")) == NULL) + if ((time_str = strtok(NULL, "|")) == NULL) { + xfree(buf); return; + } debug(3) fprintf(stderr, "cmgr: decoded time: '%s' (now: %d)\n", time_str, (int) now); - if ((user_name = strtok(NULL, "|")) == NULL) + if ((user_name = strtok(NULL, "|")) == NULL) { + xfree(buf); return; + } debug(3) fprintf(stderr, "cmgr: decoded uname: '%s'\n", user_name); - if ((passwd = strtok(NULL, "|")) == NULL) + if ((passwd = strtok(NULL, "|")) == NULL) { + xfree(buf); return; + } debug(2) fprintf(stderr, "cmgr: decoded passwd: '%s'\n", passwd); /* verify freshness and validity */ - if (atoi(time_str) + passwd_ttl < now) + if (atoi(time_str) + passwd_ttl < now) { + xfree(buf); return; - if (strcasecmp(host_name, req->hostname)) + } + if (strcasecmp(host_name, req->hostname)) { + xfree(buf); return; + } debug(1) fprintf(stderr, "cmgr: verified auth. info.\n"); /* ok, accept */ - xfree(req->user_name); + safe_free(req->user_name); req->user_name = xstrdup(user_name); req->passwd = xstrdup(passwd); xfree(buf);