Bug#931610: stretch-pu: package pound/2.7-1.3+deb9u1
Package: release.debian.org
Severity: normal
Tags: stretch
User: release.debian.org@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 <leo@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
Reply to: