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
parent 35cadf11
...@@ -199,13 +199,20 @@ VRT_priv_task(VRT_CTX, const void *vmod_id) ...@@ -199,13 +199,20 @@ VRT_priv_task(VRT_CTX, const void *vmod_id)
(uintptr_t)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 { \ #define VRT_PRIV_TOP_PREP(ctx, req, sp, top) do { \
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); \ CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); \
req = (ctx)->req; \ req = (ctx)->req; \
if (req == NULL) { \ if (req == NULL) { \
WRONG("PRIV_TOP is only accessible " \ VRT_fail(ctx, "PRIV_TOP is only accessible " \
"in client VCL context"); \ "in client VCL context"); \
NEEDLESS(return (NULL)); \ return (NULL); \
} \ } \
CHECK_OBJ(req, REQ_MAGIC); \ CHECK_OBJ(req, REQ_MAGIC); \
sp = (ctx)->sp; \ sp = (ctx)->sp; \
......
...@@ -64,6 +64,8 @@ varnish v1 -cliok "param.set debug +syncvsl" -vcl+backend { ...@@ -64,6 +64,8 @@ varnish v1 -cliok "param.set debug +syncvsl" -vcl+backend {
} }
sub vcl_recv { 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); set req.http.x0 = debug.test_priv_top(req.url + req.esi_level);
if (req.url == "/foo1") { if (req.url == "/foo1") {
o.test_priv_top(req.url + req.esi_level); o.test_priv_top(req.url + req.esi_level);
...@@ -79,9 +81,28 @@ varnish v1 -cliok "param.set debug +syncvsl" -vcl+backend { ...@@ -79,9 +81,28 @@ varnish v1 -cliok "param.set debug +syncvsl" -vcl+backend {
set req.http.o2 = o2.test_priv_top(""); 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 { sub vcl_backend_response {
set beresp.do_esi = true; set beresp.do_esi = true;
} }
sub vcl_deliver { sub vcl_deliver {
...@@ -101,3 +122,18 @@ client c1 { ...@@ -101,3 +122,18 @@ client c1 {
} -run } -run
varnish v1 -expect client_req == 2 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
...@@ -496,11 +496,11 @@ The VCL compiler supports the following private pointers: ...@@ -496,11 +496,11 @@ The VCL compiler supports the following private pointers:
* ``PRIV_TOP`` "per top-request" private pointers live for the * ``PRIV_TOP`` "per top-request" private pointers live for the
duration of one request and all its ESI-includes. They are only 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 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 These private pointers live only for the duration of their top
level request 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 * ``PRIV_VCL`` "per vcl" private pointers are useful for such global
state that applies to all calls in this VCL, for instance flags that state that applies to all calls in this VCL, for instance flags that
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment