Skip to content

Commit d0d58d9

Browse files
committed
Fix GENEVE- and VXLAN-encapsulated matching.
In my recent commit 1687065 the filter programs for "vxlan [NUM]", "vxlan and vxlan", "geneve [NUM]" and "geneve and geneve" have become substantially shorter. As it turns out, the missing instructions are the outputs of gen_geneve_offsets() and gen_vxlan_offsets(), so filtering of protocols encapsulated in GENEVE and VXLAN is no longer correct. Because libpcap does not have any apply filter tests for the affected syntax, this was not apparent until a tcpdump test failed. The instructions went missing because gen_geneve() and gen_vxlan() need to use these as a block, but instead of making a new block from scratch the functions take the result of gen_true() and modify it to add side effects. After the commit the block with the wanted side effects ended up incorrectly marked as a Boolean constant and susequently gen_and() started to discard it. In gen_cond() take an optional list of side effect instructions and make a Boolean constant block a specific case of a block with a degenerate branch statement. Switch gen_geneve() and gen_vxlan() from gen_true() to gen_uncond() to reduce the violation of layers. Restore the six previously affected tests exactly as they were before.
1 parent 730a8db commit d0d58d9

File tree

2 files changed

+352
-214
lines changed

2 files changed

+352
-214
lines changed

gencode.c

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -657,7 +657,7 @@ static struct slist *gen_load_absoffsetrel(compiler_state_t *, bpf_abs_offset *,
657657
static struct slist *gen_load_a(compiler_state_t *, enum e_offrel, u_int,
658658
u_int);
659659
static struct slist *gen_loadx_iphdrlen(compiler_state_t *);
660-
static struct block *gen_uncond(compiler_state_t *, int);
660+
static struct block *gen_uncond(compiler_state_t *, const u_char, struct slist *);
661661
static inline struct block *gen_true(compiler_state_t *);
662662
static inline struct block *gen_false(compiler_state_t *);
663663
static struct block *gen_ether_linktype(compiler_state_t *, bpf_u_int32);
@@ -2526,29 +2526,40 @@ gen_loadx_iphdrlen(compiler_state_t *cstate)
25262526
return s;
25272527
}
25282528

2529-
2529+
/*
2530+
* Produce an instruction block with the given optional side effect statements
2531+
* and a final branch statement that takes the true branch iff rsense is not
2532+
* zero. Since this function detects Boolean constants for potential later
2533+
* use, the resulting block must not be modified directly afterwards, instead
2534+
* it should be used as an argument to gen_and(), gen_or() and gen_not().
2535+
*/
25302536
static struct block *
2531-
gen_uncond(compiler_state_t *cstate, int rsense)
2537+
gen_uncond(compiler_state_t *cstate, const u_char rsense, struct slist *stmts)
25322538
{
25332539
struct slist *s;
25342540

25352541
s = new_stmt(cstate, BPF_LD|BPF_IMM);
25362542
s->s.k = !rsense;
2543+
if (stmts) {
2544+
sappend(stmts, s);
2545+
s = stmts;
2546+
}
25372547
struct block *ret = gen_jmp_k(cstate, BPF_JEQ, 0, s);
2538-
ret->meaning = rsense ? IS_TRUE : IS_FALSE;
2548+
if (! stmts)
2549+
ret->meaning = rsense ? IS_TRUE : IS_FALSE;
25392550
return ret;
25402551
}
25412552

25422553
static inline struct block *
25432554
gen_true(compiler_state_t *cstate)
25442555
{
2545-
return gen_uncond(cstate, 1);
2556+
return gen_uncond(cstate, 1, NULL);
25462557
}
25472558

25482559
static inline struct block *
25492560
gen_false(compiler_state_t *cstate)
25502561
{
2551-
return gen_uncond(cstate, 0);
2562+
return gen_uncond(cstate, 0, NULL);
25522563
}
25532564

25542565
/*
@@ -9123,9 +9134,7 @@ gen_geneve(compiler_state_t *cstate, bpf_u_int32 vni, int has_vni)
91239134
* it gets executed in the event that the Geneve filter matches. */
91249135
s = gen_geneve_offsets(cstate);
91259136

9126-
b1 = gen_true(cstate);
9127-
sappend(s, b1->stmts);
9128-
b1->stmts = s;
9137+
b1 = gen_uncond(cstate, 1, s);
91299138

91309139
b1 = gen_and(b0, b1);
91319140

@@ -9313,9 +9322,7 @@ gen_vxlan(compiler_state_t *cstate, bpf_u_int32 vni, int has_vni)
93139322
* it gets executed in the event that the VXLAN filter matches. */
93149323
s = gen_vxlan_offsets(cstate);
93159324

9316-
b1 = gen_true(cstate);
9317-
sappend(s, b1->stmts);
9318-
b1->stmts = s;
9325+
b1 = gen_uncond(cstate, 1, s);
93199326

93209327
b1 = gen_and(b0, b1);
93219328

0 commit comments

Comments
 (0)