Skip to content

Commit af32ae1

Browse files
committed
cache_ban: Forward compatibility for the binary ban representation
Our ban expressions (like "obj.age > 20s") are represented in a binary format (see top of cache_ban.h) which allows for forward compatibility, yet at the respective places we currently just trigger an assertion failure if we hit an unknown argument or operator code. This commit brings forward compatibility such that, when bans are loaded from persistent storage into older code which does not yet support newly introduced binary codes, we no longer panic. Ban evaluation: For bans, evaluating an expression to "true" is always "correct" in that the cache would not deliver banned content. It might cause objects to be removed from cache, but that is at least not incorrect. So the fail safe action this code takes is to always evaluate unknown ban expressions to true. CLI ban.list: For unsupported ban expressions, the unknown argument or operator codes are formatted as "(0x%02x)" with the string "UNSUPPORTED" as the user-specified argument. For example: 1740567193.765849 0 - (0x20) > UNSUPPORTED && obj.http.foo ~ 377.266 (note that here the operator > is supported and printed as such, and the ban contains one unsupported and one supported expression) Logging: For each unsupported argument or operator code, an Error VSL is output exactly once to vxid 0. Statistics: Whenever unsupported argument or operator codes are encountered, the newly added counters MAIN.bans_inval_arg1 and MAIN.bans_inval_oper are incremented, respectively. Fixes #4288
1 parent 276be1a commit af32ae1

File tree

3 files changed

+93
-4
lines changed

3 files changed

+93
-4
lines changed

bin/varnishd/cache/cache_ban.c

Lines changed: 73 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
#include "cache_ban.h"
4040
#include "cache_objhead.h"
4141

42+
#include "vbm.h"
4243
#include "vcli_serve.h"
4344
#include "vend.h"
4445
#include "vmb.h"
@@ -66,6 +67,10 @@ struct ban_test {
6667
const void *arg2_spec;
6768
};
6869

70+
// mark invalid arg1/oper so we report only once
71+
static struct vbitmap *inval_oper_logged;
72+
static struct vbitmap *inval_arg1_logged;
73+
6974
static const char * const arg_name[BAN_ARGARRSZ + 1] = {
7075
#define PVAR(a, b, c) [BAN_ARGIDX(c)] = (a),
7176
#include "tbl/ban_vars.h"
@@ -215,6 +220,8 @@ ban_get_lump(const uint8_t **bs)
215220

216221
/*--------------------------------------------------------------------
217222
* Pick a test apart from a spec string
223+
*
224+
* NOTICE: This code must be invariant to unknown arg1 and oper
218225
*/
219226

220227
static void
@@ -486,6 +493,30 @@ BAN_Time(const struct ban *b)
486493
* Evaluate ban-spec
487494
*/
488495

496+
static void
497+
ban_inval_arg1(uint8_t arg1)
498+
{
499+
Lck_Lock(&ban_mtx);
500+
VSC_C_main->bans_inval_arg1++;
501+
Lck_Unlock(&ban_mtx);
502+
if (vbit_test(inval_arg1_logged, arg1))
503+
return;
504+
vbit_set(inval_arg1_logged, arg1);
505+
VSL(SLT_Error, NO_VXID, "Unsupported ban argument 0x%02x", arg1);
506+
}
507+
508+
static void
509+
ban_inval_oper(uint8_t oper)
510+
{
511+
Lck_Lock(&ban_mtx);
512+
VSC_C_main->bans_inval_oper++;
513+
Lck_Unlock(&ban_mtx);
514+
if (vbit_test(inval_oper_logged, oper))
515+
return;
516+
vbit_set(inval_oper_logged, oper);
517+
VSL(SLT_Error, NO_VXID, "Unsupported ban operator 0x%02x", oper);
518+
}
519+
489520
int
490521
ban_evaluate(struct worker *wrk, const uint8_t *bsarg, struct objcore *oc,
491522
const struct http *reqhttp, unsigned *tests)
@@ -547,7 +578,8 @@ ban_evaluate(struct worker *wrk, const uint8_t *bsarg, struct objcore *oc,
547578
darg2 = bt.arg2_double;
548579
break;
549580
default:
550-
WRONG("Wrong BAN_ARG code");
581+
ban_inval_arg1(bt.arg1);
582+
continue;
551583
}
552584

553585
switch (bt.oper) {
@@ -608,7 +640,7 @@ ban_evaluate(struct worker *wrk, const uint8_t *bsarg, struct objcore *oc,
608640
return (0);
609641
break;
610642
default:
611-
WRONG("Wrong BAN_OPER code");
643+
ban_inval_oper(bt.oper);
612644
}
613645
}
614646
return (1);
@@ -794,6 +826,27 @@ ccf_ban(struct cli *cli, const char * const *av, void *priv)
794826
bprintf((buf), "%jus", dec); \
795827
} while (0)
796828

