Package: release.debian.org Severity: normal Tags: stretch User: release.debian....@packages.debian.org Usertags: pu
pound is affected by non-dsa CVE-2016-10711. Attached is the diff, backported from pound 2.8a, same as the diff being used by SUSE. (c.f. https://security-tracker.debian.org/tracker/CVE-2016-10711 ) Thanks!
diff --git a/debian/changelog b/debian/changelog index d5946a9..d59d80c 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,10 @@ +pound (2.7-1.3+deb9u1) stretch; urgency=medium + + * Fix request smuggling via crafted headers, CVE-2016-10711 + (Closes: #888786). + + -- Carsten Leonhardt <l...@debian.org> Sun, 07 Jul 2019 23:44:04 +0200 + pound (2.7-1.3) unstable; urgency=medium * Non-maintainer upload. diff --git a/debian/patches/0003-CVE-2016-1071.patch b/debian/patches/0003-CVE-2016-1071.patch new file mode 100644 index 0000000..09da940 --- /dev/null +++ b/debian/patches/0003-CVE-2016-1071.patch @@ -0,0 +1,210 @@ +Description: Backport fix for CVE-2016-10711 +Author: Robert Segall +Origin: upstream, http://www.apsis.ch/pound/Pound-2.8a.tgz<upstream|backport|vendor|other> +Last-Update: 2019-07-07 +--- a/http.c ++++ b/http.c +@@ -31,7 +31,8 @@ + static char *h500 = "500 Internal Server Error", + *h501 = "501 Not Implemented", + *h503 = "503 Service Unavailable", +- *h414 = "414 Request URI too long"; ++ *h414 = "414 Request URI too long", ++ *h400 = "Bad Request"; + + static char *err_response = "HTTP/1.0 %s\r\nContent-Type: text/html\r\nContent-Length: %d\r\nExpires: now\r\nPragma: no-cache\r\nCache-control: no-cache,no-store\r\n\r\n%s"; + +@@ -83,7 +84,7 @@ + safe_url, safe_url); + snprintf(rep, sizeof(rep), + "HTTP/1.0 %d %s\r\nLocation: %s\r\nContent-Type: text/html\r\nContent-Length: %d\r\n\r\n", +- code, code_msg, safe_url, strlen(cont)); ++ code, code_msg, safe_url, (int)strlen(cont)); + BIO_write(c, rep, strlen(rep)); + BIO_write(c, cont, strlen(cont)); + BIO_flush(c); +@@ -126,11 +127,11 @@ + get_line(BIO *const in, char *const buf, const int bufsize) + { + char tmp; +- int i, n_read; ++ int i, n_read, seen_cr; + + memset(buf, 0, bufsize); +- for(n_read = 0;;) +- switch(BIO_gets(in, buf + n_read, bufsize - n_read - 1)) { ++ for(i = 0, seen_cr = 0; i < bufsize - 1; i++) ++ switch(BIO_read(in, &tmp, 1)) { + case -2: + /* BIO_gets not implemented */ + return -1; +@@ -138,24 +139,49 @@ + case -1: + return 1; + default: +- for(i = n_read; i < bufsize && buf[i]; i++) +- if(buf[i] == '\n' || buf[i] == '\r') { +- buf[i] = '\0'; ++ if(seen_cr) ++ if(tmp != '\n') { ++ /* we have CR not followed by NL */ ++ do { ++ if(BIO_read(in, &tmp, 1) < 0) ++ return 1; ++ } while(tmp != '\n'); ++ return 1; ++ } else { ++ buf[i - 1] = '\0'; + return 0; + } +- if(i < bufsize) { +- n_read = i; ++ ++ if(!iscntrl(tmp) || tmp == '\t') { ++ buf[i] = tmp; ++ continue; ++ } ++ ++ if(tmp == '\r') { ++ seen_cr = 1; + continue; + } +- logmsg(LOG_NOTICE, "(%lx) line too long: %s", pthread_self(), buf); +- /* skip rest of "line" */ +- tmp = '\0'; +- while(tmp != '\n') +- if(BIO_read(in, &tmp, 1) != 1) ++ ++ if(tmp == '\n') { ++ /* line ends in NL only (no CR) */ ++ buf[i] = 0; ++ return 0; ++ } ++ ++ /* all other control characters cause an error */ ++ do { ++ if(BIO_read(in, &tmp, 1) < 0) + return 1; +- break; ++ } while(tmp != '\n'); ++ return 1; + } +- return 0; ++ ++ /* line too long */ ++ do { ++ if(BIO_read(in, &tmp, 1) < 0) ++ return 1; ++ } while(tmp != '\n'); ++ return 1; + } + + /* +@@ -393,22 +419,16 @@ + + /* HTTP/1.1 allows leading CRLF */ + memset(buf, 0, MAXBUF); +- while((res = BIO_gets(in, buf, MAXBUF - 1)) > 0) { +- has_eol = strip_eol(buf); ++ while((res = get_line(in, buf, MAXBUF)) == 0) + if(buf[0]) + break; +- } + +- if(res <= 0) { ++ if(res < 0) { + /* this is expected to occur only on client reads */ + /* logmsg(LOG_NOTICE, "headers: bad starting read"); */ + return NULL; +- } else if(!has_eol) { +- /* check for request length limit */ +- logmsg(LOG_WARNING, "(%lx) e414 headers: request URI too long", pthread_self()); +- err_reply(cl, h414, lstn->err414); +- return NULL; + } ++ + if((headers = (char **)calloc(MAXHEADERS, sizeof(char *))) == NULL) { + logmsg(LOG_WARNING, "(%lx) e500 headers: out of memory", pthread_self()); + err_reply(cl, h500, lstn->err500); +@@ -426,8 +446,10 @@ + for(n = 1; n < MAXHEADERS; n++) { + if(get_line(in, buf, MAXBUF)) { + free_headers(headers); ++ /* this is not necessarily an error, EOF/timeout are possible + logmsg(LOG_WARNING, "(%lx) e500 can't read header", pthread_self()); + err_reply(cl, h500, lstn->err500); ++ */ + return NULL; + } + if(!buf[0]) +@@ -713,23 +735,39 @@ + conn_closed = 1; + break; + case HEADER_TRANSFER_ENCODING: +- if(cont >= L0) +- headers_ok[n] = 0; +- else if(!strcasecmp("chunked", buf)) +- if(chunked) +- headers_ok[n] = 0; +- else +- chunked = 1; ++ if(!strcasecmp("chunked", buf)) ++ chunked = 1; ++ else { ++ addr2str(caddr, MAXBUF - 1, &from_host, 1); ++ logmsg(LOG_NOTICE, "(%lx) e400 multiple Transfer-encoding \"%s\" from %s", pthread_self(), url, caddr); ++ err_reply(cl, h400, "Bad request: multiple Transfer-encoding values"); ++ free_headers(headers); ++ clean_all(); ++ return; ++ } + break; + case HEADER_CONTENT_LENGTH: +- if(chunked || cont >= 0L) +- headers_ok[n] = 0; +- else { +- if((cont = ATOL(buf)) < 0L) +- headers_ok[n] = 0; +- if(is_rpc == 1 && (cont < 0x20000L || cont > 0x80000000L)) +- is_rpc = -1; ++ if(cont != L_1 || strchr(buf, ',')) { ++ addr2str(caddr, MAXBUF - 1, &from_host, 1); ++ logmsg(LOG_NOTICE, "(%lx) e400 multiple Content-length \"%s\" from %s", pthread_self(), url, caddr); ++ err_reply(cl, h400, "Bad request: multiple Content-length values"); ++ free_headers(headers); ++ clean_all(); ++ return; + } ++ for(mh = buf; *mh; mh++) ++ if(!isdigit(*mh)) { ++ addr2str(caddr, MAXBUF - 1, &from_host, 1); ++ logmsg(LOG_NOTICE, "(%lx) e400 Content-length bad value \"%s\" from %s", pthread_self(), url, caddr); ++ err_reply(cl, h400, "Bad request: Content-length bad value"); ++ free_headers(headers); ++ clean_all(); ++ return; ++ } ++ if((cont = ATOL(buf)) < 0L) ++ headers_ok[n] = 0; ++ if(is_rpc == 1 && (cont < 0x20000L || cont > 0x80000000L)) ++ is_rpc = -1; + break; + case HEADER_EXPECT: + /* +@@ -787,6 +825,16 @@ + } + } + ++ /* check for possible request smuggling attempt */ ++ if(chunked != 0 && cont != L_1) { ++ addr2str(caddr, MAXBUF - 1, &from_host, 1); ++ logmsg(LOG_NOTICE, "(%lx) e501 Transfer-encoding and Content-length \"%s\" from %s", pthread_self(), url, caddr); ++ err_reply(cl, h400, "Bad request: Transfer-encoding and Content-length headers present"); ++ free_headers(headers); ++ clean_all(); ++ return; ++ } ++ + /* possibly limited request size */ + if(lstn->max_req > L0 && cont > L0 && cont > lstn->max_req && is_rpc != 1) { + addr2str(caddr, MAXBUF - 1, &from_host, 1); diff --git a/debian/patches/series b/debian/patches/series index 36f32be..d8659e3 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -1,2 +1,3 @@ 0001-Add-MKCALENDAR-to-xHTTP-2-and-above.patch 0002-add-support-openssl1.1-dhparam.patch +0003-CVE-2016-1071.patch