Compare commits
1 commit
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b34510898d |
3 changed files with 243 additions and 1 deletions
137
varnish-6.4.0_fix_VSV00007.patch
Normal file
137
varnish-6.4.0_fix_VSV00007.patch
Normal file
|
|
@ -0,0 +1,137 @@
|
|||
commit 82b0a629f60136e76112c6f2c6372cce77b683be
|
||||
Author: Martin Blix Grydeland <martin@varnish-software.com>
|
||||
Date: Tue Jun 22 11:47:55 2021 +0200
|
||||
|
||||
Take content length into account on H/2 request bodies
|
||||
|
||||
When receiving H/2 data frames, make sure to take the advertised content
|
||||
length into account, and fail appropriately if the combined sum of the
|
||||
data frames does not match the content length.
|
||||
|
||||
diff --git a/bin/varnishd/http2/cache_http2.h b/bin/varnishd/http2/cache_http2.h
|
||||
index 270306d15..c1456a680 100644
|
||||
--- a/bin/varnishd/http2/cache_http2.h
|
||||
+++ b/bin/varnishd/http2/cache_http2.h
|
||||
@@ -134,6 +134,8 @@ struct h2_req {
|
||||
/* Where to wake this stream up */
|
||||
struct worker *wrk;
|
||||
|
||||
+ ssize_t reqbody_bytes;
|
||||
+
|
||||
VTAILQ_ENTRY(h2_req) tx_list;
|
||||
h2_error error;
|
||||
};
|
||||
diff --git a/bin/varnishd/http2/cache_http2_proto.c b/bin/varnishd/http2/cache_http2_proto.c
|
||||
index c079656b1..59dd0336b 100644
|
||||
--- a/bin/varnishd/http2/cache_http2_proto.c
|
||||
+++ b/bin/varnishd/http2/cache_http2_proto.c
|
||||
@@ -554,6 +554,7 @@ h2_end_headers(struct worker *wrk, struct h2_sess *h2,
|
||||
struct req *req, struct h2_req *r2)
|
||||
{
|
||||
h2_error h2e;
|
||||
+ ssize_t cl;
|
||||
|
||||
ASSERT_RXTHR(h2);
|
||||
assert(r2->state == H2_S_OPEN);
|
||||
@@ -574,16 +575,24 @@ h2_end_headers(struct worker *wrk, struct h2_sess *h2,
|
||||
// XXX: Have I mentioned H/2 Is hodge-podge ?
|
||||
http_CollectHdrSep(req->http, H_Cookie, "; "); // rfc7540,l,3114,3120
|
||||
|
||||
+ cl = http_GetContentLength(req->http);
|
||||
+ assert(cl >= -2);
|
||||
+ if (cl == -2) {
|
||||
+ VSLb(h2->vsl, SLT_Debug, "Non-parseable Content-Length");
|
||||
+ return (H2SE_PROTOCOL_ERROR);
|
||||
+ }
|
||||
+
|
||||
if (req->req_body_status == NULL) {
|
||||
- if (!http_GetHdr(req->http, H_Content_Length, NULL))
|
||||
+ if (cl == -1)
|
||||
req->req_body_status = BS_EOF;
|
||||
else
|
||||
req->req_body_status = BS_LENGTH;
|
||||
+ req->htc->content_length = cl;
|
||||
} else {
|
||||
/* A HEADER frame contained END_STREAM */
|
||||
assert (req->req_body_status == BS_NONE);
|
||||
r2->state = H2_S_CLOS_REM;
|
||||
- if (http_GetContentLength(req->http) > 0)
|
||||
+ if (cl > 0)
|
||||
return (H2CE_PROTOCOL_ERROR); //rfc7540,l,1838,1840
|
||||
}
|
||||
|
||||
@@ -737,6 +746,7 @@ h2_rx_data(struct worker *wrk, struct h2_sess *h2, struct h2_req *r2)
|
||||
int w1 = 0, w2 = 0;
|
||||
char buf[4];
|
||||
unsigned wi;
|
||||
+ ssize_t cl;
|
||||
|
||||
CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
|
||||
ASSERT_RXTHR(h2);
|
||||
@@ -755,6 +765,23 @@ h2_rx_data(struct worker *wrk, struct h2_sess *h2, struct h2_req *r2)
|
||||
Lck_Unlock(&h2->sess->mtx);
|
||||
return (h2->error ? h2->error : r2->error);
|
||||
}
|
||||
+
|
||||
+ r2->reqbody_bytes += h2->rxf_len;
|
||||
+ if (h2->rxf_flags & H2FF_DATA_END_STREAM)
|
||||
+ r2->state = H2_S_CLOS_REM;
|
||||
+ cl = r2->req->htc->content_length;
|
||||
+ if (cl >= 0 && (r2->reqbody_bytes > cl ||
|
||||
+ (r2->state >= H2_S_CLOS_REM && r2->reqbody_bytes != cl))) {
|
||||
+ VSLb(h2->vsl, SLT_Debug,
|
||||
+ "H2: stream %u: Received data and Content-Length"
|
||||
+ " mismatch", h2->rxf_stream);
|
||||
+ r2->error = H2SE_PROTOCOL_ERROR; // rfc7540,l,3150,3163
|
||||
+ if (r2->cond)
|
||||
+ AZ(pthread_cond_signal(r2->cond));
|
||||
+ Lck_Unlock(&h2->sess->mtx);
|
||||
+ return (H2SE_PROTOCOL_ERROR);
|
||||
+ }
|
||||
+
|
||||
AZ(h2->mailcall);
|
||||
h2->mailcall = r2;
|
||||
h2->req0->r_window -= h2->rxf_len;
|
||||
@@ -773,6 +800,8 @@ h2_rx_data(struct worker *wrk, struct h2_sess *h2, struct h2_req *r2)
|
||||
r2->r_window += wi;
|
||||
w2 = 1;
|
||||
}
|
||||
+
|
||||
+
|
||||
Lck_Unlock(&h2->sess->mtx);
|
||||
|
||||
if (w1 || w2) {
|
||||
@@ -795,7 +824,7 @@ h2_vfp_body(struct vfp_ctx *vc, struct vfp_entry *vfe, void *ptr, ssize_t *lp)
|
||||
struct h2_req *r2;
|
||||
struct h2_sess *h2;
|
||||
unsigned l;
|
||||
- enum vfp_status retval = VFP_OK;
|
||||
+ enum vfp_status retval;
|
||||
|
||||
CHECK_OBJ_NOTNULL(vc, VFP_CTX_MAGIC);
|
||||
CHECK_OBJ_NOTNULL(vfe, VFP_ENTRY_MAGIC);
|
||||
@@ -808,7 +837,6 @@ h2_vfp_body(struct vfp_ctx *vc, struct vfp_entry *vfe, void *ptr, ssize_t *lp)
|
||||
*lp = 0;
|
||||
|
||||
Lck_Lock(&h2->sess->mtx);
|
||||
- assert (r2->state == H2_S_OPEN);
|
||||
r2->cond = &vc->wrk->cond;
|
||||
while (h2->mailcall != r2 && h2->error == 0 && r2->error == 0)
|
||||
AZ(Lck_CondWait(r2->cond, &h2->sess->mtx, 0));
|
||||
@@ -831,12 +859,10 @@ h2_vfp_body(struct vfp_ctx *vc, struct vfp_entry *vfe, void *ptr, ssize_t *lp)
|
||||
Lck_Unlock(&h2->sess->mtx);
|
||||
return (VFP_OK);
|
||||
}
|
||||
- if (h2->rxf_len == 0) {
|
||||
- if (h2->rxf_flags & H2FF_DATA_END_STREAM) {
|
||||
- retval = VFP_END;
|
||||
- r2->state = H2_S_CLOS_REM;
|
||||
- }
|
||||
- }
|
||||
+ if (h2->rxf_len == 0 && r2->state >= H2_S_CLOS_REM)
|
||||
+ retval = VFP_END;
|
||||
+ else
|
||||
+ retval = VFP_OK;
|
||||
h2->mailcall = NULL;
|
||||
AZ(pthread_cond_signal(h2->cond));
|
||||
}
|
||||
94
varnish-6.4.0_test_for_VSV00007.patch
Normal file
94
varnish-6.4.0_test_for_VSV00007.patch
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
commit 102d0e7a9f5a097535c1afcdfcd0332f66bfb024
|
||||
Author: Martin Blix Grydeland <martin@varnish-software.com>
|
||||
Date: Tue Jun 22 11:47:58 2021 +0200
|
||||
|
||||
VSV00007 Test case for H2 smuggling attack
|
||||
|
||||
diff --git a/bin/varnishtest/tests/f00007.vtc b/bin/varnishtest/tests/f00007.vtc
|
||||
new file mode 100644
|
||||
index 000000000..1cf45aad1
|
||||
--- /dev/null
|
||||
+++ b/bin/varnishtest/tests/f00007.vtc
|
||||
@@ -0,0 +1,82 @@
|
||||
+varnishtest "H/2 content length smuggling attack"
|
||||
+
|
||||
+server s1 {
|
||||
+ rxreqhdrs
|
||||
+ expect_close
|
||||
+} -start
|
||||
+
|
||||
+server s2 {
|
||||
+ rxreqhdrs
|
||||
+ expect_close
|
||||
+} -start
|
||||
+
|
||||
+server s3 {
|
||||
+ rxreq
|
||||
+ expect_close
|
||||
+} -start
|
||||
+
|
||||
+server s4 {
|
||||
+ rxreq
|
||||
+ expect req.body == "A"
|
||||
+ txresp
|
||||
+} -start
|
||||
+
|
||||
+varnish v1 -vcl+backend {
|
||||
+ import vtc;
|
||||
+ sub vcl_backend_fetch {
|
||||
+ if (bereq.url == "/1") {
|
||||
+ set bereq.backend = s1;
|
||||
+ } else if (bereq.url == "/2") {
|
||||
+ set bereq.backend = s2;
|
||||
+ } else if (bereq.url == "/3") {
|
||||
+ set bereq.backend = s3;
|
||||
+ } else {
|
||||
+ set bereq.backend = s4;
|
||||
+ }
|
||||
+ }
|
||||
+} -start
|
||||
+
|
||||
+varnish v1 -cliok "param.set feature +http2"
|
||||
+varnish v1 -cliok "param.set debug +syncvsl"
|
||||
+
|
||||
+client c1 {
|
||||
+ stream 1 {
|
||||
+ txreq -req POST -url /1 -hdr "content-length" "1" -nostrend
|
||||
+ txdata -data "AGET /FAIL HTTP/1.1\r\n\r\n"
|
||||
+ rxrst
|
||||
+ expect rst.err == PROTOCOL_ERROR
|
||||
+ } -run
|
||||
+} -run
|
||||
+
|
||||
+client c2 {
|
||||
+ stream 1 {
|
||||
+ txreq -req POST -url /2 -hdr "content-length" "1" -nostrend
|
||||
+ txdata -data "AGET /FAIL HTTP/1.1\r\n\r\n" -nostrend
|
||||
+ txdata
|
||||
+ rxrst
|
||||
+ expect rst.err == PROTOCOL_ERROR
|
||||
+ } -run
|
||||
+} -run
|
||||
+
|
||||
+client c3 {
|
||||
+ stream 1 {
|
||||
+ txreq -req POST -url /3 -hdr "content-length" "1" -nostrend
|
||||
+ txdata -data "A" -nostrend
|
||||
+ txdata -data "GET /FAIL HTTP/1.1\r\n\r\n"
|
||||
+ rxwinup
|
||||
+ rxrst
|
||||
+ expect rst.err == PROTOCOL_ERROR
|
||||
+ } -run
|
||||
+} -run
|
||||
+
|
||||
+client c4 {
|
||||
+ stream 1 {
|
||||
+ txreq -req POST -url /4 -hdr "content-length" "1" -nostrend
|
||||
+ txdata -data "A" -nostrend
|
||||
+ txdata
|
||||
+ rxwinup
|
||||
+ rxwinup
|
||||
+ rxresp
|
||||
+ expect resp.status == 200
|
||||
+ } -run
|
||||
+} -run
|
||||
13
varnish.spec
13
varnish.spec
|
|
@ -24,7 +24,7 @@
|
|||
Summary: High-performance HTTP accelerator
|
||||
Name: varnish
|
||||
Version: 6.4.0
|
||||
Release: 4%{?dist}
|
||||
Release: 5%{?dist}
|
||||
License: BSD
|
||||
URL: https://www.varnish-cache.org/
|
||||
Source0: http://varnish-cache.org/_downloads/%{name}-%{version}%{?vd_rc}.tgz
|
||||
|
|
@ -65,6 +65,12 @@ Patch16: varnish-6.4.0_el6_fix_warning_from_old_gcc.patch
|
|||
# Patch 018: gcc-10.0.1/s390x compilation fix, upstream commit b0af060
|
||||
#Patch18: varnish-6.3.2_fix_s390x.patch
|
||||
|
||||
# Patch019: fix for CVE-2021-36740, upstream commit 82b0a629
|
||||
Patch19: varnish-6.4.0_fix_VSV00007.patch
|
||||
|
||||
# Patch019: test for CVE-2021-36740, upstream commit 102d0e7a
|
||||
Patch20: varnish-6.4.0_test_for_VSV00007.patch
|
||||
|
||||
%if 0%{?fedora} > 29
|
||||
Provides: varnish%{_isa} = %{version}-%{release}
|
||||
Provides: varnishd(abi)%{_isa} = %{abi}
|
||||
|
|
@ -190,6 +196,8 @@ sed -i '8 i\RPM_BUILD_ROOT=%{buildroot}' find-provides
|
|||
%patch4 -p0
|
||||
%patch16 -p1
|
||||
%endif
|
||||
%patch19 -p1
|
||||
%patch20 -p1
|
||||
|
||||
%build
|
||||
%if 0%{?rhel} == 6
|
||||
|
|
@ -433,6 +441,9 @@ fi
|
|||
|
||||
|
||||
%changelog
|
||||
* Say Jul 17 2021 Ingvar Hagelund <ingvar@redpill-linpro.com> 6.4.0-5
|
||||
- Added patches for CVE-2021-36740 aka VSV00007, bz#1982412
|
||||
|
||||
* Tue Aug 04 2020 Ingvar Hagelund <ingvar@redpill-linpro.com> 6.4.0-4
|
||||
- Added -Wno-error=free-nonheap-object to CFLAGS to build on s390x
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue