[master] d0db4c975 Avoid panic with PRIV_TOP arguments
Nils Goroll
nils.goroll at uplex.de
Mon Jan 18 15:40:07 UTC 2021
commit d0db4c975f281c8d096b48b6fd6014cdfc606ab5
Author: Nils Goroll <nils.goroll at uplex.de>
Date: Mon Jan 18 16:34:48 2021 +0100
Avoid panic with PRIV_TOP arguments
Instead of triggering a WRONG() panic, we now fail the VCL when any vmod
function with PRIV_TOP argument(s) is present in a sub called from
outside client context.
Note that the VCL failure happens not when the vmod function with the
PRIV_TOP argument is called, but rather when the containing SUB is
called. This is because we prepare PRIV_TOP arguments in the function
preamble.
Fixes #3498
diff --git a/bin/varnishd/cache/cache_vrt_priv.c b/bin/varnishd/cache/cache_vrt_priv.c
index d6884c228..fcdece918 100644
--- a/bin/varnishd/cache/cache_vrt_priv.c
+++ b/bin/varnishd/cache/cache_vrt_priv.c
@@ -199,13 +199,20 @@ VRT_priv_task(VRT_CTX, const void *vmod_id)
(uintptr_t)vmod_id));
}
+/*
+ * XXX #3498 on VRT_fail(): Would be better to move the PRIV_TOP check to VCC
+ *
+ * This will fail in the preamble of any VCL SUB containing a call to a vmod
+ * function with a PRIV_TOP argument, which might not exactly be pola
+ */
+
#define VRT_PRIV_TOP_PREP(ctx, req, sp, top) do { \
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); \
req = (ctx)->req; \
if (req == NULL) { \
- WRONG("PRIV_TOP is only accessible " \
+ VRT_fail(ctx, "PRIV_TOP is only accessible " \
"in client VCL context"); \
- NEEDLESS(return (NULL)); \
+ return (NULL); \
} \
CHECK_OBJ(req, REQ_MAGIC); \
sp = (ctx)->sp; \
diff --git a/bin/varnishtest/tests/v00043.vtc b/bin/varnishtest/tests/v00043.vtc
index 828b06668..95b85770b 100644
--- a/bin/varnishtest/tests/v00043.vtc
+++ b/bin/varnishtest/tests/v00043.vtc
@@ -64,6 +64,8 @@ varnish v1 -cliok "param.set debug +syncvsl" -vcl+backend {
}
sub vcl_recv {
+ set req.http.x0 = debug.test_priv_top(req.url + req.esi_level);
+ # coverage
set req.http.x0 = debug.test_priv_top(req.url + req.esi_level);
if (req.url == "/foo1") {
o.test_priv_top(req.url + req.esi_level);
@@ -79,9 +81,28 @@ varnish v1 -cliok "param.set debug +syncvsl" -vcl+backend {
set req.http.o2 = o2.test_priv_top("");
}
+ # XXX because PRIV_TOP arguments get initialized in the
+ # function preamble, the mere presence of a vmod call with a
+ # PRIV_TOP argument in a SUB will trigger the failure if that
+ # sub is called at all.
+ #
+ # So to test #3498, we need to fence test_priv_top into its
+ # own sub
+ sub callingmewill503 {
+ debug.test_priv_top("only works on client side");
+ }
+
+ sub vcl_backend_fetch {
+ if (bereq.url == "/fail") {
+ call callingmewill503;
+ }
+ if (bereq.url == "/failo") {
+ o2.test_priv_top("only works on client side");
+ }
+ }
+
sub vcl_backend_response {
set beresp.do_esi = true;
-
}
sub vcl_deliver {
@@ -101,3 +122,18 @@ client c1 {
} -run
varnish v1 -expect client_req == 2
+
+client c1 {
+ txreq -url /fail
+ rxresp
+ expect resp.status == 503
+} -start
+
+client c2 {
+ txreq -url /failo
+ rxresp
+ expect resp.status == 503
+} -start
+
+client c1 -wait
+client c2 -wait
diff --git a/doc/sphinx/reference/vmod.rst b/doc/sphinx/reference/vmod.rst
index 48e99a28a..9c3e08317 100644
--- a/doc/sphinx/reference/vmod.rst
+++ b/doc/sphinx/reference/vmod.rst
@@ -496,11 +496,11 @@ The VCL compiler supports the following private pointers:
* ``PRIV_TOP`` "per top-request" private pointers live for the
duration of one request and all its ESI-includes. They are only
defined for the client side. When used from backend VCL subs, a NULL
- pointer will be passed.
+ pointer will potentially be passed and a VCL failure triggered.
These private pointers live only for the duration of their top
level request
- .. XXX BROKEN https://github.com/varnishcache/varnish-cache/issues/3498
+ .. PRIV_TOP see #3498
* ``PRIV_VCL`` "per vcl" private pointers are useful for such global
state that applies to all calls in this VCL, for instance flags that
More information about the varnish-commit
mailing list