829+
static void
830+
ban_render_inval(struct cli *cli, uint8_t arg1, uint8_t oper)
831+
{
832+
if (! IS_BAN_ARG(arg1))
833+
ban_inval_arg1(arg1);
834+
if (! IS_BAN_OPER(oper))
835+
ban_inval_oper(oper);
836+
837+
if (IS_BAN_ARG(arg1))
838+
VCLI_Out(cli, "%s", arg_name[BAN_ARGIDX(arg1)]);
839+
else
840+
VCLI_Out(cli, "(0x%02x)", arg1);
841+
842+
if (IS_BAN_OPER(oper))
843+
VCLI_Out(cli, " %s ", ban_oper[BAN_OPERIDX(oper)]);
844+
else
845+
VCLI_Out(cli, " (0x%02x) ", oper);
846+
847+
VCLI_Out(cli, "UNSUPPORTED");
848+
}
849+
797850
static void
798851
ban_render(struct cli *cli, const uint8_t *bs, int quote)
799852
{
@@ -805,6 +858,13 @@ ban_render(struct cli *cli, const uint8_t *bs, int quote)
805858
bs += BANS_HEAD_LEN;
806859
while (bs < be) {
807860
ban_iter(&bs, &bt);
861+
if (UNLIKELY(! IS_BAN_ARG(bt.arg1) || ! IS_BAN_OPER(bt.oper))) {
862+
ban_render_inval(cli, bt.arg1, bt.oper);
863+
if (bs < be)
864+
VCLI_Out(cli, " && ");
865+
continue;
866+
}
867+
808868
ASSERT_BAN_ARG(bt.arg1);
809869
ASSERT_BAN_OPER(bt.oper);
810870

@@ -985,6 +1045,12 @@ BAN_Init(void)
9851045
{
9861046
struct ban_proto *bp;
9871047

1048+
// uses malloc where static could be used, but only once
1049+
inval_oper_logged = vbit_new(256);
1050+
inval_arg1_logged = vbit_new(256);
1051+
AN(inval_oper_logged);
1052+
AN(inval_arg1_logged);
1053+
9881054
BAN_Build_Init();
9891055
Lck_New(&ban_mtx, lck_ban);
9901056
CLI_AddFuncs(ban_cmds);
@@ -1028,4 +1094,9 @@ BAN_Shutdown(void)
10281094
Lck_Unlock(&ban_mtx);
10291095

10301096
BAN_Build_Fini();
1097+
1098+
vbit_destroy(inval_oper_logged);
1099+
vbit_destroy(inval_arg1_logged);
1100+
inval_oper_logged = NULL;
1101+
inval_arg1_logged = NULL;
10311102
}

bin/varnishd/cache/cache_ban.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,8 @@
8686

8787
#define BAN_OPERIDX(x) ((x) - BANS_OPER_OFF_)
8888
#define BAN_OPERARRSZ (BANS_OPER_LIM_ - BANS_OPER_OFF_)
89-
#define ASSERT_BAN_OPER(x) assert((x) >= BANS_OPER_OFF_ && (x) < BANS_OPER_LIM_)
89+
#define IS_BAN_OPER(x) ((x) >= BANS_OPER_OFF_ && (x) < BANS_OPER_LIM_)
90+
#define ASSERT_BAN_OPER(x) assert(IS_BAN_OPER(x))
9091

9192
#define BANS_ARG_URL 0x18
9293
#define BANS_ARG_OFF_ BANS_ARG_URL
@@ -101,7 +102,8 @@
101102

102103
#define BAN_ARGIDX(x) ((x) - BANS_ARG_OFF_)
103104
#define BAN_ARGARRSZ (BANS_ARG_LIM - BANS_ARG_OFF_)
104-
#define ASSERT_BAN_ARG(x) assert((x) >= BANS_ARG_OFF_ && (x) < BANS_ARG_LIM)
105+
#define IS_BAN_ARG(x) ((x) >= BANS_ARG_OFF_ && (x) < BANS_ARG_LIM)
106+
#define ASSERT_BAN_ARG(x) assert(IS_BAN_ARG(x))
105107

106108
// has an arg1_spec (BANS_FLAG_HTTP at build time)
107109
#define BANS_HAS_ARG1_SPEC(arg) \

lib/libvsc/VSC_main.vsc

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -925,6 +925,22 @@
925925
Number of extra bytes accumulated through dropped and completed
926926
bans in the persistent ban lists.
927927

928+
.. varnish_vsc:: bans_inval_arg1
929+
:group: ban_mtx
930+
:oneliner: Unsupported ban argument encountered
931+
932+
Number of times an unsupported ban argument has been encountered.
933+
934+
Unsupported ban arguments always evaluate true.
935+
936+
.. varnish_vsc:: bans_inval_oper
937+
:group: ban_mtx
938+
:oneliner: Unsupported ban operator encountered
939+
940+
Number of times an unsupported ban operator has been encountered.
941+
942+
Unsupported ban operators always evaluate true.
943+
928944
.. varnish_vsc:: n_purges
929945
:oneliner: Number of purge operations executed
930946

0 commit comments

Comments
 (0)