diff -Nru varnish-6.2.1/debian/changelog varnish-6.2.1/debian/changelog --- varnish-6.2.1/debian/changelog 2022-05-04 21:16:37.000000000 +0100 +++ varnish-6.2.1/debian/changelog 2022-08-16 17:57:53.000000000 +0100 @@ -1,3 +1,36 @@ +varnish (6.2.1-2ubuntu0.2) focal-security; urgency=medium + + * SECURITY REGRESSION: Incomplete fix for CVE-2020-11653 (LP: #1986627) + - debian/patches/WS_ReserveAll.patch: Rename to CVE-2020-11653-01.patch. + - debian/patches/WS_ReserveSize.patch: Rename to CVE-2020-11653-02.patch. + - debian/patches/CVE-2020-11653-03.patch: Add a facility to test + WS_ReserveSize(). + - debian/patches/CVE-2020-11653-04.patch: Correct the overflow condition in + WS_ReserveSize(). + - debian/patches/CVE-2020-11653-05.patch: Fix copy-pasted test description. + - debian/patches/CVE-2020-11653-06.patch: Add Session Attribute workspace + overflow handling. + - debian/patches/CVE-2020-11653-07.patch: Simplify WS allocation in + tlv_string. + - debian/patches/CVE-2020-11653-08.patch: Try to make the proxy code session + workspace overflow test on 32-bit platforms. + - debian/patches/CVE-2020-11653-09.patch: Adjust the workspace session size + for 32-bit vtest machines. + - debian/patches/CVE-2020-11653-10.patch: Handle out of session workspace in + http1_new_session(). + - debian/patches/CVE-2020-11653-11.patch: Remove extra call to + SES_Reserve_proto_priv(). + - debian/patches/CVE-2020-11653-12.patch: Remove call to + SES_Reserve_proto_priv() in h2_init_sess(). + - debian/patches/CVE-2020-11653-13.patch: Handle badly formatted proxy TLVs. + - debian/patches/CVE-2020-11653-14.patch: Add a missing assertion to + WS_ReserveAll(). + - debian/patches/CVE-2020-11653-15.patch: Fix WS_ReserveSize calls when + bytes is equal to free workspace. + - debian/patches/CVE-2020-11653.patch: Rename to CVE-2020-11653-16.patch. + + -- Luís Infante da Câmara Tue, 16 Aug 2022 17:57:53 +0100 + varnish (6.2.1-2ubuntu0.1) focal-security; urgency=medium * SECURITY UPDATE: Sensitive Information Disclosure diff -Nru varnish-6.2.1/debian/patches/CVE-2020-11653-01.patch varnish-6.2.1/debian/patches/CVE-2020-11653-01.patch --- varnish-6.2.1/debian/patches/CVE-2020-11653-01.patch 1970-01-01 01:00:00.000000000 +0100 +++ varnish-6.2.1/debian/patches/CVE-2020-11653-01.patch 2022-05-04 21:16:37.000000000 +0100 @@ -0,0 +1,282 @@ +From c6df6a5fa9e5575b079d602895eb429db417c5cd Mon Sep 17 00:00:00 2001 +From: Nils Goroll +Date: Mon, 8 Apr 2019 15:19:30 +0200 +Subject: [PATCH] Add WS_ReserveAll() to replace WS_Reserve(ws, 0) + +... to un-confuse the interface + +Notes on changes from WS_Reserve(): + +* Removed the first WS_Assert because all we change is ws->r and we got + a specific assert on it. + +* it follows from PAOK(ws->e) && PAOK(ws->f) in WS_Assert() that + PAOK(ws->r) && PAOK(b), so we remove the PRNDDN() + +Ref: varnishcache/varnish-cache#2967 + +(cherry picked from commit d001cdd2045aa484a968d09859cddf59dee372cb) +--- + bin/varnishd/cache/cache.h | 1 + + bin/varnishd/cache/cache_hash.c | 2 +- + bin/varnishd/cache/cache_http.c | 4 +-- + bin/varnishd/cache/cache_session.c | 2 +- + bin/varnishd/cache/cache_vary.c | 2 +- + bin/varnishd/cache/cache_vrt.c | 6 ++--- + bin/varnishd/cache/cache_vrt_filter.c | 2 +- + bin/varnishd/cache/cache_vrt_re.c | 2 +- + bin/varnishd/cache/cache_ws.c | 32 +++++++++++++++++++----- + bin/varnishd/http2/cache_http2_deliver.c | 6 +++-- + bin/varnishd/http2/cache_http2_hpack.c | 2 +- + lib/libvmod_blob/vmod_blob.c | 4 +-- + lib/libvmod_std/vmod_std.c | 2 +- + lib/libvmod_vtc/vmod_vtc.c | 4 +-- + 14 files changed, 47 insertions(+), 24 deletions(-) + +--- varnish-6.2.1.orig/bin/varnishd/cache/cache.h ++++ varnish-6.2.1/bin/varnishd/cache/cache.h +@@ -765,6 +765,7 @@ void WRK_BgThread(pthread_t *thr, const + + void WS_Init(struct ws *ws, const char *id, void *space, unsigned len); + unsigned WS_Reserve(struct ws *ws, unsigned bytes); ++unsigned WS_ReserveAll(struct ws *); + unsigned WS_ReserveLumps(struct ws *ws, size_t sz); + void WS_MarkOverflow(struct ws *ws); + void WS_Release(struct ws *ws, unsigned bytes); +--- varnish-6.2.1.orig/bin/varnishd/cache/cache_hash.c ++++ varnish-6.2.1/bin/varnishd/cache/cache_hash.c +@@ -650,7 +650,7 @@ HSH_Purge(struct worker *wrk, struct obj + + CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC); + CHECK_OBJ_NOTNULL(oh, OBJHEAD_MAGIC); +- ospc = WS_Reserve(wrk->aws, 0); ++ ospc = WS_ReserveAll(wrk->aws); + assert(ospc >= sizeof *ocp); + /* + * Because of "soft" purges, there might be oc's in the list that has +--- varnish-6.2.1.orig/bin/varnishd/cache/cache_http.c ++++ varnish-6.2.1/bin/varnishd/cache/cache_http.c +@@ -394,7 +394,7 @@ http_CollectHdrSep(struct http *hp, cons + } + if (b == NULL) { + /* Found second header, start our collection */ +- ml = WS_Reserve(hp->ws, 0); ++ ml = WS_ReserveAll(hp->ws); + b = hp->ws->f; + e = b + ml; + x = Tlen(hp->hd[f]); +@@ -1228,7 +1228,7 @@ http_PrintfHeader(struct http *to, const + unsigned l, n; + + CHECK_OBJ_NOTNULL(to, HTTP_MAGIC); +- l = WS_Reserve(to->ws, 0); ++ l = WS_ReserveAll(to->ws); + va_start(ap, fmt); + n = vsnprintf(to->ws->f, l, fmt, ap); + va_end(ap); +--- varnish-6.2.1.orig/bin/varnishd/cache/cache_session.c ++++ varnish-6.2.1/bin/varnishd/cache/cache_session.c +@@ -203,7 +203,7 @@ HTC_RxInit(struct http_conn *htc, struct + + CHECK_OBJ_NOTNULL(htc, HTTP_CONN_MAGIC); + htc->ws = ws; +- (void)WS_Reserve(htc->ws, 0); ++ (void)WS_ReserveAll(htc->ws); + htc->rxbuf_b = ws->f; + htc->rxbuf_e = ws->f; + if (htc->pipeline_b != NULL) { +--- varnish-6.2.1.orig/bin/varnishd/cache/cache_vary.c ++++ varnish-6.2.1/bin/varnishd/cache/cache_vary.c +@@ -230,7 +230,7 @@ VRY_Prep(struct req *req) + AZ(req->vary_b); + AZ(req->vary_l); + AZ(req->vary_e); +- (void)WS_Reserve(req->ws, 0); ++ (void)WS_ReserveAll(req->ws); + } else { + AN(req->ws->r); + } +--- varnish-6.2.1.orig/bin/varnishd/cache/cache_vrt.c ++++ varnish-6.2.1/bin/varnishd/cache/cache_vrt.c +@@ -261,7 +261,7 @@ VRT_String(struct ws *ws, const char *h, + unsigned u, x; + va_list aq; + +- u = WS_Reserve(ws, 0); ++ u = WS_ReserveAll(ws); + e = b = ws->f; + e += u; + +@@ -385,7 +385,7 @@ VRT_StrandsWS(struct ws *ws, const char + int i; + + AN(s); +- u = WS_Reserve(ws, 0); ++ u = WS_ReserveAll(ws); + + for (i = 0; i < s->n; i++) + if (s->p[i] != NULL && *s->p[i] != '\0') { +@@ -573,7 +573,7 @@ VRT_IP_string(VRT_CTX, VCL_IP ip) + CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); + if (ip == NULL) + return (NULL); +- len = WS_Reserve(ctx->ws, 0); ++ len = WS_ReserveAll(ctx->ws); + if (len == 0) { + WS_Release(ctx->ws, 0); + return (NULL); +--- varnish-6.2.1.orig/bin/varnishd/cache/cache_vrt_filter.c ++++ varnish-6.2.1/bin/varnishd/cache/cache_vrt_filter.c +@@ -251,7 +251,7 @@ filter_on_ws(struct ws *ws, filter_list_ + + AN(func); + AN(arg); +- u = WS_Reserve(ws, 0); ++ u = WS_ReserveAll(ws); + if (u == 0) { + WS_Release(ws, 0); + WS_MarkOverflow(ws); +--- varnish-6.2.1.orig/bin/varnishd/cache/cache_vrt_re.c ++++ varnish-6.2.1/bin/varnishd/cache/cache_vrt_re.c +@@ -127,7 +127,7 @@ VRT_regsub(VRT_CTX, int all, const char + return (str); + } + +- u = WS_Reserve(ctx->ws, 0); ++ u = WS_ReserveAll(ctx->ws); + res_e = res_b = b0 = ctx->ws->f; + res_e += u; + +--- varnish-6.2.1.orig/bin/varnishd/cache/cache_ws.c ++++ varnish-6.2.1/bin/varnishd/cache/cache_ws.c +@@ -202,7 +202,7 @@ WS_Printf(struct ws *ws, const char *fmt + va_list ap; + char *p; + +- u = WS_Reserve(ws, 0); ++ u = WS_ReserveAll(ws); + p = ws->f; + va_start(ap, fmt); + v = vsnprintf(p, u, fmt, ap); +@@ -227,6 +227,30 @@ WS_Snapshot(struct ws *ws) + return (ws->f == ws->s ? 0 : (uintptr_t)ws->f); + } + ++/* ++ * WS_Release() must be called in all cases ++ */ ++unsigned ++WS_ReserveAll(struct ws *ws) ++{ ++ unsigned b; ++ ++ assert(ws->r == NULL); ++ ++ ws->r = ws->e; ++ b = pdiff(ws->f, ws->r); ++ ++ WS_Assert(ws); ++ DSL(DBG_WORKSPACE, 0, "WS_ReserveAll(%p) = %u", ws, b); ++ ++ return (b); ++} ++ ++/* ++ * bytes == 0 argument is deprecated - use WS_ReserveAll ++ * ++ * XXX rename to WS_ReserveSize and macro-wrap WS_Reserve to emit #warn ? ++ */ + unsigned + WS_Reserve(struct ws *ws, unsigned bytes) + { +@@ -253,11 +277,7 @@ WS_Reserve(struct ws *ws, unsigned bytes + unsigned + WS_ReserveLumps(struct ws *ws, size_t sz) + { +- unsigned u; +- +- u = WS_Reserve(ws, 0); +- u /= sz; +- return (u); ++ return (WS_ReserveAll(ws) / sz); + } + + void +--- varnish-6.2.1.orig/bin/varnishd/http2/cache_http2_deliver.c ++++ varnish-6.2.1/bin/varnishd/http2/cache_http2_deliver.c +@@ -225,9 +225,11 @@ h2_build_headers(struct vsb *resp, struc + uint8_t buf[6]; + ssize_t sz, sz1; + +- l = WS_Reserve(req->ws, 0); +- if (l < 10) ++ l = WS_ReserveAll(req->ws); ++ if (l < 10) { ++ WS_Release(req->ws, 0); + return (-1); ++ } + + AN(VSB_new(resp, req->ws->f, l, VSB_FIXEDLEN)); + +--- varnish-6.2.1.orig/bin/varnishd/http2/cache_http2_hpack.c ++++ varnish-6.2.1/bin/varnishd/http2/cache_http2_hpack.c +@@ -175,7 +175,7 @@ h2h_decode_init(const struct h2_sess *h2 + d = h2->decode; + INIT_OBJ(d, H2H_DECODE_MAGIC); + VHD_Init(d->vhd); +- d->out_l = WS_Reserve(h2->new_req->http->ws, 0); ++ d->out_l = WS_ReserveAll(h2->new_req->http->ws); + assert(d->out_l > 0); /* Can't do any work without any buffer + space. Require non-zero size. */ + d->out = h2->new_req->http->ws->f; +--- varnish-6.2.1.orig/lib/libvmod_blob/vmod_blob.c ++++ varnish-6.2.1/lib/libvmod_blob/vmod_blob.c +@@ -339,7 +339,7 @@ vmod_decode(VRT_CTX, VCL_ENUM decs, VCL_ + CHECK_OBJ_NOTNULL(ctx->ws, WS_MAGIC); + + buf = WS_Front(ctx->ws); +- space = WS_Reserve(ctx->ws, 0); ++ space = WS_ReserveAll(ctx->ws); + + if (length <= 0) + length = -1; +@@ -378,7 +378,7 @@ encode(VRT_CTX, enum encoding enc, enum + CHECK_OBJ_NOTNULL(ctx->ws, WS_MAGIC); + snap = WS_Snapshot(ctx->ws); + buf = WS_Front(ctx->ws); +- space = WS_Reserve(ctx->ws, 0); ++ space = WS_ReserveAll(ctx->ws); + + len = func[enc].encode(enc, kase, buf, space, b->blob, b->len); + +--- varnish-6.2.1.orig/lib/libvmod_std/vmod_std.c ++++ varnish-6.2.1/lib/libvmod_std/vmod_std.c +@@ -72,7 +72,7 @@ vmod_updown(VRT_CTX, int up, const char + const char *p; + + CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); +- u = WS_Reserve(ctx->ws, 0); ++ u = WS_ReserveAll(ctx->ws); + e = b = ctx->ws->f; + e += u; + p = s; +--- varnish-6.2.1.orig/lib/libvmod_vtc/vmod_vtc.c ++++ varnish-6.2.1/lib/libvmod_vtc/vmod_vtc.c +@@ -155,7 +155,7 @@ vmod_workspace_alloc(VRT_CTX, VCL_ENUM w + WS_Assert(ws); + + if (size < 0) { +- size += WS_Reserve(ws, 0); ++ size += WS_ReserveAll(ws); + WS_Release(ws, 0); + } + if (size <= 0) { +@@ -182,7 +182,7 @@ vmod_workspace_free(VRT_CTX, VCL_ENUM wh + return(-1); + WS_Assert(ws); + +- u = WS_Reserve(ws, 0); ++ u = WS_ReserveAll(ws); + WS_Release(ws, 0); + return (u); + } diff -Nru varnish-6.2.1/debian/patches/CVE-2020-11653-02.patch varnish-6.2.1/debian/patches/CVE-2020-11653-02.patch --- varnish-6.2.1/debian/patches/CVE-2020-11653-02.patch 1970-01-01 01:00:00.000000000 +0100 +++ varnish-6.2.1/debian/patches/CVE-2020-11653-02.patch 2022-05-04 21:16:37.000000000 +0100 @@ -0,0 +1,130 @@ +From 534e045e040fc213f72aa38a85806f152e3ef5e0 Mon Sep 17 00:00:00 2001 +From: Nils Goroll +Date: Mon, 8 Apr 2019 16:26:07 +0200 +Subject: [PATCH] Deprecate WS_Reserve() and replace it with WS_ReserveSize() + +WS_ReserveSize() does not leave the workspace reserved when the +reservation fails, so WS_Release() must be called for retval > 0 only. + +Besides the debug string, it is identical to WS_Reserve() except for + + assert(bytes > 0); + +Follow-up varnishcache/varnish-cache#2967 + +Note: The WS_Reserve() function has not been deprecated as that can +potentially create problems for the build process of VMODs. + +(cherry picked from commit 4e33359772a3d751b2ef4b5c4b40259f1bcd6903) +--- + bin/varnishd/cache/cache.h | 3 +++ + bin/varnishd/cache/cache_session.c | 6 +++--- + bin/varnishd/cache/cache_wrk.c | 2 +- + bin/varnishd/cache/cache_ws.c | 31 +++++++++++++++++++++++++++--- + lib/libvmod_proxy/vmod_proxy.c | 2 +- + 5 files changed, 36 insertions(+), 8 deletions(-) + +--- varnish-6.2.1.orig/bin/varnishd/cache/cache.h ++++ varnish-6.2.1/bin/varnishd/cache/cache.h +@@ -764,7 +764,10 @@ void WRK_BgThread(pthread_t *thr, const + /* cache_ws.c */ + + void WS_Init(struct ws *ws, const char *id, void *space, unsigned len); ++ ++/* WS_Reserve(): Use WS_ReserveSize() or WS_ReserveAll() */ + unsigned WS_Reserve(struct ws *ws, unsigned bytes); ++unsigned WS_ReserveSize(struct ws *, unsigned); + unsigned WS_ReserveAll(struct ws *); + unsigned WS_ReserveLumps(struct ws *ws, size_t sz); + void WS_MarkOverflow(struct ws *ws); +--- varnish-6.2.1.orig/bin/varnishd/cache/cache_session.c ++++ varnish-6.2.1/bin/varnishd/cache/cache_session.c +@@ -112,7 +112,7 @@ ses_reserve_attr(struct sess *sp, enum s + assert(a < SA_LAST); + assert(sz >= 0); + AN(dst); +- o = WS_Reserve(sp->ws, sz); ++ o = WS_ReserveSize(sp->ws, sz); + assert(o >= sz); + *dst = sp->ws->f; + o = sp->ws->f - sp->ws->s; +@@ -415,7 +415,7 @@ ses_handle(struct waited *wp, enum wait_ + case WAITER_ACTION: + pp = sp->pool; + CHECK_OBJ_NOTNULL(pp, POOL_MAGIC); +- assert(sizeof *tp <= WS_Reserve(sp->ws, sizeof *tp)); ++ assert(sizeof *tp <= WS_ReserveSize(sp->ws, sizeof *tp)); + tp = (void*)sp->ws->f; + tp->func = xp->unwait; + tp->priv = sp; +@@ -453,7 +453,7 @@ SES_Wait(struct sess *sp, const struct t + /* + * put struct waited on the workspace + */ +- if (WS_Reserve(sp->ws, sizeof(struct waited)) ++ if (WS_ReserveSize(sp->ws, sizeof(struct waited)) + < sizeof(struct waited)) { + SES_Delete(sp, SC_OVERLOAD, NAN); + return; +--- varnish-6.2.1.orig/bin/varnishd/cache/cache_wrk.c ++++ varnish-6.2.1/bin/varnishd/cache/cache_wrk.c +@@ -238,7 +238,7 @@ Pool_Task_Arg(struct worker *wrk, enum t + retval = 0; + } + AZ(wrk2->task.func); +- assert(arg_len <= WS_Reserve(wrk2->aws, arg_len)); ++ assert(arg_len <= WS_ReserveSize(wrk2->aws, arg_len)); + memcpy(wrk2->aws->f, arg, arg_len); + wrk2->task.func = func; + wrk2->task.priv = wrk2->aws->f; +--- varnish-6.2.1.orig/bin/varnishd/cache/cache_ws.c ++++ varnish-6.2.1/bin/varnishd/cache/cache_ws.c +@@ -247,9 +247,34 @@ WS_ReserveAll(struct ws *ws) + } + + /* +- * bytes == 0 argument is deprecated - use WS_ReserveAll +- * +- * XXX rename to WS_ReserveSize and macro-wrap WS_Reserve to emit #warn ? ++ * WS_Release() must be called for retval > 0 only ++ */ ++unsigned ++WS_ReserveSize(struct ws *ws, unsigned bytes) ++{ ++ unsigned b2; ++ ++ WS_Assert(ws); ++ assert(ws->r == NULL); ++ assert(bytes > 0); ++ ++ b2 = PRNDDN(ws->e - ws->f); ++ if (bytes < b2) ++ b2 = PRNDUP(bytes); ++ ++ if (ws->f + b2 > ws->e) { ++ WS_MarkOverflow(ws); ++ return (0); ++ } ++ ws->r = ws->f + b2; ++ DSL(DBG_WORKSPACE, 0, "WS_ReserveSize(%p, %u/%u) = %u", ++ ws, b2, bytes, pdiff(ws->f, ws->r)); ++ WS_Assert(ws); ++ return (pdiff(ws->f, ws->r)); ++} ++ ++/* ++ * XXX remove for 2020-03-15 release + */ + unsigned + WS_Reserve(struct ws *ws, unsigned bytes) +--- varnish-6.2.1.orig/lib/libvmod_proxy/vmod_proxy.c ++++ varnish-6.2.1/lib/libvmod_proxy/vmod_proxy.c +@@ -105,7 +105,7 @@ tlv_string(VRT_CTX, int tlv) + + if (VPX_tlv(ctx->req, tlv, (void **)&dst, &len)) + return (NULL); +- if (!WS_Reserve(ctx->ws, len+1)) ++ if (!WS_ReserveSize(ctx->ws, len+1)) + return (NULL); + d = ctx->ws->f; + memcpy(d, dst, len); diff -Nru varnish-6.2.1/debian/patches/CVE-2020-11653-03.patch varnish-6.2.1/debian/patches/CVE-2020-11653-03.patch --- varnish-6.2.1/debian/patches/CVE-2020-11653-03.patch 1970-01-01 01:00:00.000000000 +0100 +++ varnish-6.2.1/debian/patches/CVE-2020-11653-03.patch 2022-08-16 17:55:23.000000000 +0100 @@ -0,0 +1,72 @@ +From 4921b008487555e2a32d542309e81eefc7870b42 Mon Sep 17 00:00:00 2001 +From: Nils Goroll +Date: Tue, 26 Nov 2019 13:21:37 +0100 +Subject: [PATCH 01/13] add a facility to test WS_ReserveSize() + +(cherry picked from commit ed3b095c0414af453493580a654f63a02d22e0e8) +--- + lib/libvmod_vtc/vmod.vcc | 8 ++++++++ + lib/libvmod_vtc/vmod_vtc.c | 28 ++++++++++++++++++++++++++++ + 2 files changed, 36 insertions(+) + +diff --git a/lib/libvmod_vtc/vmod.vcc b/lib/libvmod_vtc/vmod.vcc +index e1644fffc..907d8720b 100644 +--- a/lib/libvmod_vtc/vmod.vcc ++++ b/lib/libvmod_vtc/vmod.vcc +@@ -96,6 +96,14 @@ as much as needed to leave that many bytes free. The actual allocation size + may be higher to comply with memory alignment requirements of the CPU + architecture. A failed allocation fails the transaction. + ++$Function BYTES workspace_reserve(ENUM { client, backend, session, thread }, ++ INT size) ++ ++Attempt to reserve *size* bytes and release the reservation right ++away. Return the size of the reservation. ++ ++See `vtc.workspace_alloc()` for semantics of the *size* argument. ++ + $Function INT workspace_free(ENUM { client, backend, session, thread }) + + Find how much unallocated space there is left in a workspace. +diff --git a/lib/libvmod_vtc/vmod_vtc.c b/lib/libvmod_vtc/vmod_vtc.c +index ee9d23fa0..a2342c110 100644 +--- a/lib/libvmod_vtc/vmod_vtc.c ++++ b/lib/libvmod_vtc/vmod_vtc.c +@@ -169,6 +169,34 @@ vmod_workspace_alloc(VRT_CTX, VCL_ENUM which, VCL_INT size) + memset(p, '\0', size); + } + ++VCL_BYTES v_matchproto_(td_vtc_workspace_reserve) ++vmod_workspace_reserve(VRT_CTX, VCL_ENUM which, VCL_INT size) ++{ ++ struct ws *ws; ++ unsigned r; ++ ++ CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); ++ ++ ws = vtc_ws_find(ctx, which); ++ if (ws == NULL) ++ return (0); ++ WS_Assert(ws); ++ ++ if (size < 0) { ++ size += WS_ReserveAll(ws); ++ WS_Release(ws, 0); ++ } ++ if (size <= 0) { ++ VRT_fail(ctx, "Attempted negative WS reservation"); ++ return (0); ++ } ++ r = WS_ReserveSize(ws, size); ++ if (r == 0) ++ return (0); ++ WS_Release(ws, 0); ++ return (1); ++} ++ + VCL_INT v_matchproto_(td_vtc_workspace_free) + vmod_workspace_free(VRT_CTX, VCL_ENUM which) + { +-- +2.25.1 + diff -Nru varnish-6.2.1/debian/patches/CVE-2020-11653-04.patch varnish-6.2.1/debian/patches/CVE-2020-11653-04.patch --- varnish-6.2.1/debian/patches/CVE-2020-11653-04.patch 1970-01-01 01:00:00.000000000 +0100 +++ varnish-6.2.1/debian/patches/CVE-2020-11653-04.patch 2022-08-16 17:55:23.000000000 +0100 @@ -0,0 +1,67 @@ +From ccc936474ce64d710394df3565efaf48a8169b8e Mon Sep 17 00:00:00 2001 +From: Nils Goroll +Date: Tue, 26 Nov 2019 13:27:09 +0100 +Subject: [PATCH 02/13] WS_ReserveSize() must not hold a reservation for zero + return value + +This originates from a3d47c258fb7938f67a053f6d041257edb69afe9, but +was overlooked in 4e33359772a3d751b2ef4b5c4b40259f1bcd6903: + +When there is insufficient space to fulfil the reservation request, we +must not leave the workspace reserved. + +Fixes varnishcache/varnish-cache#3131 + +(cherry picked from commit 505b7bd9643006fa8e3977f920564ce12a2b24a2) +--- + bin/varnishd/cache/cache_ws.c | 2 +- + bin/varnishtest/tests/r03131.vtc | 24 ++++++++++++++++++++++++ + 2 files changed, 25 insertions(+), 1 deletion(-) + create mode 100644 bin/varnishtest/tests/r03131.vtc + +diff --git a/bin/varnishd/cache/cache_ws.c b/bin/varnishd/cache/cache_ws.c +index 7b8df6d23..e98e2cc69 100644 +--- a/bin/varnishd/cache/cache_ws.c ++++ b/bin/varnishd/cache/cache_ws.c +@@ -262,7 +262,7 @@ WS_ReserveSize(struct ws *ws, unsigned bytes) + if (bytes < b2) + b2 = PRNDUP(bytes); + +- if (ws->f + b2 > ws->e) { ++ if (ws->f + b2 >= ws->e) { + WS_MarkOverflow(ws); + return (0); + } +diff --git a/bin/varnishtest/tests/r03131.vtc b/bin/varnishtest/tests/r03131.vtc +new file mode 100644 +index 000000000..2722b748a +--- /dev/null ++++ b/bin/varnishtest/tests/r03131.vtc +@@ -0,0 +1,24 @@ ++varnishtest "Test workspace functions in vmod_vtc" ++ ++varnish v1 -vcl { ++ import vtc; ++ import std; ++ ++ backend dummy {.host = "${bad_backend}"; } ++ ++ sub vcl_recv { ++ return (synth(200)); ++ } ++ ++ sub vcl_synth { ++ set resp.http.res1 = vtc.workspace_reserve(client, 1024 * 1024); ++ vtc.workspace_alloc(client, -1); ++ set resp.http.res2 = vtc.workspace_reserve(client, 8); ++ set resp.http.res3 = vtc.workspace_reserve(client, 8); ++ } ++} -start ++ ++client c1 { ++ txreq ++ rxresp ++} -run +-- +2.25.1 + diff -Nru varnish-6.2.1/debian/patches/CVE-2020-11653-05.patch varnish-6.2.1/debian/patches/CVE-2020-11653-05.patch --- varnish-6.2.1/debian/patches/CVE-2020-11653-05.patch 1970-01-01 01:00:00.000000000 +0100 +++ varnish-6.2.1/debian/patches/CVE-2020-11653-05.patch 2022-08-16 17:55:23.000000000 +0100 @@ -0,0 +1,23 @@ +From 299e298382dbe609363ed5a0fad74d4cc17b446f Mon Sep 17 00:00:00 2001 +From: Nils Goroll +Date: Tue, 26 Nov 2019 14:09:32 +0100 +Subject: [PATCH 03/13] fix copy-pasta vtc description + +(cherry picked from commit 815331b3aecca0eb7e4e29f6dd4d778124c2ac9d) +--- + bin/varnishtest/tests/r03131.vtc | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/bin/varnishtest/tests/r03131.vtc b/bin/varnishtest/tests/r03131.vtc +index 2722b748a..43f0995b0 100644 +--- a/bin/varnishtest/tests/r03131.vtc ++++ b/bin/varnishtest/tests/r03131.vtc +@@ -1,4 +1,4 @@ +-varnishtest "Test workspace functions in vmod_vtc" ++varnishtest "Test WS_ReserveSize() overflow behavior" + + varnish v1 -vcl { + import vtc; +-- +2.25.1 + diff -Nru varnish-6.2.1/debian/patches/CVE-2020-11653-06.patch varnish-6.2.1/debian/patches/CVE-2020-11653-06.patch --- varnish-6.2.1/debian/patches/CVE-2020-11653-06.patch 1970-01-01 01:00:00.000000000 +0100 +++ varnish-6.2.1/debian/patches/CVE-2020-11653-06.patch 2022-08-16 17:55:23.000000000 +0100 @@ -0,0 +1,415 @@ +From dd33a92513f9339c7e3cd977ff0aae56688c13fe Mon Sep 17 00:00:00 2001 +From: Nils Goroll +Date: Tue, 26 Nov 2019 14:56:24 +0100 +Subject: [PATCH 04/13] Add Session Attribute workspace overflow handling + +Notes: + +* for the acceptor, I think it makes sense to keep AN assertion (pun!) + because varnish is not viable if the session workspace is too small + to even hold the attributes initialized in the acceptor. + + If this was an issue, we should rather revisit the minimum values for + the session workspace + +* for h1 and h2 session setup, I have used XXXAN() because I am not sure + how we should best handle allocation failures. + +* The relevant bit, for now, is the proxy code which may allocate + arbitrarily long TLV attributes, so this is the code for which we now + actually handle errors and test that we do + +On the vtc: I added the test to o00005.vtc because there existed a +previous overflow test from 267504b8143bdb8ef96240455a3aa788f96b579b, +but that only tested for the one case of a WS overflow which was already +handled. + +Fixes varnishcache/varnish-cache#3145 + +(cherry picked from commit 287dc4a6745c374e0b229bfa861d664989a3a9e8) +--- + bin/varnishd/cache/cache_acceptor.c | 14 ++--- + bin/varnishd/cache/cache_session.c | 20 ++++--- + bin/varnishd/cache/cache_varnishd.h | 4 +- + bin/varnishd/http1/cache_http1_fsm.c | 2 +- + bin/varnishd/http2/cache_http2_session.c | 4 +- + bin/varnishd/proxy/cache_proxy_proto.c | 55 +++++++++++++------ + bin/varnishtest/tests/o00005.vtc | 68 +++++++++++++++++++++++- + 7 files changed, 130 insertions(+), 37 deletions(-) + +diff --git a/bin/varnishd/cache/cache_acceptor.c b/bin/varnishd/cache/cache_acceptor.c +index 8300d1b5d..ee0b6063e 100644 +--- a/bin/varnishd/cache/cache_acceptor.c ++++ b/bin/varnishd/cache/cache_acceptor.c +@@ -317,17 +317,17 @@ vca_mk_tcp(const struct wrk_accept *wa, + struct sockaddr_storage ss; + socklen_t sl; + +- SES_Reserve_remote_addr(sp, &sa); ++ AN(SES_Reserve_remote_addr(sp, &sa)); + AN(VSA_Build(sa, &wa->acceptaddr, wa->acceptaddrlen)); + sp->sattr[SA_CLIENT_ADDR] = sp->sattr[SA_REMOTE_ADDR]; + + VTCP_name(sa, raddr, VTCP_ADDRBUFSIZE, rport, VTCP_PORTBUFSIZE); +- SES_Set_String_Attr(sp, SA_CLIENT_IP, raddr); +- SES_Set_String_Attr(sp, SA_CLIENT_PORT, rport); ++ AN(SES_Set_String_Attr(sp, SA_CLIENT_IP, raddr)); ++ AN(SES_Set_String_Attr(sp, SA_CLIENT_PORT, rport)); + + sl = sizeof ss; + AZ(getsockname(sp->fd, (void*)&ss, &sl)); +- SES_Reserve_local_addr(sp, &sa); ++ AN(SES_Reserve_local_addr(sp, &sa)); + AN(VSA_Build(sa, &ss, sl)); + sp->sattr[SA_SERVER_ADDR] = sp->sattr[SA_LOCAL_ADDR]; + VTCP_name(sa, laddr, VTCP_ADDRBUFSIZE, lport, VTCP_PORTBUFSIZE); +@@ -340,13 +340,13 @@ vca_mk_uds(struct wrk_accept *wa, struct sess *sp, char *laddr, char *lport, + struct suckaddr *sa; + + (void) wa; +- SES_Reserve_remote_addr(sp, &sa); ++ AN(SES_Reserve_remote_addr(sp, &sa)); + AZ(SES_Set_remote_addr(sp, bogo_ip)); + sp->sattr[SA_CLIENT_ADDR] = sp->sattr[SA_REMOTE_ADDR]; + sp->sattr[SA_LOCAL_ADDR] = sp->sattr[SA_REMOTE_ADDR]; + sp->sattr[SA_SERVER_ADDR] = sp->sattr[SA_REMOTE_ADDR]; +- SES_Set_String_Attr(sp, SA_CLIENT_IP, "0.0.0.0"); +- SES_Set_String_Attr(sp, SA_CLIENT_PORT, "0"); ++ AN(SES_Set_String_Attr(sp, SA_CLIENT_IP, "0.0.0.0")); ++ AN(SES_Set_String_Attr(sp, SA_CLIENT_PORT, "0")); + + strcpy(laddr, "0.0.0.0"); + strcpy(raddr, "0.0.0.0"); +diff --git a/bin/varnishd/cache/cache_session.c b/bin/varnishd/cache/cache_session.c +index 8c9e2d7c9..c9a0f5180 100644 +--- a/bin/varnishd/cache/cache_session.c ++++ b/bin/varnishd/cache/cache_session.c +@@ -103,8 +103,8 @@ ses_set_attr(const struct sess *sp, enum sess_attr a, const void *src, int sz) + return (0); + } + +-static void +-ses_reserve_attr(struct sess *sp, enum sess_attr a, void **dst, int sz) ++static int ++ses_res_attr(struct sess *sp, enum sess_attr a, void **dst, int sz) + { + ssize_t o; + +@@ -113,12 +113,14 @@ ses_reserve_attr(struct sess *sp, enum sess_attr a, void **dst, int sz) + assert(sz >= 0); + AN(dst); + o = WS_ReserveSize(sp->ws, sz); +- assert(o >= sz); ++ if (o < sz) ++ return (0); + *dst = sp->ws->f; + o = sp->ws->f - sp->ws->s; + WS_Release(sp->ws, sz); + assert(o >= 0 && o <= 0xffff); + sp->sattr[a] = (uint16_t)o; ++ return (1); + } + + #define SESS_ATTR(UP, low, typ, len) \ +@@ -134,16 +136,16 @@ ses_reserve_attr(struct sess *sp, enum sess_attr a, void **dst, int sz) + return (ses_get_attr(sp, SA_##UP, (void**)dst)); \ + } \ + \ +- void \ ++ int \ + SES_Reserve_##low(struct sess *sp, typ **dst) \ + { \ +- assert(len >= 0); \ +- ses_reserve_attr(sp, SA_##UP, (void**)dst, len); \ ++ assert(len > 0); \ ++ return (ses_res_attr(sp, SA_##UP, (void**)dst, len)); \ + } + + #include "tbl/sess_attr.h" + +-void ++int + SES_Set_String_Attr(struct sess *sp, enum sess_attr a, const char *src) + { + void *q; +@@ -157,8 +159,10 @@ SES_Set_String_Attr(struct sess *sp, enum sess_attr a, const char *src) + default: WRONG("wrong sess_attr"); + } + +- ses_reserve_attr(sp, a, &q, strlen(src) + 1); ++ if (! ses_res_attr(sp, a, &q, strlen(src) + 1)) ++ return (0); + strcpy(q, src); ++ return (1); + } + + const char * +diff --git a/bin/varnishd/cache/cache_varnishd.h b/bin/varnishd/cache/cache_varnishd.h +index f5c4bf656..4d6ce1022 100644 +--- a/bin/varnishd/cache/cache_varnishd.h ++++ b/bin/varnishd/cache/cache_varnishd.h +@@ -378,9 +378,9 @@ enum htc_status_e HTC_RxStuff(struct http_conn *, htc_complete_f *, + + #define SESS_ATTR(UP, low, typ, len) \ + int SES_Set_##low(const struct sess *sp, const typ *src); \ +- void SES_Reserve_##low(struct sess *sp, typ **dst); ++ int SES_Reserve_##low(struct sess *sp, typ **dst); + #include "tbl/sess_attr.h" +-void SES_Set_String_Attr(struct sess *sp, enum sess_attr a, const char *src); ++int SES_Set_String_Attr(struct sess *sp, enum sess_attr a, const char *src); + + + enum htc_status_e { +diff --git a/bin/varnishd/http1/cache_http1_fsm.c b/bin/varnishd/http1/cache_http1_fsm.c +index 4f6e8efd1..2b937ec86 100644 +--- a/bin/varnishd/http1/cache_http1_fsm.c ++++ b/bin/varnishd/http1/cache_http1_fsm.c +@@ -112,7 +112,7 @@ http1_new_session(struct worker *wrk, void *arg) + CHECK_OBJ_NOTNULL(sp, SESS_MAGIC); + + HTC_RxInit(req->htc, req->ws); +- SES_Reserve_proto_priv(sp, &u); ++ XXXAN(SES_Reserve_proto_priv(sp, &u)); + http1_setstate(sp, H1NEWREQ); + wrk->task.func = http1_req; + wrk->task.priv = req; +diff --git a/bin/varnishd/http2/cache_http2_session.c b/bin/varnishd/http2/cache_http2_session.c +index efd560db6..788879bbf 100644 +--- a/bin/varnishd/http2/cache_http2_session.c ++++ b/bin/varnishd/http2/cache_http2_session.c +@@ -101,7 +101,7 @@ h2_init_sess(const struct worker *wrk, struct sess *sp, + + if (SES_Get_proto_priv(sp, &up)) { + /* Already reserved if we came via H1 */ +- SES_Reserve_proto_priv(sp, &up); ++ XXXAN(SES_Reserve_proto_priv(sp, &up)); + *up = 0; + } + if (*up == 0) { +@@ -130,7 +130,7 @@ h2_init_sess(const struct worker *wrk, struct sess *sp, + AZ(VHT_Init(h2->dectbl, + h2->local_settings.header_table_size)); + +- SES_Reserve_proto_priv(sp, &up); ++ XXXAN(SES_Reserve_proto_priv(sp, &up)); + *up = (uintptr_t)h2; + } + AN(up); +diff --git a/bin/varnishd/proxy/cache_proxy_proto.c b/bin/varnishd/proxy/cache_proxy_proto.c +index 86fc2f97d..f5fecad02 100644 +--- a/bin/varnishd/proxy/cache_proxy_proto.c ++++ b/bin/varnishd/proxy/cache_proxy_proto.c +@@ -49,6 +49,13 @@ struct vpx_tlv { + char tlv[1]; + }; + ++static inline int ++vpx_ws_err(const struct req *req) ++{ ++ VSL(SLT_Error, req->sp->vxid, "insufficient workspace"); ++ return (-1); ++} ++ + /********************************************************************** + * PROXY 1 protocol + */ +@@ -128,10 +135,19 @@ vpx_proto1(const struct worker *wrk, const struct req *req) + freeaddrinfo(res); + return (-1); + } +- SES_Reserve_client_addr(req->sp, &sa); ++ if (! SES_Reserve_client_addr(req->sp, &sa)) { ++ freeaddrinfo(res); ++ return (vpx_ws_err(req)); ++ } + AN(VSA_Build(sa, res->ai_addr, res->ai_addrlen)); +- SES_Set_String_Attr(req->sp, SA_CLIENT_IP, fld[1]); +- SES_Set_String_Attr(req->sp, SA_CLIENT_PORT, fld[3]); ++ if (! SES_Set_String_Attr(req->sp, SA_CLIENT_IP, fld[1])) { ++ freeaddrinfo(res); ++ return (vpx_ws_err(req)); ++ } ++ if (! SES_Set_String_Attr(req->sp, SA_CLIENT_PORT, fld[3])) { ++ freeaddrinfo(res); ++ return (vpx_ws_err(req)); ++ } + freeaddrinfo(res); + + i = getaddrinfo(fld[2], fld[4], &hints, &res); +@@ -149,7 +165,10 @@ vpx_proto1(const struct worker *wrk, const struct req *req) + freeaddrinfo(res); + return (-1); + } +- SES_Reserve_server_addr(req->sp, &sa); ++ if (! SES_Reserve_server_addr(req->sp, &sa)) { ++ freeaddrinfo(res); ++ return (vpx_ws_err(req)); ++ } + AN(VSA_Build(sa, res->ai_addr, res->ai_addrlen)); + freeaddrinfo(res); + +@@ -403,14 +422,16 @@ vpx_proto2(const struct worker *wrk, struct req *req) + /* dst/server */ + memcpy(&sin4.sin_addr, p + 20, 4); + memcpy(&sin4.sin_port, p + 26, 2); +- SES_Reserve_server_addr(req->sp, &sa); ++ if (! SES_Reserve_server_addr(req->sp, &sa)) ++ return (vpx_ws_err(req)); + AN(VSA_Build(sa, &sin4, sizeof sin4)); + VTCP_name(sa, ha, sizeof ha, pa, sizeof pa); + + /* src/client */ + memcpy(&sin4.sin_addr, p + 16, 4); + memcpy(&sin4.sin_port, p + 24, 2); +- SES_Reserve_client_addr(req->sp, &sa); ++ if (! SES_Reserve_client_addr(req->sp, &sa)) ++ return (vpx_ws_err(req)); + AN(VSA_Build(sa, &sin4, sizeof sin4)); + break; + case 0x21: +@@ -429,14 +450,16 @@ vpx_proto2(const struct worker *wrk, struct req *req) + /* dst/server */ + memcpy(&sin6.sin6_addr, p + 32, 16); + memcpy(&sin6.sin6_port, p + 50, 2); +- SES_Reserve_server_addr(req->sp, &sa); ++ if (! SES_Reserve_server_addr(req->sp, &sa)) ++ return (vpx_ws_err(req)); + AN(VSA_Build(sa, &sin6, sizeof sin6)); + VTCP_name(sa, ha, sizeof ha, pa, sizeof pa); + + /* src/client */ + memcpy(&sin6.sin6_addr, p + 16, 16); + memcpy(&sin6.sin6_port, p + 48, 2); +- SES_Reserve_client_addr(req->sp, &sa); ++ if (! SES_Reserve_client_addr(req->sp, &sa)) ++ return (vpx_ws_err(req)); + AN(VSA_Build(sa, &sin6, sizeof sin6)); + break; + default: +@@ -448,8 +471,10 @@ vpx_proto2(const struct worker *wrk, struct req *req) + + AN(sa); + VTCP_name(sa, hb, sizeof hb, pb, sizeof pb); +- SES_Set_String_Attr(req->sp, SA_CLIENT_IP, hb); +- SES_Set_String_Attr(req->sp, SA_CLIENT_PORT, pb); ++ if (! SES_Set_String_Attr(req->sp, SA_CLIENT_IP, hb)) ++ return (vpx_ws_err(req)); ++ if (! SES_Set_String_Attr(req->sp, SA_CLIENT_PORT, pb)) ++ return (vpx_ws_err(req)); + + VSL(SLT_Proxy, req->sp->vxid, "2 %s %s %s %s", hb, pb, ha, pa); + +@@ -476,15 +501,13 @@ vpx_proto2(const struct worker *wrk, struct req *req) + return (-1); + } + tlv = WS_Alloc(req->sp->ws, sizeof *tlv + tlv_len); +- if (tlv == NULL) { +- VSL(SLT_ProxyGarbage, req->sp->vxid, +- "PROXY2: TLV overflows WS"); +- return (-1); +- } ++ if (tlv == NULL) ++ return (vpx_ws_err(req)); + INIT_OBJ(tlv, VPX_TLV_MAGIC); + tlv->len = tlv_len; + memcpy(tlv->tlv, tlv_start, tlv_len); +- SES_Reserve_proxy_tlv(req->sp, &up); ++ if (! SES_Reserve_proxy_tlv(req->sp, &up)) ++ return (vpx_ws_err(req)); + *up = (uintptr_t)tlv; + return (0); + } +diff --git a/bin/varnishtest/tests/o00005.vtc b/bin/varnishtest/tests/o00005.vtc +index 3ae1aacfe..d84b92d4d 100644 +--- a/bin/varnishtest/tests/o00005.vtc ++++ b/bin/varnishtest/tests/o00005.vtc +@@ -5,7 +5,8 @@ server s1 { + txresp + } -start + +-varnish v1 -proto "PROXY" -vcl+backend { ++varnish v1 -arg "-p pool_sess=0,0,0" -proto "PROXY" -vcl+backend { ++ import vtc; + import proxy; + + sub vcl_deliver { +@@ -20,6 +21,7 @@ varnish v1 -proto "PROXY" -vcl+backend { + set resp.http.key = proxy.cert_key(); + set resp.http.sign = proxy.cert_sign(); + set resp.http.cn = proxy.client_cert_cn(); ++ set resp.http.ws_free = vtc.workspace_free(session); + } + } -start + +@@ -243,4 +245,68 @@ client c1 { + expect_close + } -run + ++delay 1 ++ + varnish v1 -expect ws_session_overflow == 1 ++ ++# error handling elsewhere in the proxy code ++# request is the same as initial ++ ++varnish v1 -cliok "param.set workspace_session 450" ++varnish v1 -cliok "param.set pool_sess 10,100,1" ++ ++delay 1 ++ ++# get rid of the surplus session mpl ++client c10 -proxy1 "1.2.3.4:1111 5.6.7.8:5678" { ++ txreq ++ rxresp ++} -start ++client c11 -proxy1 "1.2.3.4:1111 5.6.7.8:5678" { ++ txreq ++ rxresp ++} -start ++client c12 -proxy1 "1.2.3.4:1111 5.6.7.8:5678" { ++ txreq ++ rxresp ++} -start ++client c13 -proxy1 "1.2.3.4:1111 5.6.7.8:5678" { ++ txreq ++ rxresp ++} -start ++client c14 -proxy1 "1.2.3.4:1111 5.6.7.8:5678" { ++ txreq ++ rxresp ++} -start ++ ++client c10 -wait ++client c11 -wait ++client c12 -wait ++client c13 -wait ++client c14 -wait ++ ++client c2 { ++ # PROXY2 with CRC32C TLV ++ sendhex { ++ 0d 0a 0d 0a 00 0d 0a 51 55 49 54 0a ++ 21 11 00 65 ++ d9 46 b5 21 ++ 5f 8e a8 22 ++ ed 96 ++ 01 bb ++ 03 00 04 95 03 ee 75 ++ 01 00 02 68 32 ++ 02 00 0a 68 6f 63 64 65 74 2e 6e 65 74 ++ 20 00 3d ++ 01 00 00 00 00 ++ 21 00 07 54 4c 53 76 31 2e 33 ++ 25 00 05 45 43 32 35 36 ++ 24 00 0a 52 53 41 2d 53 48 41 32 35 36 ++ 23 00 16 41 45 41 44 2d 41 45 53 31 32 38 ++ 2d 47 43 4d 2d 53 48 41 32 35 36 ++ } ++ txreq ++ expect_close ++} -run ++ ++varnish v1 -expect ws_session_overflow == 2 +-- +2.25.1 + diff -Nru varnish-6.2.1/debian/patches/CVE-2020-11653-07.patch varnish-6.2.1/debian/patches/CVE-2020-11653-07.patch --- varnish-6.2.1/debian/patches/CVE-2020-11653-07.patch 1970-01-01 01:00:00.000000000 +0100 +++ varnish-6.2.1/debian/patches/CVE-2020-11653-07.patch 2022-08-16 17:55:23.000000000 +0100 @@ -0,0 +1,50 @@ +From 33b8240b55156c303856868b822f054c6d86147c Mon Sep 17 00:00:00 2001 +From: Emmanuel Hocdet +Date: Thu, 14 Nov 2019 11:14:07 +0100 +Subject: [PATCH 05/13] Simplify WS allocation in tlv_string + +Patch by @ehocdet, commit message edited by @nigoroll: + +The root cause of #3131 was misdiagnosed to the extent that, while this +change had prevented it, the root cause was a bug in WS_ReserveSize() +fixed in 505b7bd9643006fa8e3977f920564ce12a2b24a2 + +The previous tlv_string() code was correct except for the +fact that error handling should have checked for WS_ReserveSize(ctx->ws, +len+1) <= len (also spotted by @ehocdet). + +Someone had mentioned at some point that we would not want to VRT_fail(), +but I think this must have been related to the proxy transport code, not +the proxy vmod. + +Ref varnishcache/varnish-cache#3131 + +(cherry picked from commit e74f9e871bc0eab014b7dd359d6ae83153c3ee37) +--- + lib/libvmod_proxy/vmod_proxy.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/lib/libvmod_proxy/vmod_proxy.c b/lib/libvmod_proxy/vmod_proxy.c +index 58f2db295..222de9c53 100644 +--- a/lib/libvmod_proxy/vmod_proxy.c ++++ b/lib/libvmod_proxy/vmod_proxy.c +@@ -105,12 +105,13 @@ tlv_string(VRT_CTX, int tlv) + + if (VPX_tlv(ctx->req, tlv, (void **)&dst, &len)) + return (NULL); +- if (!WS_ReserveSize(ctx->ws, len+1)) ++ d = WS_Alloc(ctx->ws, len+1); ++ if (d == NULL) { ++ VRT_fail(ctx, "proxy.TLV: out of workspace"); + return (NULL); +- d = ctx->ws->f; ++ } + memcpy(d, dst, len); + d[len] = '\0'; +- WS_Release(ctx->ws, len+1); + return (d); + } + +-- +2.25.1 + diff -Nru varnish-6.2.1/debian/patches/CVE-2020-11653-08.patch varnish-6.2.1/debian/patches/CVE-2020-11653-08.patch --- varnish-6.2.1/debian/patches/CVE-2020-11653-08.patch 1970-01-01 01:00:00.000000000 +0100 +++ varnish-6.2.1/debian/patches/CVE-2020-11653-08.patch 2022-08-16 17:55:23.000000000 +0100 @@ -0,0 +1,41 @@ +From f286ed20f6f5e7329e2a2967e6492f9a2d97207c Mon Sep 17 00:00:00 2001 +From: Nils Goroll +Date: Thu, 28 Nov 2019 11:19:08 +0100 +Subject: [PATCH 06/13] Try to make the proxy code session workspace overflow + test on 32bit + +Ref varnishcache/varnish-cache#3145 / 287dc4a6745c374e0b229bfa861d664989a3a9e8 + +(cherry picked from commit e1a57eb7a7350ac4c8a0235dc991bef400b118c1) +--- + bin/varnishtest/tests/o00005.vtc | 14 ++++++++++---- + 1 file changed, 10 insertions(+), 4 deletions(-) + +diff --git a/bin/varnishtest/tests/o00005.vtc b/bin/varnishtest/tests/o00005.vtc +index d84b92d4d..2ac11d1a8 100644 +--- a/bin/varnishtest/tests/o00005.vtc ++++ b/bin/varnishtest/tests/o00005.vtc +@@ -249,10 +249,16 @@ delay 1 + + varnish v1 -expect ws_session_overflow == 1 + +-# error handling elsewhere in the proxy code +-# request is the same as initial +- +-varnish v1 -cliok "param.set workspace_session 450" ++# workspace overflow handling elsewhere in the proxy code ++# ++# the workspace_session size is chosen to fail as closely as possible ++# below the minimum required value for the vtc to work (= the ++# workspace to overflow) both on 64 and 32 bit. ++# ++# This value is fragile, ideally we would want something like ++# vtc.alloc(-x), yet there is no vcl code being run before we parse ++# proxy headers ++varnish v1 -cliok "param.set workspace_session 410" + varnish v1 -cliok "param.set pool_sess 10,100,1" + + delay 1 +-- +2.25.1 + diff -Nru varnish-6.2.1/debian/patches/CVE-2020-11653-09.patch varnish-6.2.1/debian/patches/CVE-2020-11653-09.patch --- varnish-6.2.1/debian/patches/CVE-2020-11653-09.patch 1970-01-01 01:00:00.000000000 +0100 +++ varnish-6.2.1/debian/patches/CVE-2020-11653-09.patch 2022-08-16 17:55:23.000000000 +0100 @@ -0,0 +1,28 @@ +From 9296c547138bc6898d3ed8238019a0a5db4aa9b7 Mon Sep 17 00:00:00 2001 +From: Nils Goroll +Date: Thu, 28 Nov 2019 12:21:17 +0100 +Subject: [PATCH 07/13] more tweaking for 32bit vtest machines + +Ref varnishcache/varnish-cache#3145 / 287dc4a6745c374e0b229bfa861d664989a3a9e8 + +(cherry picked from commit d6dec03101a67c38addf549435ae51df38f1d7db) +--- + bin/varnishtest/tests/o00005.vtc | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/bin/varnishtest/tests/o00005.vtc b/bin/varnishtest/tests/o00005.vtc +index 2ac11d1a8..b09a8fcaf 100644 +--- a/bin/varnishtest/tests/o00005.vtc ++++ b/bin/varnishtest/tests/o00005.vtc +@@ -258,7 +258,7 @@ varnish v1 -expect ws_session_overflow == 1 + # This value is fragile, ideally we would want something like + # vtc.alloc(-x), yet there is no vcl code being run before we parse + # proxy headers +-varnish v1 -cliok "param.set workspace_session 410" ++varnish v1 -cliok "param.set workspace_session 402" + varnish v1 -cliok "param.set pool_sess 10,100,1" + + delay 1 +-- +2.25.1 + diff -Nru varnish-6.2.1/debian/patches/CVE-2020-11653-10.patch varnish-6.2.1/debian/patches/CVE-2020-11653-10.patch --- varnish-6.2.1/debian/patches/CVE-2020-11653-10.patch 1970-01-01 01:00:00.000000000 +0100 +++ varnish-6.2.1/debian/patches/CVE-2020-11653-10.patch 2022-08-16 17:55:23.000000000 +0100 @@ -0,0 +1,110 @@ +From e20d258a89774577d14273ae759d69b6d33717e9 Mon Sep 17 00:00:00 2001 +From: Martin Blix Grydeland +Date: Thu, 12 Dec 2019 13:12:48 +0100 +Subject: [PATCH 08/13] Handle out of session workspace in http1_new_session() + +If proxy protocol is in use, it is possible to fill the session workspace +exactly before entering http1_new_session(), which will cause it to assert +when calling SES_Reserve_proto_priv(). + +with this patch we will close the session gracefully. +--- + bin/varnishd/http1/cache_http1_fsm.c | 10 ++++- + bin/varnishtest/tests/f00005.vtc | 64 ++++++++++++++++++++++++++++ + 2 files changed, 73 insertions(+), 1 deletion(-) + create mode 100644 bin/varnishtest/tests/f00005.vtc + +diff --git a/bin/varnishd/http1/cache_http1_fsm.c b/bin/varnishd/http1/cache_http1_fsm.c +index 2b937ec86..fe8de28e0 100644 +--- a/bin/varnishd/http1/cache_http1_fsm.c ++++ b/bin/varnishd/http1/cache_http1_fsm.c +@@ -112,7 +112,15 @@ http1_new_session(struct worker *wrk, void *arg) + CHECK_OBJ_NOTNULL(sp, SESS_MAGIC); + + HTC_RxInit(req->htc, req->ws); +- XXXAN(SES_Reserve_proto_priv(sp, &u)); ++ if (!SES_Reserve_proto_priv(sp, &u)) { ++ /* Out of session workspace. Free the req, close the sess, ++ * and do not set a new task func, which will exit the ++ * worker thread. */ ++ VSL(SLT_Error, req->sp->vxid, "insufficient workspace"); ++ Req_Release(req); ++ SES_Delete(sp, SC_RX_JUNK, NAN); ++ return; ++ } + http1_setstate(sp, H1NEWREQ); + wrk->task.func = http1_req; + wrk->task.priv = req; +diff --git a/bin/varnishtest/tests/f00005.vtc b/bin/varnishtest/tests/f00005.vtc +new file mode 100644 +index 000000000..866d941dd +--- /dev/null ++++ b/bin/varnishtest/tests/f00005.vtc +@@ -0,0 +1,64 @@ ++varnishtest "proxy ws panic" ++ ++server s1 { ++ rxreq ++ txresp ++} -start ++ ++varnish v1 -proto "PROXY" -vcl+backend {}-start ++ ++# Too large proxy payload using TLV ++client c1 { ++ sendhex { ++0d 0a 0d 0a 00 0d 0a 51 ++55 49 54 0a 21 21 00 93 ++aa bb cc dd ee ff 11 22 ++33 44 55 66 77 88 99 aa ++bb cc dd ee ff 11 22 33 ++44 55 66 77 88 99 aa bb ++88 da 0d 73 02 00 3c 61 ++61 61 61 61 61 61 61 61 ++61 61 61 61 61 61 61 61 ++61 61 61 61 61 61 61 61 ++61 61 61 61 61 61 61 61 ++61 61 61 61 61 61 61 61 ++61 61 61 61 61 61 61 61 ++61 61 61 61 61 61 61 61 ++61 61 61 20 00 2d 01 01 ++00 00 00 21 00 07 54 4c ++53 76 31 2e 32 23 00 1b ++45 43 44 48 45 2d 52 53 ++41 2d 41 45 53 32 35 36 ++2d 47 43 4d 2d 53 48 41 ++33 38 34 ++ } ++ expect_close ++} -run ++ ++# Reduced size proxy payload to verify Varnish is still running ++client c1 { ++ sendhex { ++0d 0a 0d 0a 00 0d 0a 51 ++55 49 54 0a 21 21 00 8b ++aa bb cc dd ee ff 11 22 ++33 44 55 66 77 88 99 aa ++bb cc dd ee ff 11 22 33 ++44 55 66 77 88 99 aa bb ++88 da 0d 73 02 00 34 61 ++61 61 61 61 61 61 61 61 ++61 61 61 61 61 61 61 61 ++61 61 61 61 61 61 61 61 ++61 61 61 61 61 61 61 61 ++61 61 61 61 61 61 61 61 ++61 61 61 61 61 61 61 61 ++61 61 61 20 00 2d 01 01 ++00 00 00 21 00 07 54 4c ++53 76 31 2e 32 23 00 1b ++45 43 44 48 45 2d 52 53 ++41 2d 41 45 53 32 35 36 ++2d 47 43 4d 2d 53 48 41 ++33 38 34 ++ } ++ txreq ++ rxresp ++} -run +-- +2.25.1 + diff -Nru varnish-6.2.1/debian/patches/CVE-2020-11653-11.patch varnish-6.2.1/debian/patches/CVE-2020-11653-11.patch --- varnish-6.2.1/debian/patches/CVE-2020-11653-11.patch 1970-01-01 01:00:00.000000000 +0100 +++ varnish-6.2.1/debian/patches/CVE-2020-11653-11.patch 2022-08-16 17:55:23.000000000 +0100 @@ -0,0 +1,27 @@ +From 841c1e00b978a5ecf53f6c72cbd749e1c1730b12 Mon Sep 17 00:00:00 2001 +From: Martin Blix Grydeland +Date: Thu, 12 Dec 2019 13:16:40 +0100 +Subject: [PATCH 09/13] Remove extra call to SES_Reserve_proto_priv + +In h2_init_sess, an extra call was always made to SES_Reseve_proto_priv(), +even though it was already reserved. This wasted a pointer worth of +session workspace. This patch removes the extra call. +--- + bin/varnishd/http2/cache_http2_session.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/bin/varnishd/http2/cache_http2_session.c b/bin/varnishd/http2/cache_http2_session.c +index 788879bbf..977669589 100644 +--- a/bin/varnishd/http2/cache_http2_session.c ++++ b/bin/varnishd/http2/cache_http2_session.c +@@ -130,7 +130,6 @@ h2_init_sess(const struct worker *wrk, struct sess *sp, + AZ(VHT_Init(h2->dectbl, + h2->local_settings.header_table_size)); + +- XXXAN(SES_Reserve_proto_priv(sp, &up)); + *up = (uintptr_t)h2; + } + AN(up); +-- +2.25.1 + diff -Nru varnish-6.2.1/debian/patches/CVE-2020-11653-12.patch varnish-6.2.1/debian/patches/CVE-2020-11653-12.patch --- varnish-6.2.1/debian/patches/CVE-2020-11653-12.patch 1970-01-01 01:00:00.000000000 +0100 +++ varnish-6.2.1/debian/patches/CVE-2020-11653-12.patch 2022-08-16 17:55:23.000000000 +0100 @@ -0,0 +1,95 @@ +From e5bdc9b96327097d7f4e948149370e8fbad36954 Mon Sep 17 00:00:00 2001 +From: Martin Blix Grydeland +Date: Thu, 12 Dec 2019 13:51:17 +0100 +Subject: [PATCH 10/13] Remove call to SES_Reserve_proto_priv in h2_init_sess + +h2_init_sess can only be reached through H1 with either previous knowledge +or opportunistic upgrade. Because of this the proto_priv session attribute +will always be set before entry. This patch simplifies and removes dead +code containing a call to SES_Reserve_proto_priv. + +Note: Better diff with the --ignore-all-space option +--- + bin/varnishd/http2/cache_http2_session.c | 66 +++++++++++------------- + 1 file changed, 31 insertions(+), 35 deletions(-) + +diff --git a/bin/varnishd/http2/cache_http2_session.c b/bin/varnishd/http2/cache_http2_session.c +index 977669589..ea32cad27 100644 +--- a/bin/varnishd/http2/cache_http2_session.c ++++ b/bin/varnishd/http2/cache_http2_session.c +@@ -99,41 +99,37 @@ h2_init_sess(const struct worker *wrk, struct sess *sp, + uintptr_t *up; + struct h2_sess *h2; + +- if (SES_Get_proto_priv(sp, &up)) { +- /* Already reserved if we came via H1 */ +- XXXAN(SES_Reserve_proto_priv(sp, &up)); +- *up = 0; +- } +- if (*up == 0) { +- if (srq == NULL) +- srq = Req_New(wrk, sp); +- AN(srq); +- h2 = h2s; +- AN(h2); +- INIT_OBJ(h2, H2_SESS_MAGIC); +- h2->srq = srq; +- h2->htc = srq->htc; +- h2->ws = srq->ws; +- h2->vsl = srq->vsl; +- VSL_Flush(h2->vsl, 0); +- h2->vsl->wid = sp->vxid; +- h2->htc->rfd = &sp->fd; +- h2->sess = sp; +- h2->rxthr = pthread_self(); +- AZ(pthread_cond_init(h2->winupd_cond, NULL)); +- VTAILQ_INIT(&h2->streams); +- VTAILQ_INIT(&h2->txqueue); +- h2_local_settings(&h2->local_settings); +- h2->remote_settings = H2_proto_settings; +- h2->decode = decode; +- +- AZ(VHT_Init(h2->dectbl, +- h2->local_settings.header_table_size)); +- +- *up = (uintptr_t)h2; +- } +- AN(up); +- CAST_OBJ_NOTNULL(h2, (void*)(*up), H2_SESS_MAGIC); ++ /* proto_priv session attribute will always have been set up by H1 ++ * before reaching here. */ ++ AZ(SES_Get_proto_priv(sp, &up)); ++ assert(*up == 0); ++ ++ if (srq == NULL) ++ srq = Req_New(wrk, sp); ++ AN(srq); ++ h2 = h2s; ++ AN(h2); ++ INIT_OBJ(h2, H2_SESS_MAGIC); ++ h2->srq = srq; ++ h2->htc = srq->htc; ++ h2->ws = srq->ws; ++ h2->vsl = srq->vsl; ++ VSL_Flush(h2->vsl, 0); ++ h2->vsl->wid = sp->vxid; ++ h2->htc->rfd = &sp->fd; ++ h2->sess = sp; ++ h2->rxthr = pthread_self(); ++ AZ(pthread_cond_init(h2->winupd_cond, NULL)); ++ VTAILQ_INIT(&h2->streams); ++ VTAILQ_INIT(&h2->txqueue); ++ h2_local_settings(&h2->local_settings); ++ h2->remote_settings = H2_proto_settings; ++ h2->decode = decode; ++ ++ AZ(VHT_Init(h2->dectbl, h2->local_settings.header_table_size)); ++ ++ *up = (uintptr_t)h2; ++ + return (h2); + } + +-- +2.25.1 + diff -Nru varnish-6.2.1/debian/patches/CVE-2020-11653-13.patch varnish-6.2.1/debian/patches/CVE-2020-11653-13.patch --- varnish-6.2.1/debian/patches/CVE-2020-11653-13.patch 1970-01-01 01:00:00.000000000 +0100 +++ varnish-6.2.1/debian/patches/CVE-2020-11653-13.patch 2022-08-16 17:55:23.000000000 +0100 @@ -0,0 +1,65 @@ +From 0c38acb6da78081c9c666a9a2426e7ba945c5210 Mon Sep 17 00:00:00 2001 +From: Martin Blix Grydeland +Date: Thu, 12 Dec 2019 14:53:48 +0100 +Subject: [PATCH 11/13] Handle badly formatted proxy TLVs + +Proxy TLVs claiming to have PP2_TYPE_SSL sub-TLVs without complete payload +would cause a Varnish assert. This patch fixes the parsing of the TLVs. +--- + bin/varnishd/proxy/cache_proxy_proto.c | 9 +++++++-- + bin/varnishtest/tests/f00005.vtc | 12 ++++++++++++ + 2 files changed, 19 insertions(+), 2 deletions(-) + +diff --git a/bin/varnishd/proxy/cache_proxy_proto.c b/bin/varnishd/proxy/cache_proxy_proto.c +index f5fecad02..b84f6242c 100644 +--- a/bin/varnishd/proxy/cache_proxy_proto.c ++++ b/bin/varnishd/proxy/cache_proxy_proto.c +@@ -306,8 +306,9 @@ vpx_tlv_itern(struct vpx_tlv_iter *vpi) + return (1); + } + +-#define VPX_TLV_FOREACH(ptr, len, itv) \ +- for(vpx_tlv_iter0(itv, ptr, len); vpx_tlv_itern(itv);) ++#define VPX_TLV_FOREACH(ptr, len, itv) \ ++ for (vpx_tlv_iter0(itv, ptr, len); \ ++ (vpi->e == NULL) && vpx_tlv_itern(itv);) + + int + VPX_tlv(const struct req *req, int typ, void **dst, int *len) +@@ -483,6 +484,10 @@ vpx_proto2(const struct worker *wrk, struct req *req) + + VPX_TLV_FOREACH(d, l, vpi) { + if (vpi->t == PP2_TYPE_SSL) { ++ if (vpi->l < 5) { ++ vpi->e = "Length Error"; ++ break; ++ } + VPX_TLV_FOREACH((char*)vpi->p + 5, vpi->l - 5, vpi2) { + } + vpi->e = vpi2->e; +diff --git a/bin/varnishtest/tests/f00005.vtc b/bin/varnishtest/tests/f00005.vtc +index 866d941dd..b1b097fce 100644 +--- a/bin/varnishtest/tests/f00005.vtc ++++ b/bin/varnishtest/tests/f00005.vtc +@@ -35,6 +35,18 @@ bb cc dd ee ff 11 22 33 + expect_close + } -run + ++# Badly formatted TLV proxy payload ++client c1 { ++ sendhex { ++0d 0a 0d 0a 00 0d 0a 51 ++55 49 54 0a ++21 11 00 13 00 ff 20 ff 10 ff 03 21 20 30 00 20 ++20 00 00 19 00 02 29 20 00 00 00 41 20 9e 15 15 ++d6 00 00 08 00 00 00 00 00 07 7a 20 b1 3f 43 20 ++ } ++ expect_close ++} -run ++ + # Reduced size proxy payload to verify Varnish is still running + client c1 { + sendhex { +-- +2.25.1 + diff -Nru varnish-6.2.1/debian/patches/CVE-2020-11653-14.patch varnish-6.2.1/debian/patches/CVE-2020-11653-14.patch --- varnish-6.2.1/debian/patches/CVE-2020-11653-14.patch 1970-01-01 01:00:00.000000000 +0100 +++ varnish-6.2.1/debian/patches/CVE-2020-11653-14.patch 2022-08-16 17:55:23.000000000 +0100 @@ -0,0 +1,25 @@ +From 6d221929f761ea6e22e5384aee9981e513edae89 Mon Sep 17 00:00:00 2001 +From: Dridi Boukelmoune +Date: Mon, 16 Dec 2019 12:16:17 +0100 +Subject: [PATCH 12/13] Assert + +(cherry picked from commit 7da6220dfd86416200c43d84d40fce0cae1b5bae) +--- + bin/varnishd/cache/cache_ws.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/bin/varnishd/cache/cache_ws.c b/bin/varnishd/cache/cache_ws.c +index e98e2cc69..de04e896d 100644 +--- a/bin/varnishd/cache/cache_ws.c ++++ b/bin/varnishd/cache/cache_ws.c +@@ -235,6 +235,7 @@ WS_ReserveAll(struct ws *ws) + { + unsigned b; + ++ WS_Assert(ws); + assert(ws->r == NULL); + + ws->r = ws->e; +-- +2.25.1 + diff -Nru varnish-6.2.1/debian/patches/CVE-2020-11653-15.patch varnish-6.2.1/debian/patches/CVE-2020-11653-15.patch --- varnish-6.2.1/debian/patches/CVE-2020-11653-15.patch 1970-01-01 01:00:00.000000000 +0100 +++ varnish-6.2.1/debian/patches/CVE-2020-11653-15.patch 2022-08-16 17:55:23.000000000 +0100 @@ -0,0 +1,32 @@ +From bb3a1e362393ed78a9f55c1de32d58c6f2846420 Mon Sep 17 00:00:00 2001 +From: Martin Blix Grydeland +Date: Mon, 16 Dec 2019 16:37:27 +0100 +Subject: [PATCH 13/13] Fix WS_ReserveSize calls when bytes is equal to free + workspace + +Currently, with the 505b7bd9643006fa8e3977f920564ce12a2b24a2 patch, when +calling WS_ReserveSize with bytes equal to the amount of workspace that is +currently available, it will return zero and mark overflow. + +This patch redoes the patch, and changes it to return zero and overflow +only when the requested number of bytes is larger than what is available. +--- + bin/varnishd/cache/cache_ws.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/bin/varnishd/cache/cache_ws.c b/bin/varnishd/cache/cache_ws.c +index de04e896d..5de7a6830 100644 +--- a/bin/varnishd/cache/cache_ws.c ++++ b/bin/varnishd/cache/cache_ws.c +@@ -263,7 +263,7 @@ WS_ReserveSize(struct ws *ws, unsigned bytes) + if (bytes < b2) + b2 = PRNDUP(bytes); + +- if (ws->f + b2 >= ws->e) { ++ if (bytes > b2) { + WS_MarkOverflow(ws); + return (0); + } +-- +2.25.1 + diff -Nru varnish-6.2.1/debian/patches/CVE-2020-11653-16.patch varnish-6.2.1/debian/patches/CVE-2020-11653-16.patch --- varnish-6.2.1/debian/patches/CVE-2020-11653-16.patch 1970-01-01 01:00:00.000000000 +0100 +++ varnish-6.2.1/debian/patches/CVE-2020-11653-16.patch 2022-05-04 21:16:37.000000000 +0100 @@ -0,0 +1,60 @@ +From 676e3d2fdf2d44ab2017d0b54eb9cad3535b952c Mon Sep 17 00:00:00 2001 +From: Martin Blix Grydeland +Date: Mon, 16 Dec 2019 17:04:43 +0100 +Subject: [PATCH] Take sizeof pool_task into account when reserving WS in + SES_Wait + +The assert on WS_ReserveSize() in ses_handle() can not trip because +sizeof (struct pool_task) is less than sizeof (struct waited). But to safe +guard against future problems if that were to change, this patch makes +sure that the session workspace can hold the largest of them before +entering the waiter, erroring out if not. +--- + bin/varnishd/cache/cache_session.c | 14 +++++++++++--- + 1 file changed, 11 insertions(+), 3 deletions(-) + +--- varnish-6.2.1.orig/bin/varnishd/cache/cache_session.c ++++ varnish-6.2.1/bin/varnishd/cache/cache_session.c +@@ -403,6 +403,7 @@ ses_handle(struct waited *wp, enum wait_ + wp->magic = 0; + wp = NULL; + ++ /* The WS was reserved in SES_Wait() */ + WS_Release(sp->ws, 0); + + switch (ev) { +@@ -415,6 +416,7 @@ ses_handle(struct waited *wp, enum wait_ + case WAITER_ACTION: + pp = sp->pool; + CHECK_OBJ_NOTNULL(pp, POOL_MAGIC); ++ /* SES_Wait() guarantees the next will not assert. */ + assert(sizeof *tp <= WS_ReserveSize(sp->ws, sizeof *tp)); + tp = (void*)sp->ws->f; + tp->func = xp->unwait; +@@ -438,6 +440,7 @@ SES_Wait(struct sess *sp, const struct t + { + struct pool *pp; + struct waited *wp; ++ unsigned u; + + CHECK_OBJ_NOTNULL(sp, SESS_MAGIC); + CHECK_OBJ_NOTNULL(xp, TRANSPORT_MAGIC); +@@ -451,10 +454,15 @@ SES_Wait(struct sess *sp, const struct t + VTCP_nonblocking(sp->fd); + + /* +- * put struct waited on the workspace ++ * Put struct waited on the workspace. Make sure that the ++ * workspace can hold enough space for the largest of struct ++ * waited and pool_task, as pool_task will be needed when coming ++ * off the waiter again. + */ +- if (WS_ReserveSize(sp->ws, sizeof(struct waited)) +- < sizeof(struct waited)) { ++ u = sizeof (struct waited); ++ if (sizeof (struct pool_task) > u) ++ u = sizeof (struct pool_task); ++ if (!WS_ReserveSize(sp->ws, u)) { + SES_Delete(sp, SC_OVERLOAD, NAN); + return; + } diff -Nru varnish-6.2.1/debian/patches/CVE-2020-11653.patch varnish-6.2.1/debian/patches/CVE-2020-11653.patch --- varnish-6.2.1/debian/patches/CVE-2020-11653.patch 2022-05-04 21:16:37.000000000 +0100 +++ varnish-6.2.1/debian/patches/CVE-2020-11653.patch 1970-01-01 01:00:00.000000000 +0100 @@ -1,60 +0,0 @@ -From 676e3d2fdf2d44ab2017d0b54eb9cad3535b952c Mon Sep 17 00:00:00 2001 -From: Martin Blix Grydeland -Date: Mon, 16 Dec 2019 17:04:43 +0100 -Subject: [PATCH] Take sizeof pool_task into account when reserving WS in - SES_Wait - -The assert on WS_ReserveSize() in ses_handle() can not trip because -sizeof (struct pool_task) is less than sizeof (struct waited). But to safe -guard against future problems if that were to change, this patch makes -sure that the session workspace can hold the largest of them before -entering the waiter, erroring out if not. ---- - bin/varnishd/cache/cache_session.c | 14 +++++++++++--- - 1 file changed, 11 insertions(+), 3 deletions(-) - ---- varnish-6.2.1.orig/bin/varnishd/cache/cache_session.c -+++ varnish-6.2.1/bin/varnishd/cache/cache_session.c -@@ -403,6 +403,7 @@ ses_handle(struct waited *wp, enum wait_ - wp->magic = 0; - wp = NULL; - -+ /* The WS was reserved in SES_Wait() */ - WS_Release(sp->ws, 0); - - switch (ev) { -@@ -415,6 +416,7 @@ ses_handle(struct waited *wp, enum wait_ - case WAITER_ACTION: - pp = sp->pool; - CHECK_OBJ_NOTNULL(pp, POOL_MAGIC); -+ /* SES_Wait() guarantees the next will not assert. */ - assert(sizeof *tp <= WS_ReserveSize(sp->ws, sizeof *tp)); - tp = (void*)sp->ws->f; - tp->func = xp->unwait; -@@ -438,6 +440,7 @@ SES_Wait(struct sess *sp, const struct t - { - struct pool *pp; - struct waited *wp; -+ unsigned u; - - CHECK_OBJ_NOTNULL(sp, SESS_MAGIC); - CHECK_OBJ_NOTNULL(xp, TRANSPORT_MAGIC); -@@ -451,10 +454,15 @@ SES_Wait(struct sess *sp, const struct t - VTCP_nonblocking(sp->fd); - - /* -- * put struct waited on the workspace -+ * Put struct waited on the workspace. Make sure that the -+ * workspace can hold enough space for the largest of struct -+ * waited and pool_task, as pool_task will be needed when coming -+ * off the waiter again. - */ -- if (WS_ReserveSize(sp->ws, sizeof(struct waited)) -- < sizeof(struct waited)) { -+ u = sizeof (struct waited); -+ if (sizeof (struct pool_task) > u) -+ u = sizeof (struct pool_task); -+ if (!WS_ReserveSize(sp->ws, u)) { - SES_Delete(sp, SC_OVERLOAD, NAN); - return; - } diff -Nru varnish-6.2.1/debian/patches/series varnish-6.2.1/debian/patches/series --- varnish-6.2.1/debian/patches/series 2022-05-04 21:16:37.000000000 +0100 +++ varnish-6.2.1/debian/patches/series 2022-08-16 17:57:53.000000000 +0100 @@ -1,6 +1,19 @@ CVE-2019-20637.patch -WS_ReserveAll.patch -WS_ReserveSize.patch -CVE-2020-11653.patch +CVE-2020-11653-01.patch +CVE-2020-11653-02.patch +CVE-2020-11653-03.patch +CVE-2020-11653-04.patch +CVE-2020-11653-05.patch +CVE-2020-11653-06.patch +CVE-2020-11653-07.patch +CVE-2020-11653-08.patch +CVE-2020-11653-09.patch +CVE-2020-11653-10.patch +CVE-2020-11653-11.patch +CVE-2020-11653-12.patch +CVE-2020-11653-13.patch +CVE-2020-11653-14.patch +CVE-2020-11653-15.patch +CVE-2020-11653-16.patch CVE-2021-36740.patch CVE-2022-23959.patch diff -Nru varnish-6.2.1/debian/patches/WS_ReserveAll.patch varnish-6.2.1/debian/patches/WS_ReserveAll.patch --- varnish-6.2.1/debian/patches/WS_ReserveAll.patch 2022-05-04 21:16:37.000000000 +0100 +++ varnish-6.2.1/debian/patches/WS_ReserveAll.patch 1970-01-01 01:00:00.000000000 +0100 @@ -1,282 +0,0 @@ -From c6df6a5fa9e5575b079d602895eb429db417c5cd Mon Sep 17 00:00:00 2001 -From: Nils Goroll -Date: Mon, 8 Apr 2019 15:19:30 +0200 -Subject: [PATCH] Add WS_ReserveAll() to replace WS_Reserve(ws, 0) - -... to un-confuse the interface - -Notes on changes from WS_Reserve(): - -* Removed the first WS_Assert because all we change is ws->r and we got - a specific assert on it. - -* it follows from PAOK(ws->e) && PAOK(ws->f) in WS_Assert() that - PAOK(ws->r) && PAOK(b), so we remove the PRNDDN() - -Ref: varnishcache/varnish-cache#2967 - -(cherry picked from commit d001cdd2045aa484a968d09859cddf59dee372cb) ---- - bin/varnishd/cache/cache.h | 1 + - bin/varnishd/cache/cache_hash.c | 2 +- - bin/varnishd/cache/cache_http.c | 4 +-- - bin/varnishd/cache/cache_session.c | 2 +- - bin/varnishd/cache/cache_vary.c | 2 +- - bin/varnishd/cache/cache_vrt.c | 6 ++--- - bin/varnishd/cache/cache_vrt_filter.c | 2 +- - bin/varnishd/cache/cache_vrt_re.c | 2 +- - bin/varnishd/cache/cache_ws.c | 32 +++++++++++++++++++----- - bin/varnishd/http2/cache_http2_deliver.c | 6 +++-- - bin/varnishd/http2/cache_http2_hpack.c | 2 +- - lib/libvmod_blob/vmod_blob.c | 4 +-- - lib/libvmod_std/vmod_std.c | 2 +- - lib/libvmod_vtc/vmod_vtc.c | 4 +-- - 14 files changed, 47 insertions(+), 24 deletions(-) - ---- varnish-6.2.1.orig/bin/varnishd/cache/cache.h -+++ varnish-6.2.1/bin/varnishd/cache/cache.h -@@ -765,6 +765,7 @@ void WRK_BgThread(pthread_t *thr, const - - void WS_Init(struct ws *ws, const char *id, void *space, unsigned len); - unsigned WS_Reserve(struct ws *ws, unsigned bytes); -+unsigned WS_ReserveAll(struct ws *); - unsigned WS_ReserveLumps(struct ws *ws, size_t sz); - void WS_MarkOverflow(struct ws *ws); - void WS_Release(struct ws *ws, unsigned bytes); ---- varnish-6.2.1.orig/bin/varnishd/cache/cache_hash.c -+++ varnish-6.2.1/bin/varnishd/cache/cache_hash.c -@@ -650,7 +650,7 @@ HSH_Purge(struct worker *wrk, struct obj - - CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC); - CHECK_OBJ_NOTNULL(oh, OBJHEAD_MAGIC); -- ospc = WS_Reserve(wrk->aws, 0); -+ ospc = WS_ReserveAll(wrk->aws); - assert(ospc >= sizeof *ocp); - /* - * Because of "soft" purges, there might be oc's in the list that has ---- varnish-6.2.1.orig/bin/varnishd/cache/cache_http.c -+++ varnish-6.2.1/bin/varnishd/cache/cache_http.c -@@ -394,7 +394,7 @@ http_CollectHdrSep(struct http *hp, cons - } - if (b == NULL) { - /* Found second header, start our collection */ -- ml = WS_Reserve(hp->ws, 0); -+ ml = WS_ReserveAll(hp->ws); - b = hp->ws->f; - e = b + ml; - x = Tlen(hp->hd[f]); -@@ -1228,7 +1228,7 @@ http_PrintfHeader(struct http *to, const - unsigned l, n; - - CHECK_OBJ_NOTNULL(to, HTTP_MAGIC); -- l = WS_Reserve(to->ws, 0); -+ l = WS_ReserveAll(to->ws); - va_start(ap, fmt); - n = vsnprintf(to->ws->f, l, fmt, ap); - va_end(ap); ---- varnish-6.2.1.orig/bin/varnishd/cache/cache_session.c -+++ varnish-6.2.1/bin/varnishd/cache/cache_session.c -@@ -203,7 +203,7 @@ HTC_RxInit(struct http_conn *htc, struct - - CHECK_OBJ_NOTNULL(htc, HTTP_CONN_MAGIC); - htc->ws = ws; -- (void)WS_Reserve(htc->ws, 0); -+ (void)WS_ReserveAll(htc->ws); - htc->rxbuf_b = ws->f; - htc->rxbuf_e = ws->f; - if (htc->pipeline_b != NULL) { ---- varnish-6.2.1.orig/bin/varnishd/cache/cache_vary.c -+++ varnish-6.2.1/bin/varnishd/cache/cache_vary.c -@@ -230,7 +230,7 @@ VRY_Prep(struct req *req) - AZ(req->vary_b); - AZ(req->vary_l); - AZ(req->vary_e); -- (void)WS_Reserve(req->ws, 0); -+ (void)WS_ReserveAll(req->ws); - } else { - AN(req->ws->r); - } ---- varnish-6.2.1.orig/bin/varnishd/cache/cache_vrt.c -+++ varnish-6.2.1/bin/varnishd/cache/cache_vrt.c -@@ -261,7 +261,7 @@ VRT_String(struct ws *ws, const char *h, - unsigned u, x; - va_list aq; - -- u = WS_Reserve(ws, 0); -+ u = WS_ReserveAll(ws); - e = b = ws->f; - e += u; - -@@ -385,7 +385,7 @@ VRT_StrandsWS(struct ws *ws, const char - int i; - - AN(s); -- u = WS_Reserve(ws, 0); -+ u = WS_ReserveAll(ws); - - for (i = 0; i < s->n; i++) - if (s->p[i] != NULL && *s->p[i] != '\0') { -@@ -573,7 +573,7 @@ VRT_IP_string(VRT_CTX, VCL_IP ip) - CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); - if (ip == NULL) - return (NULL); -- len = WS_Reserve(ctx->ws, 0); -+ len = WS_ReserveAll(ctx->ws); - if (len == 0) { - WS_Release(ctx->ws, 0); - return (NULL); ---- varnish-6.2.1.orig/bin/varnishd/cache/cache_vrt_filter.c -+++ varnish-6.2.1/bin/varnishd/cache/cache_vrt_filter.c -@@ -251,7 +251,7 @@ filter_on_ws(struct ws *ws, filter_list_ - - AN(func); - AN(arg); -- u = WS_Reserve(ws, 0); -+ u = WS_ReserveAll(ws); - if (u == 0) { - WS_Release(ws, 0); - WS_MarkOverflow(ws); ---- varnish-6.2.1.orig/bin/varnishd/cache/cache_vrt_re.c -+++ varnish-6.2.1/bin/varnishd/cache/cache_vrt_re.c -@@ -127,7 +127,7 @@ VRT_regsub(VRT_CTX, int all, const char - return (str); - } - -- u = WS_Reserve(ctx->ws, 0); -+ u = WS_ReserveAll(ctx->ws); - res_e = res_b = b0 = ctx->ws->f; - res_e += u; - ---- varnish-6.2.1.orig/bin/varnishd/cache/cache_ws.c -+++ varnish-6.2.1/bin/varnishd/cache/cache_ws.c -@@ -202,7 +202,7 @@ WS_Printf(struct ws *ws, const char *fmt - va_list ap; - char *p; - -- u = WS_Reserve(ws, 0); -+ u = WS_ReserveAll(ws); - p = ws->f; - va_start(ap, fmt); - v = vsnprintf(p, u, fmt, ap); -@@ -227,6 +227,30 @@ WS_Snapshot(struct ws *ws) - return (ws->f == ws->s ? 0 : (uintptr_t)ws->f); - } - -+/* -+ * WS_Release() must be called in all cases -+ */ -+unsigned -+WS_ReserveAll(struct ws *ws) -+{ -+ unsigned b; -+ -+ assert(ws->r == NULL); -+ -+ ws->r = ws->e; -+ b = pdiff(ws->f, ws->r); -+ -+ WS_Assert(ws); -+ DSL(DBG_WORKSPACE, 0, "WS_ReserveAll(%p) = %u", ws, b); -+ -+ return (b); -+} -+ -+/* -+ * bytes == 0 argument is deprecated - use WS_ReserveAll -+ * -+ * XXX rename to WS_ReserveSize and macro-wrap WS_Reserve to emit #warn ? -+ */ - unsigned - WS_Reserve(struct ws *ws, unsigned bytes) - { -@@ -253,11 +277,7 @@ WS_Reserve(struct ws *ws, unsigned bytes - unsigned - WS_ReserveLumps(struct ws *ws, size_t sz) - { -- unsigned u; -- -- u = WS_Reserve(ws, 0); -- u /= sz; -- return (u); -+ return (WS_ReserveAll(ws) / sz); - } - - void ---- varnish-6.2.1.orig/bin/varnishd/http2/cache_http2_deliver.c -+++ varnish-6.2.1/bin/varnishd/http2/cache_http2_deliver.c -@@ -225,9 +225,11 @@ h2_build_headers(struct vsb *resp, struc - uint8_t buf[6]; - ssize_t sz, sz1; - -- l = WS_Reserve(req->ws, 0); -- if (l < 10) -+ l = WS_ReserveAll(req->ws); -+ if (l < 10) { -+ WS_Release(req->ws, 0); - return (-1); -+ } - - AN(VSB_new(resp, req->ws->f, l, VSB_FIXEDLEN)); - ---- varnish-6.2.1.orig/bin/varnishd/http2/cache_http2_hpack.c -+++ varnish-6.2.1/bin/varnishd/http2/cache_http2_hpack.c -@@ -175,7 +175,7 @@ h2h_decode_init(const struct h2_sess *h2 - d = h2->decode; - INIT_OBJ(d, H2H_DECODE_MAGIC); - VHD_Init(d->vhd); -- d->out_l = WS_Reserve(h2->new_req->http->ws, 0); -+ d->out_l = WS_ReserveAll(h2->new_req->http->ws); - assert(d->out_l > 0); /* Can't do any work without any buffer - space. Require non-zero size. */ - d->out = h2->new_req->http->ws->f; ---- varnish-6.2.1.orig/lib/libvmod_blob/vmod_blob.c -+++ varnish-6.2.1/lib/libvmod_blob/vmod_blob.c -@@ -339,7 +339,7 @@ vmod_decode(VRT_CTX, VCL_ENUM decs, VCL_ - CHECK_OBJ_NOTNULL(ctx->ws, WS_MAGIC); - - buf = WS_Front(ctx->ws); -- space = WS_Reserve(ctx->ws, 0); -+ space = WS_ReserveAll(ctx->ws); - - if (length <= 0) - length = -1; -@@ -378,7 +378,7 @@ encode(VRT_CTX, enum encoding enc, enum - CHECK_OBJ_NOTNULL(ctx->ws, WS_MAGIC); - snap = WS_Snapshot(ctx->ws); - buf = WS_Front(ctx->ws); -- space = WS_Reserve(ctx->ws, 0); -+ space = WS_ReserveAll(ctx->ws); - - len = func[enc].encode(enc, kase, buf, space, b->blob, b->len); - ---- varnish-6.2.1.orig/lib/libvmod_std/vmod_std.c -+++ varnish-6.2.1/lib/libvmod_std/vmod_std.c -@@ -72,7 +72,7 @@ vmod_updown(VRT_CTX, int up, const char - const char *p; - - CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); -- u = WS_Reserve(ctx->ws, 0); -+ u = WS_ReserveAll(ctx->ws); - e = b = ctx->ws->f; - e += u; - p = s; ---- varnish-6.2.1.orig/lib/libvmod_vtc/vmod_vtc.c -+++ varnish-6.2.1/lib/libvmod_vtc/vmod_vtc.c -@@ -155,7 +155,7 @@ vmod_workspace_alloc(VRT_CTX, VCL_ENUM w - WS_Assert(ws); - - if (size < 0) { -- size += WS_Reserve(ws, 0); -+ size += WS_ReserveAll(ws); - WS_Release(ws, 0); - } - if (size <= 0) { -@@ -182,7 +182,7 @@ vmod_workspace_free(VRT_CTX, VCL_ENUM wh - return(-1); - WS_Assert(ws); - -- u = WS_Reserve(ws, 0); -+ u = WS_ReserveAll(ws); - WS_Release(ws, 0); - return (u); - } diff -Nru varnish-6.2.1/debian/patches/WS_ReserveSize.patch varnish-6.2.1/debian/patches/WS_ReserveSize.patch --- varnish-6.2.1/debian/patches/WS_ReserveSize.patch 2022-05-04 21:16:37.000000000 +0100 +++ varnish-6.2.1/debian/patches/WS_ReserveSize.patch 1970-01-01 01:00:00.000000000 +0100 @@ -1,130 +0,0 @@ -From 534e045e040fc213f72aa38a85806f152e3ef5e0 Mon Sep 17 00:00:00 2001 -From: Nils Goroll -Date: Mon, 8 Apr 2019 16:26:07 +0200 -Subject: [PATCH] Deprecate WS_Reserve() and replace it with WS_ReserveSize() - -WS_ReserveSize() does not leave the workspace reserved when the -reservation fails, so WS_Release() must be called for retval > 0 only. - -Besides the debug string, it is identical to WS_Reserve() except for - - assert(bytes > 0); - -Follow-up varnishcache/varnish-cache#2967 - -Note: The WS_Reserve() function has not been deprecated as that can -potentially create problems for the build process of VMODs. - -(cherry picked from commit 4e33359772a3d751b2ef4b5c4b40259f1bcd6903) ---- - bin/varnishd/cache/cache.h | 3 +++ - bin/varnishd/cache/cache_session.c | 6 +++--- - bin/varnishd/cache/cache_wrk.c | 2 +- - bin/varnishd/cache/cache_ws.c | 31 +++++++++++++++++++++++++++--- - lib/libvmod_proxy/vmod_proxy.c | 2 +- - 5 files changed, 36 insertions(+), 8 deletions(-) - ---- varnish-6.2.1.orig/bin/varnishd/cache/cache.h -+++ varnish-6.2.1/bin/varnishd/cache/cache.h -@@ -764,7 +764,10 @@ void WRK_BgThread(pthread_t *thr, const - /* cache_ws.c */ - - void WS_Init(struct ws *ws, const char *id, void *space, unsigned len); -+ -+/* WS_Reserve(): Use WS_ReserveSize() or WS_ReserveAll() */ - unsigned WS_Reserve(struct ws *ws, unsigned bytes); -+unsigned WS_ReserveSize(struct ws *, unsigned); - unsigned WS_ReserveAll(struct ws *); - unsigned WS_ReserveLumps(struct ws *ws, size_t sz); - void WS_MarkOverflow(struct ws *ws); ---- varnish-6.2.1.orig/bin/varnishd/cache/cache_session.c -+++ varnish-6.2.1/bin/varnishd/cache/cache_session.c -@@ -112,7 +112,7 @@ ses_reserve_attr(struct sess *sp, enum s - assert(a < SA_LAST); - assert(sz >= 0); - AN(dst); -- o = WS_Reserve(sp->ws, sz); -+ o = WS_ReserveSize(sp->ws, sz); - assert(o >= sz); - *dst = sp->ws->f; - o = sp->ws->f - sp->ws->s; -@@ -415,7 +415,7 @@ ses_handle(struct waited *wp, enum wait_ - case WAITER_ACTION: - pp = sp->pool; - CHECK_OBJ_NOTNULL(pp, POOL_MAGIC); -- assert(sizeof *tp <= WS_Reserve(sp->ws, sizeof *tp)); -+ assert(sizeof *tp <= WS_ReserveSize(sp->ws, sizeof *tp)); - tp = (void*)sp->ws->f; - tp->func = xp->unwait; - tp->priv = sp; -@@ -453,7 +453,7 @@ SES_Wait(struct sess *sp, const struct t - /* - * put struct waited on the workspace - */ -- if (WS_Reserve(sp->ws, sizeof(struct waited)) -+ if (WS_ReserveSize(sp->ws, sizeof(struct waited)) - < sizeof(struct waited)) { - SES_Delete(sp, SC_OVERLOAD, NAN); - return; ---- varnish-6.2.1.orig/bin/varnishd/cache/cache_wrk.c -+++ varnish-6.2.1/bin/varnishd/cache/cache_wrk.c -@@ -238,7 +238,7 @@ Pool_Task_Arg(struct worker *wrk, enum t - retval = 0; - } - AZ(wrk2->task.func); -- assert(arg_len <= WS_Reserve(wrk2->aws, arg_len)); -+ assert(arg_len <= WS_ReserveSize(wrk2->aws, arg_len)); - memcpy(wrk2->aws->f, arg, arg_len); - wrk2->task.func = func; - wrk2->task.priv = wrk2->aws->f; ---- varnish-6.2.1.orig/bin/varnishd/cache/cache_ws.c -+++ varnish-6.2.1/bin/varnishd/cache/cache_ws.c -@@ -247,9 +247,34 @@ WS_ReserveAll(struct ws *ws) - } - - /* -- * bytes == 0 argument is deprecated - use WS_ReserveAll -- * -- * XXX rename to WS_ReserveSize and macro-wrap WS_Reserve to emit #warn ? -+ * WS_Release() must be called for retval > 0 only -+ */ -+unsigned -+WS_ReserveSize(struct ws *ws, unsigned bytes) -+{ -+ unsigned b2; -+ -+ WS_Assert(ws); -+ assert(ws->r == NULL); -+ assert(bytes > 0); -+ -+ b2 = PRNDDN(ws->e - ws->f); -+ if (bytes < b2) -+ b2 = PRNDUP(bytes); -+ -+ if (ws->f + b2 > ws->e) { -+ WS_MarkOverflow(ws); -+ return (0); -+ } -+ ws->r = ws->f + b2; -+ DSL(DBG_WORKSPACE, 0, "WS_ReserveSize(%p, %u/%u) = %u", -+ ws, b2, bytes, pdiff(ws->f, ws->r)); -+ WS_Assert(ws); -+ return (pdiff(ws->f, ws->r)); -+} -+ -+/* -+ * XXX remove for 2020-03-15 release - */ - unsigned - WS_Reserve(struct ws *ws, unsigned bytes) ---- varnish-6.2.1.orig/lib/libvmod_proxy/vmod_proxy.c -+++ varnish-6.2.1/lib/libvmod_proxy/vmod_proxy.c -@@ -105,7 +105,7 @@ tlv_string(VRT_CTX, int tlv) - - if (VPX_tlv(ctx->req, tlv, (void **)&dst, &len)) - return (NULL); -- if (!WS_Reserve(ctx->ws, len+1)) -+ if (!WS_ReserveSize(ctx->ws, len+1)) - return (NULL); - d = ctx->ws->f; - memcpy(d, dst, len);