Control: tags 1023750 + patch
Control: tags 1023750 + pending
Control: tags 1023751 + patch
Control: tags 1023751 + pending

Hi Stig,

I've prepared an NMU for varnish (versioned as 7.1.1-1.1) and
uploaded it to DELAYED/2. Please feel free to tell me if I
should delay it longer.

Regards,
Salvatore
diff -Nru varnish-7.1.1/debian/changelog varnish-7.1.1/debian/changelog
--- varnish-7.1.1/debian/changelog	2022-08-12 11:23:00.000000000 +0200
+++ varnish-7.1.1/debian/changelog	2023-01-09 22:09:31.000000000 +0100
@@ -1,3 +1,12 @@
+varnish (7.1.1-1.1) unstable; urgency=medium
+
+  * Non-maintainer upload.
+  * Add all well-known headers to the perfect hash lookup table
+    (CVE-2022-45059) (Closes: #1023750)
+  * hpack: fix pseudo-headers handling (CVE-2022-45060) (Closes: #1023751)
+
+ -- Salvatore Bonaccorso <car...@debian.org>  Mon, 09 Jan 2023 22:09:31 +0100
+
 varnish (7.1.1-1) unstable; urgency=medium
 
   * New upstream release (CVE-2022-38150, VSV00009)
diff -Nru varnish-7.1.1/debian/patches/Add-all-well-known-headers-to-the-perfect-hash-looku.patch varnish-7.1.1/debian/patches/Add-all-well-known-headers-to-the-perfect-hash-looku.patch
--- varnish-7.1.1/debian/patches/Add-all-well-known-headers-to-the-perfect-hash-looku.patch	1970-01-01 01:00:00.000000000 +0100
+++ varnish-7.1.1/debian/patches/Add-all-well-known-headers-to-the-perfect-hash-looku.patch	2023-01-09 21:57:49.000000000 +0100
@@ -0,0 +1,244 @@
+From: Martin Blix Grydeland <mar...@varnish-software.com>
+Date: Thu, 29 Sep 2022 14:38:05 +0200
+Subject: Add all well-known headers to the perfect hash lookup table
+Origin: https://github.com/varnishcache/varnish-cache/commit/fcf5722af75fdbf58dd425dd68d0beaa49bab4f4
+Bug-Debian: https://bugs.debian.org/1023750
+Bug-Debian-Security: https://security-tracker.debian.org/tracker/CVE-2022-45059
+
+This expands the perfect hash lookup table to be able to match any entry
+in the list of well-known headers from tbl/http_headers.h.
+
+Previously only the headers that had a non-zero filter flag section was
+kept in the fast match table.
+
+Fixes: VSV00010
+---
+ bin/varnishd/cache/cache_http.c  | 148 +++++++++++++++++++------------
+ bin/varnishtest/tests/f00010.vtc |  19 ++++
+ 2 files changed, 112 insertions(+), 55 deletions(-)
+ create mode 100644 bin/varnishtest/tests/f00010.vtc
+
+diff --git a/bin/varnishd/cache/cache_http.c b/bin/varnishd/cache/cache_http.c
+index 194055c3cae3..827197dedfa2 100644
+--- a/bin/varnishd/cache/cache_http.c
++++ b/bin/varnishd/cache/cache_http.c
+@@ -65,73 +65,113 @@ const char H__Reason[]	= "\010:reason:";
+  * A suitable algorithm can be found with `gperf`:
+  *
+  *	tr '" ,' '   ' < include/tbl/http_headers.h |
+- *		awk '$1 == "H(" && $4 != "0" {print$2}' |
++ *		awk '$1 == "H(" {print $2}' |
+  *		gperf --ignore-case
+  *
+  */
+ 
++#define GPERF_MIN_WORD_LENGTH 2
++#define GPERF_MAX_WORD_LENGTH 19
++#define GPERF_MAX_HASH_VALUE 79
++
+ static const unsigned char http_asso_values[256] = {
+-	39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
+-	39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
+-	39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
+-	39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
+-	39, 39, 39, 39, 39, 25, 39,  0, 20,  5, 39, 39, 39, 15,  0, 39,
+-	10, 39,  0, 39, 15, 10, 39, 39,  0, 39, 39, 39, 39, 39, 39, 39,
+-	39, 39, 39, 39, 39, 25, 39,  0, 20,  5, 39, 39, 39, 15,  0, 39,
+-	10, 39,  0, 39, 15, 10, 39, 39,  0, 39, 39, 39, 39, 39, 39, 39,
+-	39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
+-	39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
+-	39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
+-	39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
+-	39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
+-	39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
+-	39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
+-	39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39
++	80, 80, 80, 80, 80, 80, 80, 80, 80, 80,
++	80, 80, 80, 80, 80, 80, 80, 80, 80, 80,
++	80, 80, 80, 80, 80, 80, 80, 80, 80, 80,
++	80, 80, 80, 80, 80, 80, 80, 80, 80, 80,
++	80, 80, 80, 80, 80, 80, 80, 80, 80, 80,
++	80, 80, 80,  0, 80, 80, 80, 80, 80, 80,
++	80, 80, 80, 80, 80,  5, 80, 20,  0,  0,
++	5, 10,  5,  5, 80,  0, 15,  0, 20, 80,
++	40, 80,  0, 35, 10, 20, 55, 45,  0,  0,
++	80, 80, 80, 80, 80, 80, 80,  5, 80, 20,
++	0,  0,  5, 10,  5,  5, 80,  0, 15,  0,
++	20, 80, 40, 80,  0, 35, 10, 20, 55, 45,
++	0,  0, 80, 80, 80, 80, 80, 80, 80, 80,
++	80, 80, 80, 80, 80, 80, 80, 80, 80, 80,
++	80, 80, 80, 80, 80, 80, 80, 80, 80, 80,
++	80, 80, 80, 80, 80, 80, 80, 80, 80, 80,
++	80, 80, 80, 80, 80, 80, 80, 80, 80, 80,
++	80, 80, 80, 80, 80, 80, 80, 80, 80, 80,
++	80, 80, 80, 80, 80, 80, 80, 80, 80, 80,
++	80, 80, 80, 80, 80, 80, 80, 80, 80, 80,
++	80, 80, 80, 80, 80, 80, 80, 80, 80, 80,
++	80, 80, 80, 80, 80, 80, 80, 80, 80, 80,
++	80, 80, 80, 80, 80, 80, 80, 80, 80, 80,
++	80, 80, 80, 80, 80, 80, 80, 80, 80, 80,
++	80, 80, 80, 80, 80, 80, 80, 80, 80, 80,
++	80, 80, 80, 80, 80, 80
+ };
+ 
+ static struct http_hdrflg {
+ 	char		*hdr;
+ 	unsigned	flag;
+-} http_hdrflg[38 + 1] = {			// MAX_HASH_VALUE
+-	{ NULL },
+-	{ NULL },
+-	{ H_TE },
+-	{ H_Age },
+-	{ NULL },
++} http_hdrflg[GPERF_MAX_HASH_VALUE + 1] = {
++	{ NULL }, { NULL }, { NULL }, { NULL },
++	{ H_Date },
+ 	{ H_Range },
+ 	{ NULL },
+-	{ H_Upgrade },
++	{ H_Referer },
++	{ H_Age },
++	{ H_From },
++	{ H_Keep_Alive },
++	{ H_Retry_After },
++	{ H_TE },
+ 	{ H_If_Range },
+-	{ NULL },
+-	{ H_Connection },
+-	{ NULL },
++	{ H_ETag },
++	{ H_X_Forwarded_For },
++	{ H_Expect },
+ 	{ H_Trailer },
+-	{ H_If_None_Match },
+-	{ NULL },
+-	{ NULL },
+-	{ NULL },
+-	{ H_Transfer_Encoding },
+-	{ H_Proxy_Authenticate },
+-	{ H_Proxy_Authorization },
+-	{ H_Keep_Alive },
+-	{ NULL },
+-	{ NULL },
+ 	{ H_If_Match },
+-	{ H_HTTP2_Settings },
+-	{ NULL },
+-	{ NULL },
+-	{ NULL },
+-	{ H_Content_Range },
++	{ H_Host },
++	{ H_Accept_Language },
++	{ H_Accept },
++	{ H_If_Modified_Since },
++	{ H_If_None_Match },
+ 	{ H_If_Unmodified_Since },
+ 	{ NULL },
++	{ H_Cookie },
++	{ H_Upgrade },
++	{ H_Last_Modified },
++	{ H_Accept_Charset },
++	{ H_Accept_Encoding },
++	{ H_Content_MD5 },
++	{ H_Content_Type },
++	{ H_Content_Range },
++	{ NULL }, { NULL },
++	{ H_Content_Language },
++	{ H_Transfer_Encoding },
++	{ H_Authorization },
++	{ H_Content_Length },
++	{ H_User_Agent },
++	{ H_Server },
++	{ H_Expires },
++	{ H_Location },
+ 	{ NULL },
+-	{ H_If_Modified_Since },
++	{ H_Set_Cookie },
++	{ H_Content_Encoding },
++	{ H_Max_Forwards },
+ 	{ H_Cache_Control },
+ 	{ NULL },
++	{ H_Connection },
++	{ H_Pragma },
+ 	{ NULL },
++	{ H_Accept_Ranges },
++	{ H_HTTP2_Settings },
++	{ H_Allow },
++	{ H_Content_Location },
+ 	{ NULL },
++	{ H_Proxy_Authenticate },
++	{ H_Vary },
+ 	{ NULL },
+-	{ H_Accept_Ranges }
++	{ H_WWW_Authenticate },
++	{ H_Warning },
++	{ H_Via },
++	{ NULL }, { NULL }, { NULL }, { NULL },
++	{ NULL }, { NULL }, { NULL }, { NULL },
++	{ NULL }, { NULL }, { NULL }, { NULL },
++	{ NULL }, { NULL }, { NULL },
++	{ H_Proxy_Authorization }
+ };
+ 
+ static struct http_hdrflg *
+@@ -145,12 +185,12 @@ http_hdr_flags(const char *b, const char *e)
+ 	assert(b <= e);
+ 	u = (unsigned)(e - b);
+ 	assert(b + u == e);
+-	if (u < 2 || u > 19)		// MIN_WORD_LENGTH & MAX_WORD_LENGTH
+-		return(NULL);
+-	if (u > 3)
+-		u += http_asso_values[((const uint8_t*)b)[3]];
+-	if (u > 38)			// MAX_HASH_VALUE
+-		return(NULL);
++	if (u < GPERF_MIN_WORD_LENGTH || u > GPERF_MAX_WORD_LENGTH)
++		return (NULL);
++	u += http_asso_values[((const uint8_t *)b)[u - 1]] +
++	    http_asso_values[((const uint8_t *)b)[0]];
++	if (u > GPERF_MAX_HASH_VALUE)
++		return (NULL);
+ 	retval = &http_hdrflg[u];
+ 	if (retval->hdr == NULL)
+ 		return(NULL);
+@@ -168,11 +208,9 @@ http_init_hdr(char *hdr, int flg)
+ 
+ 	hdr[0] = strlen(hdr + 1);
+ 	f = http_hdr_flags(hdr + 1, hdr + hdr[0]);
+-	if (flg) {
+-		AN(f);
+-		assert(f->hdr == hdr);
+-		f->flag = flg;
+-	}
++	AN(f);
++	assert(f->hdr == hdr);
++	f->flag = flg;
+ }
+ 
+ void
+diff --git a/bin/varnishtest/tests/f00010.vtc b/bin/varnishtest/tests/f00010.vtc
+new file mode 100644
+index 000000000000..b381b5cf37a6
+--- /dev/null
++++ b/bin/varnishtest/tests/f00010.vtc
+@@ -0,0 +1,19 @@
++varnishtest "Do not allow critical headers to be marked hop-by-hop"
++
++varnish v1 -vcl {
++	backend default none;
++} -start
++
++client c1 {
++	txreq -hdr "Connection: Content-Length" -body "asdf"
++	rxresp
++	expect resp.status == 400
++	expect_close
++} -run
++
++client c2 {
++	txreq -hdr "Connection: Host"
++	rxresp
++	expect resp.status == 400
++	expect_close
++} -run
+-- 
+2.39.0
+
diff -Nru varnish-7.1.1/debian/patches/hpack-fix-pseudo-headers-handling.patch varnish-7.1.1/debian/patches/hpack-fix-pseudo-headers-handling.patch
--- varnish-7.1.1/debian/patches/hpack-fix-pseudo-headers-handling.patch	1970-01-01 01:00:00.000000000 +0100
+++ varnish-7.1.1/debian/patches/hpack-fix-pseudo-headers-handling.patch	2023-01-09 22:08:14.000000000 +0100
@@ -0,0 +1,212 @@
+From: Asad Sajjad Ahmed <asa...@varnish-software.com>
+Date: Fri, 30 Sep 2022 14:42:53 +0200
+Subject: hpack: fix pseudo-headers handling
+Origin: https://github.com/varnishcache/varnish-cache/commit/515a93df894430767073ccd8265497b6b25b54b5
+Bug-Debian: https://bugs.debian.org/1023751
+Bug-Debian-Security: https://security-tracker.debian.org/tracker/CVE-2022-45060
+
+We should apply the same restrictions on the list of allowed characters inside
+H/2 pseudo-headers as we do for H/1. This error is translated into the
+headers we send to a backend over H/1.
+
+Failure to do so could permit various exploits against a backend not handling
+malformed H/1 requests.
+
+Signed-off-by: Asad Sajjad Ahmed <asa...@varnish-software.com>
+---
+ bin/varnishd/http2/cache_http2_hpack.c | 35 +++++++++++++++++++
+ bin/varnishtest/tests/t02023.vtc       | 48 ++++++++++++++++++++++++++
+ bin/varnishtest/tests/t02024.vtc       | 48 ++++++++++++++++++++++++++
+ 3 files changed, 131 insertions(+)
+ create mode 100644 bin/varnishtest/tests/t02023.vtc
+ create mode 100644 bin/varnishtest/tests/t02024.vtc
+
+diff --git a/bin/varnishd/http2/cache_http2_hpack.c b/bin/varnishd/http2/cache_http2_hpack.c
+index 6e67b55c505b..f58788b1266a 100644
+--- a/bin/varnishd/http2/cache_http2_hpack.c
++++ b/bin/varnishd/http2/cache_http2_hpack.c
+@@ -96,13 +96,18 @@ h2h_addhdr(struct http *hp, char *b, size_t namelen, size_t len)
+ {
+ 	/* XXX: This might belong in cache/cache_http.c */
+ 	const char *b0;
++	int disallow_empty;
+ 	unsigned n;
++	char *p;
++	int i;
+ 
+ 	CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
+ 	AN(b);
+ 	assert(namelen >= 2);	/* 2 chars from the ': ' that we added */
+ 	assert(namelen <= len);
+ 
++	disallow_empty = 0;
++
+ 	if (len > UINT_MAX) {	/* XXX: cache_param max header size */
+ 		VSLb(hp->vsl, SLT_BogoHeader, "Header too large: %.20s", b);
+ 		return (H2SE_ENHANCE_YOUR_CALM);
+@@ -117,10 +122,24 @@ h2h_addhdr(struct http *hp, char *b, size_t namelen, size_t len)
+ 			b += namelen;
+ 			len -= namelen;
+ 			n = HTTP_HDR_METHOD;
++			disallow_empty = 1;
++
++			/* First field cannot contain SP or CTL */
++			for (p = b, i = 0; i < len; p++, i++) {
++				if (vct_issp(*p) || vct_isctl(*p))
++					return (H2SE_PROTOCOL_ERROR);
++			}
+ 		} else if (!strncmp(b, ":path: ", namelen)) {
+ 			b += namelen;
+ 			len -= namelen;
+ 			n = HTTP_HDR_URL;
++			disallow_empty = 1;
++
++			/* Second field cannot contain LWS or CTL */
++			for (p = b, i = 0; i < len; p++, i++) {
++				if (vct_islws(*p) || vct_isctl(*p))
++					return (H2SE_PROTOCOL_ERROR);
++			}
+ 		} else if (!strncmp(b, ":scheme: ", namelen)) {
+ 			/* XXX: What to do about this one? (typically
+ 			   "http" or "https"). For now set it as a normal
+@@ -128,6 +147,15 @@ h2h_addhdr(struct http *hp, char *b, size_t namelen, size_t len)
+ 			b++;
+ 			len-=1;
+ 			n = hp->nhd;
++
++			for (p = b + namelen, i = 0; i < len-namelen;
++			    p++, i++) {
++				if (vct_issp(*p) || vct_isctl(*p))
++					return (H2SE_PROTOCOL_ERROR);
++			}
++
++			if (!i)
++				return (H2SE_PROTOCOL_ERROR);
+ 		} else if (!strncmp(b, ":authority: ", namelen)) {
+ 			b+=6;
+ 			len-=6;
+@@ -164,6 +192,13 @@ h2h_addhdr(struct http *hp, char *b, size_t namelen, size_t len)
+ 	hp->hd[n].b = b;
+ 	hp->hd[n].e = b + len;
+ 
++	if (disallow_empty && !Tlen(hp->hd[n])) {
++		VSLb(hp->vsl, SLT_BogoHeader,
++		    "Empty pseudo-header %.*s",
++		    (int)namelen, b0);
++		return (H2SE_PROTOCOL_ERROR);
++	}
++
+ 	return (0);
+ }
+ 
+diff --git a/bin/varnishtest/tests/t02023.vtc b/bin/varnishtest/tests/t02023.vtc
+new file mode 100644
+index 000000000000..cfd843da3ecb
+--- /dev/null
++++ b/bin/varnishtest/tests/t02023.vtc
+@@ -0,0 +1,48 @@
++varnishtest "Empty pseudo-headers"
++
++server s1 {
++	rxreq
++	txresp
++} -start
++
++varnish v1 -arg "-p feature=+http2" -vcl+backend {
++} -start
++
++client c1 {
++	txreq -url ""
++	rxresp
++	expect resp.status == 400
++} -run
++
++client c1 {
++	txreq -req ""
++	rxresp
++	expect resp.status == 400
++} -run
++
++client c1 {
++	txreq -proto ""
++	rxresp
++	expect resp.status == 400
++} -run
++
++client c1 {
++	stream 1 {
++		txreq -url ""
++		rxrst
++	} -run
++} -run
++
++client c1 {
++	stream 1 {
++		txreq -scheme ""
++		rxrst
++	} -run
++} -run
++
++client c1 {
++	stream 1 {
++		txreq -req ""
++		rxrst
++	} -run
++} -run
+diff --git a/bin/varnishtest/tests/t02024.vtc b/bin/varnishtest/tests/t02024.vtc
+new file mode 100644
+index 000000000000..0d0a1abc5d09
+--- /dev/null
++++ b/bin/varnishtest/tests/t02024.vtc
+@@ -0,0 +1,48 @@
++varnishtest "Garbage pseudo-headers"
++
++server s1 {
++	rxreq
++	txresp
++} -start
++
++varnish v1 -arg "-p feature=+http2" -vcl+backend {
++} -start
++
++client c1 {
++	txreq -url " "
++	rxresp
++	expect resp.status == 400
++} -run
++
++client c1 {
++	txreq -req " "
++	rxresp
++	expect resp.status == 400
++} -run
++
++client c1 {
++	txreq -proto " "
++	rxresp
++	expect resp.status == 400
++} -run
++
++client c1 {
++	stream 1 {
++		txreq -url " "
++		rxrst
++	} -run
++} -run
++
++client c1 {
++	stream 1 {
++		txreq -scheme " "
++		rxrst
++	} -run
++} -run
++
++client c1 {
++	stream 1 {
++		txreq -req " "
++		rxrst
++	} -run
++} -run
+-- 
+2.39.0
+
diff -Nru varnish-7.1.1/debian/patches/series varnish-7.1.1/debian/patches/series
--- varnish-7.1.1/debian/patches/series	1970-01-01 01:00:00.000000000 +0100
+++ varnish-7.1.1/debian/patches/series	2023-01-09 22:06:58.000000000 +0100
@@ -0,0 +1,2 @@
+Add-all-well-known-headers-to-the-perfect-hash-looku.patch
+hpack-fix-pseudo-headers-handling.patch

Reply via email to