nftables-1.0.4-8.el9

* Thu Feb 09 2023 Phil Sutter <psutter@redhat.com> [1.0.4-8.el9]
- monitor: Sanitize startup race condition (Phil Sutter) [2130721]
- evaluate: set eval ctx for add/update statements with integer constants (Phil Sutter) [2094894]
- src: allow anon set concatenation with ether and vlan (Phil Sutter) [2094887]
- evaluate: search stacked header list for matching payload dep (Phil Sutter) [2094887]
- netlink_delinearize: also postprocess OP_AND in set element context (Phil Sutter) [2094887]
- tests: add a test case for ether and vlan listing (Phil Sutter) [2094887]
- debug: dump the l2 protocol stack (Phil Sutter) [2094887]
- proto: track full stack of seen l2 protocols, not just cumulative offset (Phil Sutter) [2094887]
- netlink_delinearize: postprocess binary ands in concatenations (Phil Sutter) [2094887]
- netlink_delinearize: allow postprocessing on concatenated elements (Phil Sutter) [2094887]
- intervals: check for EXPR_F_REMOVE in case of element mismatch (Phil Sutter) [2115627]
- intervals: fix crash when trying to remove element in empty set (Phil Sutter) [2115627]
- scanner: don't pop active flex scanner scope (Phil Sutter) [2113874]
- parser: add missing synproxy scope closure (Phil Sutter) [2113874]
- tests/py: Add a test for failing ipsec after counter (Phil Sutter) [2113874]
- doc: Document limitations of ipsec expression with xfrm_interface (Phil Sutter) [1806431]
Resolves: rhbz#1806431, rhbz#2094887, rhbz#2094894, rhbz#2113874, rhbz#2115627, rhbz#2130721, rhbz#2094890
This commit is contained in:
Phil Sutter 2023-02-09 15:47:30 +01:00
parent b2d6b2fb35
commit 552075b562
19 changed files with 1963 additions and 8 deletions

View File

@ -0,0 +1,44 @@
From f999616d8248bf51831c4eef4ea5a2fd57805857 Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Thu, 9 Feb 2023 10:15:02 +0100
Subject: [PATCH] doc: Document limitations of ipsec expression with
xfrm_interface
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1806431
Upstream Status: nftables commit 446e76dbde713
commit 446e76dbde713327358f17a8af6ce86b8541c836
Author: Phil Sutter <phil@nwl.cc>
Date: Thu Jun 23 17:49:20 2022 +0200
doc: Document limitations of ipsec expression with xfrm_interface
Point at a possible solution to match IPsec info of locally generated
traffic routed to an xfrm-type interface.
Signed-off-by: Phil Sutter <phil@nwl.cc>
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Phil Sutter <psutter@redhat.com>
---
doc/primary-expression.txt | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/doc/primary-expression.txt b/doc/primary-expression.txt
index f97778b..4d6b087 100644
--- a/doc/primary-expression.txt
+++ b/doc/primary-expression.txt
@@ -428,6 +428,10 @@ Destination address of the tunnel|
ipv4_addr/ipv6_addr
|=================================
+*Note:* When using xfrm_interface, this expression is not useable in output
+hook as the plain packet does not traverse it with IPsec info attached - use a
+chain in postrouting hook instead.
+
NUMGEN EXPRESSION
~~~~~~~~~~~~~~~~~
--
2.39.1

View File

@ -0,0 +1,86 @@
From 39c0d8ee8c8b0a667fc1c20336b3d248d28759f3 Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Thu, 9 Feb 2023 10:18:10 +0100
Subject: [PATCH] tests/py: Add a test for failing ipsec after counter
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2113874
Upstream Status: nftables commit ed2426bccd3ea
commit ed2426bccd3ea954adc8a010bf1736e8ed6a81b9
Author: Phil Sutter <phil@nwl.cc>
Date: Thu Jun 23 16:28:42 2022 +0200
tests/py: Add a test for failing ipsec after counter
This is a bug in parser/scanner due to scoping:
| Error: syntax error, unexpected string, expecting saddr or daddr
| add rule ip ipsec-ip4 ipsec-forw counter ipsec out ip daddr 192.168.1.2
| ^^^^^
Signed-off-by: Phil Sutter <phil@nwl.cc>
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Phil Sutter <psutter@redhat.com>
---
tests/py/inet/ipsec.t | 2 ++
tests/py/inet/ipsec.t.json | 21 +++++++++++++++++++++
tests/py/inet/ipsec.t.payload | 6 ++++++
3 files changed, 29 insertions(+)
diff --git a/tests/py/inet/ipsec.t b/tests/py/inet/ipsec.t
index e924e9b..b18df39 100644
--- a/tests/py/inet/ipsec.t
+++ b/tests/py/inet/ipsec.t
@@ -19,3 +19,5 @@ ipsec in ip6 daddr dead::beef;ok
ipsec out ip6 saddr dead::feed;ok
ipsec in spnum 256 reqid 1;fail
+
+counter ipsec out ip daddr 192.168.1.2;ok
diff --git a/tests/py/inet/ipsec.t.json b/tests/py/inet/ipsec.t.json
index d7d3a03..18a64f3 100644
--- a/tests/py/inet/ipsec.t.json
+++ b/tests/py/inet/ipsec.t.json
@@ -134,3 +134,24 @@
}
}
]
+
+# counter ipsec out ip daddr 192.168.1.2
+[
+ {
+ "counter": null
+ },
+ {
+ "match": {
+ "left": {
+ "ipsec": {
+ "dir": "out",
+ "family": "ip",
+ "key": "daddr",
+ "spnum": 0
+ }
+ },
+ "op": "==",
+ "right": "192.168.1.2"
+ }
+ }
+]
diff --git a/tests/py/inet/ipsec.t.payload b/tests/py/inet/ipsec.t.payload
index c46a226..9648255 100644
--- a/tests/py/inet/ipsec.t.payload
+++ b/tests/py/inet/ipsec.t.payload
@@ -37,3 +37,9 @@ ip ipsec-ip4 ipsec-forw
[ xfrm load out 0 saddr6 => reg 1 ]
[ cmp eq reg 1 0x0000adde 0x00000000 0x00000000 0xedfe0000 ]
+# counter ipsec out ip daddr 192.168.1.2
+ip ipsec-ip4 ipsec-forw
+ [ counter pkts 0 bytes 0 ]
+ [ xfrm load out 0 daddr4 => reg 1 ]
+ [ cmp eq reg 1 0x0201a8c0 ]
+
--
2.39.1

View File

@ -0,0 +1,38 @@
From 8d7afedbb71217b8b7dbdec5240b822fb8c5b9d3 Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Thu, 9 Feb 2023 10:18:10 +0100
Subject: [PATCH] parser: add missing synproxy scope closure
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2113874
Upstream Status: nftables commit 994bf5004b365
commit 994bf5004b365904029f0fe8c2de587178583712
Author: Florian Westphal <fw@strlen.de>
Date: Thu Jun 23 18:28:14 2022 +0200
parser: add missing synproxy scope closure
Fixes: 232f2c3287fc ("scanner: synproxy: Move to own scope")
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Phil Sutter <psutter@redhat.com>
---
src/parser_bison.y | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/parser_bison.y b/src/parser_bison.y
index ca5c488..b548d5b 100644
--- a/src/parser_bison.y
+++ b/src/parser_bison.y
@@ -2016,7 +2016,7 @@ map_block_obj_type : COUNTER close_scope_counter { $$ = NFT_OBJECT_COUNTER; }
| QUOTA close_scope_quota { $$ = NFT_OBJECT_QUOTA; }
| LIMIT close_scope_limit { $$ = NFT_OBJECT_LIMIT; }
| SECMARK close_scope_secmark { $$ = NFT_OBJECT_SECMARK; }
- | SYNPROXY { $$ = NFT_OBJECT_SYNPROXY; }
+ | SYNPROXY close_scope_synproxy { $$ = NFT_OBJECT_SYNPROXY; }
;
map_block : /* empty */ { $$ = $<set>-1; }
--
2.39.1

View File

@ -0,0 +1,144 @@
From ec8483bd878fa1c8a7b53b243e5d7017634df65e Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Thu, 9 Feb 2023 10:18:10 +0100
Subject: [PATCH] scanner: don't pop active flex scanner scope
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2113874
Upstream Status: nftables commit 8623772af0610
commit 8623772af06103ed4ccca3d07e55afbf3d952d6d
Author: Florian Westphal <fw@strlen.de>
Date: Thu Jun 23 19:56:19 2022 +0200
scanner: don't pop active flex scanner scope
Currently we can pop a flex scope that is still active, i.e. the
scanner_pop_start_cond() for the scope has not been done.
Example:
counter ipsec out ip daddr 192.168.1.2 counter name "ipsec_out"
Here, parser fails because 'daddr' is parsed as STRING, not as DADDR token.
Bug is as follows:
COUNTER changes scope to COUNTER. (COUNTER).
Next, IPSEC scope gets pushed, stack is: COUNTER, IPSEC.
Then, the 'COUNTER' scope close happens. Because active scope has changed,
we cannot pop (we would pop the 'ipsec' scope in flex).
The pop operation gets delayed accordingly.
Next, IP gets pushed, stack is: COUNTER, IPSEC, IP, plus the information
that one scope closure/pop was delayed.
Then, the IP scope is closed. Because a pop operation was delayed, we pop again,
which brings us back to COUNTER state.
This is bogus: The pop operation CANNOT be done yet, because the ipsec scope
is still open, but the existing code lacks the information to detect this.
After popping the IP scope, we must remain in IPSEC scope until bison
parser calls scanner_pop_start_cond(, IPSEC).
This adds a counter per flex scope so that we can detect this case.
In above case, after the IP scope gets closed, the "new" (previous)
scope (IPSEC) will be treated as active and its close is attempted again
on the next call to scanner_pop_start_cond().
After this patch, transition in above rule is:
push counter (COUNTER)
push IPSEC (COUNTER, IPSEC)
pop COUNTER (delayed: COUNTER, IPSEC, pending-pop for COUNTER),
push IP (COUNTER, IPSEC, IP, pending-pop for COUNTER)
pop IP (COUNTER, IPSEC, pending-pop for COUNTER)
parse DADDR (we're in IPSEC scope, its valid token)
pop IPSEC (pops all remaining scopes).
We could also resurrect the commit:
"scanner: flags: move to own scope", the test case passes with the
new scope closure logic.
Fixes: bff106c5b277 ("scanner: add support for scope nesting")
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Phil Sutter <psutter@redhat.com>
---
include/parser.h | 3 +++
src/scanner.l | 11 +++++++++++
2 files changed, 14 insertions(+)
diff --git a/include/parser.h b/include/parser.h
index f32154c..5e5ad28 100644
--- a/include/parser.h
+++ b/include/parser.h
@@ -26,6 +26,7 @@ struct parser_state {
unsigned int flex_state_pop;
unsigned int startcond_type;
struct list_head *cmds;
+ unsigned int *startcond_active;
};
enum startcond_type {
@@ -82,6 +83,8 @@ enum startcond_type {
PARSER_SC_STMT_REJECT,
PARSER_SC_STMT_SYNPROXY,
PARSER_SC_STMT_TPROXY,
+
+ __SC_MAX
};
struct mnl_socket;
diff --git a/src/scanner.l b/src/scanner.l
index 2154281..ed7256b 100644
--- a/src/scanner.l
+++ b/src/scanner.l
@@ -1148,6 +1148,8 @@ void *scanner_init(struct parser_state *state)
yylex_init_extra(state, &scanner);
yyset_out(NULL, scanner);
+ state->startcond_active = xzalloc_array(__SC_MAX,
+ sizeof(*state->startcond_active));
return scanner;
}
@@ -1177,6 +1179,8 @@ void scanner_destroy(struct nft_ctx *nft)
struct parser_state *state = yyget_extra(nft->scanner);
input_descriptor_list_destroy(state);
+ xfree(state->startcond_active);
+
yylex_destroy(nft->scanner);
}
@@ -1185,6 +1189,7 @@ static void scanner_push_start_cond(void *scanner, enum startcond_type type)
struct parser_state *state = yyget_extra(scanner);
state->startcond_type = type;
+ state->startcond_active[type]++;
yy_push_state((int)type, scanner);
}
@@ -1193,6 +1198,8 @@ void scanner_pop_start_cond(void *scanner, enum startcond_type t)
{
struct parser_state *state = yyget_extra(scanner);
+ state->startcond_active[t]--;
+
if (state->startcond_type != t) {
state->flex_state_pop++;
return; /* Can't pop just yet! */
@@ -1202,6 +1209,10 @@ void scanner_pop_start_cond(void *scanner, enum startcond_type t)
state->flex_state_pop--;
state->startcond_type = yy_top_state(scanner);
yy_pop_state(scanner);
+
+ t = state->startcond_type;
+ if (state->startcond_active[t])
+ return;
}
state->startcond_type = yy_top_state(scanner);
--
2.39.1

View File

@ -0,0 +1,67 @@
From 70732ebb3cd1b847e72dce5ae8fe3c69580bd778 Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Thu, 9 Feb 2023 10:25:59 +0100
Subject: [PATCH] intervals: fix crash when trying to remove element in empty
set
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2115627
Upstream Status: nftables commit 5357cb7b5cb93
commit 5357cb7b5cb93fc9b20d4d95b093d6b9f86b7727
Author: Pablo Neira Ayuso <pablo@netfilter.org>
Date: Thu Jun 23 14:20:17 2022 +0200
intervals: fix crash when trying to remove element in empty set
The set deletion routine expects an initialized set, otherwise it crashes.
Fixes: 3e8d934e4f72 ("intervals: support to partial deletion with automerge")
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Signed-off-by: Phil Sutter <psutter@redhat.com>
---
src/intervals.c | 6 +++++-
tests/shell/testcases/sets/errors_0 | 14 ++++++++++++++
2 files changed, 19 insertions(+), 1 deletion(-)
create mode 100755 tests/shell/testcases/sets/errors_0
diff --git a/src/intervals.c b/src/intervals.c
index dcc06d1..c21b3ee 100644
--- a/src/intervals.c
+++ b/src/intervals.c
@@ -475,7 +475,11 @@ int set_delete(struct list_head *msgs, struct cmd *cmd, struct set *set,
if (set->automerge)
automerge_delete(msgs, set, init, debug_mask);
- set_to_range(existing_set->init);
+ if (existing_set->init) {
+ set_to_range(existing_set->init);
+ } else {
+ existing_set->init = set_expr_alloc(&internal_location, set);
+ }
list_splice_init(&init->expressions, &del_list);
diff --git a/tests/shell/testcases/sets/errors_0 b/tests/shell/testcases/sets/errors_0
new file mode 100755
index 0000000..2960b69
--- /dev/null
+++ b/tests/shell/testcases/sets/errors_0
@@ -0,0 +1,14 @@
+#!/bin/bash
+
+set -e
+
+RULESET="table ip x {
+ set y {
+ type ipv4_addr
+ flags interval
+ }
+}
+
+delete element ip x y { 2.3.4.5 }"
+
+$NFT -f - <<< $RULESET || exit 0
--
2.39.1

View File

@ -0,0 +1,80 @@
From 8099eb08541428efe92c4a1a4cbaf3530fd125e7 Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Thu, 9 Feb 2023 10:25:59 +0100
Subject: [PATCH] intervals: check for EXPR_F_REMOVE in case of element
mismatch
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2115627
Upstream Status: nftables commit 6d1ee9267e7e5
commit 6d1ee9267e7e5e429a84d7bb8a8644f9eebddb22
Author: Pablo Neira Ayuso <pablo@netfilter.org>
Date: Thu Jun 23 18:41:21 2022 +0200
intervals: check for EXPR_F_REMOVE in case of element mismatch
If auto-merge is disable and element to be deleted finds no exact
matching, then bail out.
Fixes: 3e8d934e4f72 ("intervals: support to partial deletion with automerge")
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Signed-off-by: Phil Sutter <psutter@redhat.com>
---
src/intervals.c | 4 ++++
tests/shell/testcases/sets/errors_0 | 20 ++++++++++++++++++--
2 files changed, 22 insertions(+), 2 deletions(-)
diff --git a/src/intervals.c b/src/intervals.c
index c21b3ee..13009ca 100644
--- a/src/intervals.c
+++ b/src/intervals.c
@@ -421,6 +421,10 @@ static int setelem_delete(struct list_head *msgs, struct set *set,
expr_error(msgs, i, "element does not exist");
err = -1;
goto err;
+ } else if (i->flags & EXPR_F_REMOVE) {
+ expr_error(msgs, i, "element does not exist");
+ err = -1;
+ goto err;
}
prev = NULL;
}
diff --git a/tests/shell/testcases/sets/errors_0 b/tests/shell/testcases/sets/errors_0
index 2960b69..a676ac7 100755
--- a/tests/shell/testcases/sets/errors_0
+++ b/tests/shell/testcases/sets/errors_0
@@ -1,7 +1,5 @@
#!/bin/bash
-set -e
-
RULESET="table ip x {
set y {
type ipv4_addr
@@ -11,4 +9,22 @@ RULESET="table ip x {
delete element ip x y { 2.3.4.5 }"
+$NFT -f - <<< $RULESET
+if [ $? -eq 0 ]
+then
+ exit 1
+fi
+
+RULESET="table ip x {
+ set y {
+ type ipv4_addr
+ flags interval
+ }
+}
+
+add element x y { 1.1.1.1/24 }
+delete element x y { 1.1.1.1/24 }
+add element x y { 1.1.1.1/24 }
+delete element x y { 2.2.2.2/24 }"
+
$NFT -f - <<< $RULESET || exit 0
--
2.39.1

View File

@ -0,0 +1,76 @@
From cff78b77d409445b0490e67bf9329e69e0bbc872 Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Thu, 9 Feb 2023 10:27:57 +0100
Subject: [PATCH] netlink_delinearize: allow postprocessing on concatenated
elements
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2094887
Upstream Status: nftables commit 0542a431e8dcc
commit 0542a431e8dccfa86fa5b1744f536e61a0b204f3
Author: Florian Westphal <fw@strlen.de>
Date: Tue Jun 14 21:57:58 2022 +0200
netlink_delinearize: allow postprocessing on concatenated elements
Currently there is no case where the individual expressions inside a
mapped concatenation need to be munged.
However, to support proper delinearization for an input like
'rule netdev nt nc set update ether saddr . vlan id timeout 5s @macset'
we need to allow this.
Right now, this gets listed as:
update @macset { @ll,48,48 . @ll,112,16 & 0xfff timeout 5s }
because the ethernet protocol is replaced by vlan beforehand,
so we fail to map @ll,48,48 to a vlan protocol.
Likewise, we can't map the vlan info either because we cannot
cope with the 'and' operation properly, nor is it removed.
Prepare for this by deleting and re-adding so that we do not
corrupt the linked list.
After this, the list can be safely changed and a followup patch
can start to delete/reallocate expressions.
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Phil Sutter <psutter@redhat.com>
---
src/netlink_delinearize.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c
index 068c3bb..2f13990 100644
--- a/src/netlink_delinearize.c
+++ b/src/netlink_delinearize.c
@@ -2538,16 +2538,21 @@ static void expr_postprocess(struct rule_pp_ctx *ctx, struct expr **exprp)
unsigned int type = expr->dtype->type, ntype = 0;
int off = expr->dtype->subtypes;
const struct datatype *dtype;
+ LIST_HEAD(tmp);
+ struct expr *n;
- list_for_each_entry(i, &expr->expressions, list) {
+ list_for_each_entry_safe(i, n, &expr->expressions, list) {
if (type) {
dtype = concat_subtype_lookup(type, --off);
expr_set_type(i, dtype, dtype->byteorder);
}
+ list_del(&i->list);
expr_postprocess(ctx, &i);
+ list_add_tail(&i->list, &tmp);
ntype = concat_subtype_add(ntype, i->dtype->type);
}
+ list_splice(&tmp, &expr->expressions);
datatype_set(expr, concat_type_alloc(ntype));
break;
}
--
2.39.1

View File

@ -0,0 +1,159 @@
From 29f041b93d7fc4e23c62c2e2e3cbbeaafa83b4ef Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Thu, 9 Feb 2023 10:27:57 +0100
Subject: [PATCH] netlink_delinearize: postprocess binary ands in
concatenations
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2094887
Upstream Status: nftables commit 89688c947efc3
commit 89688c947efc36d25c58c85650414fa3a491732e
Author: Florian Westphal <fw@strlen.de>
Date: Tue Jun 14 21:56:48 2022 +0200
netlink_delinearize: postprocess binary ands in concatenations
Input:
update ether saddr . vlan id timeout 5s @macset
ether saddr . vlan id @macset
Before this patch, gets rendered as:
update @macset { @ll,48,48 . @ll,112,16 & 0xfff timeout 5s }
@ll,48,48 . @ll,112,16 & 0xfff @macset
After this, listing will show:
update @macset { @ll,48,48 . vlan id timeout 5s }
@ll,48,48 . vlan id @macset
The @ll, ... is due to vlan description replacing the ethernet one,
so payload decode fails to take the concatenation apart (the ethernet
header payload info is matched vs. vlan template).
This will be adjusted by a followup patch.
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Phil Sutter <psutter@redhat.com>
---
include/netlink.h | 6 ++++++
src/netlink_delinearize.c | 45 ++++++++++++++++++++++++++++++++++-----
2 files changed, 46 insertions(+), 5 deletions(-)
diff --git a/include/netlink.h b/include/netlink.h
index e8e0f68..71c888f 100644
--- a/include/netlink.h
+++ b/include/netlink.h
@@ -42,10 +42,16 @@ struct netlink_parse_ctx {
struct netlink_ctx *nlctx;
};
+
+#define RULE_PP_IN_CONCATENATION (1 << 0)
+
+#define RULE_PP_REMOVE_OP_AND (RULE_PP_IN_CONCATENATION)
+
struct rule_pp_ctx {
struct proto_ctx pctx;
struct payload_dep_ctx pdctx;
struct stmt *stmt;
+ unsigned int flags;
};
extern const struct input_descriptor indesc_netlink;
diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c
index 2f13990..cba419d 100644
--- a/src/netlink_delinearize.c
+++ b/src/netlink_delinearize.c
@@ -2259,12 +2259,13 @@ static void binop_adjust(const struct expr *binop, struct expr *right,
}
}
-static void binop_postprocess(struct rule_pp_ctx *ctx, struct expr *expr,
- struct expr **expr_binop)
+static void __binop_postprocess(struct rule_pp_ctx *ctx,
+ struct expr *expr,
+ struct expr *left,
+ struct expr *mask,
+ struct expr **expr_binop)
{
struct expr *binop = *expr_binop;
- struct expr *left = binop->left;
- struct expr *mask = binop->right;
unsigned int shift;
assert(binop->etype == EXPR_BINOP);
@@ -2300,15 +2301,26 @@ static void binop_postprocess(struct rule_pp_ctx *ctx, struct expr *expr,
assert(binop->left == left);
*expr_binop = expr_get(left);
- expr_free(binop);
if (left->etype == EXPR_PAYLOAD)
payload_match_postprocess(ctx, expr, left);
else if (left->etype == EXPR_EXTHDR && right)
expr_set_type(right, left->dtype, left->byteorder);
+
+ expr_free(binop);
}
}
+static void binop_postprocess(struct rule_pp_ctx *ctx, struct expr *expr,
+ struct expr **expr_binop)
+{
+ struct expr *binop = *expr_binop;
+ struct expr *left = binop->left;
+ struct expr *mask = binop->right;
+
+ __binop_postprocess(ctx, expr, left, mask, expr_binop);
+}
+
static void map_binop_postprocess(struct rule_pp_ctx *ctx, struct expr *expr)
{
struct expr *binop = expr->map;
@@ -2541,6 +2553,7 @@ static void expr_postprocess(struct rule_pp_ctx *ctx, struct expr **exprp)
LIST_HEAD(tmp);
struct expr *n;
+ ctx->flags |= RULE_PP_IN_CONCATENATION;
list_for_each_entry_safe(i, n, &expr->expressions, list) {
if (type) {
dtype = concat_subtype_lookup(type, --off);
@@ -2552,6 +2565,7 @@ static void expr_postprocess(struct rule_pp_ctx *ctx, struct expr **exprp)
ntype = concat_subtype_add(ntype, i->dtype->type);
}
+ ctx->flags &= ~RULE_PP_IN_CONCATENATION;
list_splice(&tmp, &expr->expressions);
datatype_set(expr, concat_type_alloc(ntype));
break;
@@ -2568,6 +2582,27 @@ static void expr_postprocess(struct rule_pp_ctx *ctx, struct expr **exprp)
expr_set_type(expr->right, &integer_type,
BYTEORDER_HOST_ENDIAN);
break;
+ case OP_AND:
+ expr_set_type(expr->right, expr->left->dtype,
+ expr->left->byteorder);
+
+ /* Do not process OP_AND in ordinary rule context.
+ *
+ * Removal needs to be performed as part of the relational
+ * operation because the RHS constant might need to be adjusted
+ * (shifted).
+ *
+ * This is different in set element context or concatenations:
+ * There is no relational operation (eq, neq and so on), thus
+ * it needs to be processed right away.
+ */
+ if ((ctx->flags & RULE_PP_REMOVE_OP_AND) &&
+ expr->left->etype == EXPR_PAYLOAD &&
+ expr->right->etype == EXPR_VALUE) {
+ __binop_postprocess(ctx, expr, expr->left, expr->right, exprp);
+ return;
+ }
+ break;
default:
expr_set_type(expr->right, expr->left->dtype,
expr->left->byteorder);
--
2.39.1

View File

@ -0,0 +1,287 @@
From 72f0ca53bcc6586b921ff70dac9f3a911e4ec170 Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Thu, 9 Feb 2023 10:27:57 +0100
Subject: [PATCH] proto: track full stack of seen l2 protocols, not just
cumulative offset
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2094887
Upstream Status: nftables commit 0d9daa0407212
commit 0d9daa0407212c8cc89b3ea8aee031ddf0109b08
Author: Florian Westphal <fw@strlen.de>
Date: Mon Jul 25 14:32:13 2022 +0200
proto: track full stack of seen l2 protocols, not just cumulative offset
For input, a cumulative size counter of all pushed l2 headers is enough,
because we have the full expression tree available to us.
For delinearization we need to track all seen l2 headers, else we lose
information that we might need at a later time.
Consider:
rule netdev nt nc set update ether saddr . vlan id
during delinearization, the vlan proto_desc replaces the ethernet one,
and by the time we try to split the concatenation apart we will search
the ether saddr offset vs. the templates for proto_vlan.
This replaces the offset with an array that stores the protocol
descriptions seen.
Then, if the payload offset is larger than our description, search the
l2 stack and adjust the offset until we're within the expected offset
boundary.
Reported-by: Eric Garver <eric@garver.life>
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Phil Sutter <psutter@redhat.com>
---
include/proto.h | 3 +-
src/evaluate.c | 15 +++++++--
src/netlink_delinearize.c | 5 ---
src/payload.c | 67 ++++++++++++++++++++++++++++++++-------
src/proto.c | 2 --
5 files changed, 71 insertions(+), 21 deletions(-)
diff --git a/include/proto.h b/include/proto.h
index a04240a..35e760c 100644
--- a/include/proto.h
+++ b/include/proto.h
@@ -193,13 +193,14 @@ struct proto_ctx {
struct {
struct location location;
const struct proto_desc *desc;
- unsigned int offset;
struct {
struct location location;
const struct proto_desc *desc;
} protos[PROTO_CTX_NUM_PROTOS];
unsigned int num_protos;
} protocol[PROTO_BASE_MAX + 1];
+ const struct proto_desc *stacked_ll[PROTO_CTX_NUM_PROTOS];
+ uint8_t stacked_ll_count;
};
extern void proto_ctx_init(struct proto_ctx *ctx, unsigned int family,
diff --git a/src/evaluate.c b/src/evaluate.c
index 82bf131..9246064 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -678,7 +678,13 @@ static int resolve_protocol_conflict(struct eval_ctx *ctx,
conflict_resolution_gen_dependency(ctx, link, payload, &nstmt) < 0)
return 1;
- payload->payload.offset += ctx->pctx.protocol[base].offset;
+ if (base == PROTO_BASE_LL_HDR) {
+ unsigned int i;
+
+ for (i = 0; i < ctx->pctx.stacked_ll_count; i++)
+ payload->payload.offset += ctx->pctx.stacked_ll[i]->length;
+ }
+
rule_stmt_insert_at(ctx->rule, nstmt, ctx->stmt);
return 0;
@@ -727,7 +733,12 @@ static int __expr_evaluate_payload(struct eval_ctx *ctx, struct expr *expr)
if (desc == payload->payload.desc) {
const struct proto_hdr_template *tmpl;
- payload->payload.offset += ctx->pctx.protocol[base].offset;
+ if (desc->base == PROTO_BASE_LL_HDR) {
+ unsigned int i;
+
+ for (i = 0; i < ctx->pctx.stacked_ll_count; i++)
+ payload->payload.offset += ctx->pctx.stacked_ll[i]->length;
+ }
check_icmp:
if (desc != &proto_icmp && desc != &proto_icmp6)
return 0;
diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c
index cba419d..0b5519d 100644
--- a/src/netlink_delinearize.c
+++ b/src/netlink_delinearize.c
@@ -1976,11 +1976,6 @@ static void payload_match_postprocess(struct rule_pp_ctx *ctx,
struct expr *expr,
struct expr *payload)
{
- enum proto_bases base = payload->payload.base;
-
- assert(payload->payload.offset >= ctx->pctx.protocol[base].offset);
- payload->payload.offset -= ctx->pctx.protocol[base].offset;
-
switch (expr->op) {
case OP_EQ:
case OP_NEQ:
diff --git a/src/payload.c b/src/payload.c
index 66418cd..2c0d0ac 100644
--- a/src/payload.c
+++ b/src/payload.c
@@ -116,8 +116,13 @@ static void payload_expr_pctx_update(struct proto_ctx *ctx,
if (desc->base == base->base) {
assert(base->length > 0);
- if (!left->payload.is_raw)
- ctx->protocol[base->base].offset += base->length;
+ if (!left->payload.is_raw) {
+ if (desc->base == PROTO_BASE_LL_HDR &&
+ ctx->stacked_ll_count < PROTO_CTX_NUM_PROTOS) {
+ ctx->stacked_ll[ctx->stacked_ll_count] = base;
+ ctx->stacked_ll_count++;
+ }
+ }
}
proto_ctx_update(ctx, desc->base, loc, desc);
}
@@ -869,6 +874,38 @@ void exthdr_dependency_kill(struct payload_dep_ctx *ctx, struct expr *expr,
}
}
+static const struct proto_desc *get_stacked_desc(const struct proto_ctx *ctx,
+ const struct proto_desc *top,
+ const struct expr *e,
+ unsigned int *skip)
+{
+ unsigned int i, total, payload_offset = e->payload.offset;
+
+ assert(e->etype == EXPR_PAYLOAD);
+
+ if (e->payload.base != PROTO_BASE_LL_HDR ||
+ payload_offset < top->length) {
+ *skip = 0;
+ return top;
+ }
+
+ for (i = 0, total = 0; i < ctx->stacked_ll_count; i++) {
+ const struct proto_desc *stacked;
+
+ stacked = ctx->stacked_ll[i];
+ if (payload_offset < stacked->length) {
+ *skip = total;
+ return stacked;
+ }
+
+ payload_offset -= stacked->length;
+ total += stacked->length;
+ }
+
+ *skip = total;
+ return top;
+}
+
/**
* payload_expr_complete - fill in type information of a raw payload expr
*
@@ -880,9 +917,10 @@ void exthdr_dependency_kill(struct payload_dep_ctx *ctx, struct expr *expr,
*/
void payload_expr_complete(struct expr *expr, const struct proto_ctx *ctx)
{
+ unsigned int payload_offset = expr->payload.offset;
const struct proto_desc *desc;
const struct proto_hdr_template *tmpl;
- unsigned int i;
+ unsigned int i, total;
assert(expr->etype == EXPR_PAYLOAD);
@@ -891,9 +929,12 @@ void payload_expr_complete(struct expr *expr, const struct proto_ctx *ctx)
return;
assert(desc->base == expr->payload.base);
+ desc = get_stacked_desc(ctx, desc, expr, &total);
+ payload_offset -= total;
+
for (i = 0; i < array_size(desc->templates); i++) {
tmpl = &desc->templates[i];
- if (tmpl->offset != expr->payload.offset ||
+ if (tmpl->offset != payload_offset ||
tmpl->len != expr->len)
continue;
@@ -950,6 +991,7 @@ bool payload_expr_trim(struct expr *expr, struct expr *mask,
unsigned int payload_len = expr->len;
const struct proto_desc *desc;
unsigned int off, i, len = 0;
+ unsigned int total;
assert(expr->etype == EXPR_PAYLOAD);
@@ -959,10 +1001,8 @@ bool payload_expr_trim(struct expr *expr, struct expr *mask,
assert(desc->base == expr->payload.base);
- if (ctx->protocol[expr->payload.base].offset) {
- assert(payload_offset >= ctx->protocol[expr->payload.base].offset);
- payload_offset -= ctx->protocol[expr->payload.base].offset;
- }
+ desc = get_stacked_desc(ctx, desc, expr, &total);
+ payload_offset -= total;
off = round_up(mask->len, BITS_PER_BYTE) - mask_len;
payload_offset += off;
@@ -1009,10 +1049,11 @@ bool payload_expr_trim(struct expr *expr, struct expr *mask,
void payload_expr_expand(struct list_head *list, struct expr *expr,
const struct proto_ctx *ctx)
{
+ unsigned int payload_offset = expr->payload.offset;
const struct proto_hdr_template *tmpl;
const struct proto_desc *desc;
+ unsigned int i, total;
struct expr *new;
- unsigned int i;
assert(expr->etype == EXPR_PAYLOAD);
@@ -1021,13 +1062,16 @@ void payload_expr_expand(struct list_head *list, struct expr *expr,
goto raw;
assert(desc->base == expr->payload.base);
+ desc = get_stacked_desc(ctx, desc, expr, &total);
+ payload_offset -= total;
+
for (i = 1; i < array_size(desc->templates); i++) {
tmpl = &desc->templates[i];
if (tmpl->len == 0)
break;
- if (tmpl->offset != expr->payload.offset)
+ if (tmpl->offset != payload_offset)
continue;
if (tmpl->icmp_dep && ctx->th_dep.icmp.type &&
@@ -1039,6 +1083,7 @@ void payload_expr_expand(struct list_head *list, struct expr *expr,
list_add_tail(&new->list, list);
expr->len -= tmpl->len;
expr->payload.offset += tmpl->len;
+ payload_offset += tmpl->len;
if (expr->len == 0)
return;
} else if (expr->len > 0) {
@@ -1051,7 +1096,7 @@ void payload_expr_expand(struct list_head *list, struct expr *expr,
}
raw:
new = payload_expr_alloc(&expr->location, NULL, 0);
- payload_init_raw(new, expr->payload.base, expr->payload.offset,
+ payload_init_raw(new, expr->payload.base, payload_offset,
expr->len);
list_add_tail(&new->list, list);
}
diff --git a/src/proto.c b/src/proto.c
index a013a00..2663f21 100644
--- a/src/proto.c
+++ b/src/proto.c
@@ -160,8 +160,6 @@ static void proto_ctx_debug(const struct proto_ctx *ctx, enum proto_bases base,
proto_base_names[i],
ctx->protocol[i].desc ? ctx->protocol[i].desc->name :
"none");
- if (ctx->protocol[i].offset)
- pr_debug(" (offset: %u)", ctx->protocol[i].offset);
if (i == base)
pr_debug(" <-");
pr_debug("\n");
--
2.39.1

View File

@ -0,0 +1,44 @@
From ed9b1e973f19f66cf08ea0db8947768f0240fa10 Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Thu, 9 Feb 2023 10:27:57 +0100
Subject: [PATCH] debug: dump the l2 protocol stack
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2094887
Upstream Status: nftables commit dbd5f348c71de
commit dbd5f348c71decf0baa8fb592c576f63fa232f50
Author: Florian Westphal <fw@strlen.de>
Date: Mon Jul 25 16:42:23 2022 +0200
debug: dump the l2 protocol stack
Previously we used to print the cumulative size of the headers,
update this to print the tracked l2 stack.
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Phil Sutter <psutter@redhat.com>
---
src/proto.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/src/proto.c b/src/proto.c
index 2663f21..c496482 100644
--- a/src/proto.c
+++ b/src/proto.c
@@ -154,6 +154,12 @@ static void proto_ctx_debug(const struct proto_ctx *ctx, enum proto_bases base,
if (!(debug_mask & NFT_DEBUG_PROTO_CTX))
return;
+ if (base == PROTO_BASE_LL_HDR && ctx->stacked_ll_count) {
+ pr_debug(" saved ll headers:");
+ for (i = 0; i < ctx->stacked_ll_count; i++)
+ pr_debug(" %s", ctx->stacked_ll[i]->name);
+ }
+
pr_debug("update %s protocol context:\n", proto_base_names[base]);
for (i = PROTO_BASE_LL_HDR; i <= PROTO_BASE_MAX; i++) {
pr_debug(" %-20s: %s",
--
2.39.1

View File

@ -0,0 +1,65 @@
From a273fd3aaf89391ac84d7a155b3bb177552bf115 Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Thu, 9 Feb 2023 10:27:57 +0100
Subject: [PATCH] tests: add a test case for ether and vlan listing
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2094887
Upstream Status: nftables commit f680055cd4377
commit f680055cd4377f2f531f5f77b3aaa7550988665d
Author: Florian Westphal <fw@strlen.de>
Date: Mon Jul 25 19:31:22 2022 +0200
tests: add a test case for ether and vlan listing
before this patch series, test fails dump validation:
- update @macset { ether saddr . vlan id timeout 5s } counter packets 0 bytes 0
- ether saddr . vlan id @macset
+ update @macset { @ll,48,48 . @ll,112,16 & 0xfff timeout 5s } counter packets 0 bytes 0
+ @ll,48,48 . @ll,112,16 & 0xfff @macset
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Phil Sutter <psutter@redhat.com>
---
tests/shell/testcases/sets/0070stacked_l2_headers | 6 ++++++
.../sets/dumps/0070stacked_l2_headers.nft | 14 ++++++++++++++
2 files changed, 20 insertions(+)
create mode 100755 tests/shell/testcases/sets/0070stacked_l2_headers
create mode 100644 tests/shell/testcases/sets/dumps/0070stacked_l2_headers.nft
diff --git a/tests/shell/testcases/sets/0070stacked_l2_headers b/tests/shell/testcases/sets/0070stacked_l2_headers
new file mode 100755
index 0000000..07820b7
--- /dev/null
+++ b/tests/shell/testcases/sets/0070stacked_l2_headers
@@ -0,0 +1,6 @@
+#!/bin/bash
+
+set -e
+dumpfile=$(dirname $0)/dumps/$(basename $0).nft
+
+$NFT -f "$dumpfile"
diff --git a/tests/shell/testcases/sets/dumps/0070stacked_l2_headers.nft b/tests/shell/testcases/sets/dumps/0070stacked_l2_headers.nft
new file mode 100644
index 0000000..ef254b9
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0070stacked_l2_headers.nft
@@ -0,0 +1,14 @@
+table netdev nt {
+ set macset {
+ typeof ether saddr . vlan id
+ size 1024
+ flags dynamic,timeout
+ }
+
+ chain nc {
+ update @macset { ether saddr . vlan id timeout 5s } counter packets 0 bytes 0
+ ether saddr . vlan id @macset
+ vlan pcp 1
+ ether saddr 0a:0b:0c:0d:0e:0f vlan id 42
+ }
+}
--
2.39.1

View File

@ -0,0 +1,99 @@
From 72a88a128ebb386307e9d3ef1b71cefa52c7a0af Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Thu, 9 Feb 2023 10:27:57 +0100
Subject: [PATCH] netlink_delinearize: also postprocess OP_AND in set element
context
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2094887
Upstream Status: nftables commit b1e3ed0335d13
commit b1e3ed0335d13d206a2a2698a1ba189fa396dbf3
Author: Florian Westphal <fw@strlen.de>
Date: Mon Aug 1 13:03:18 2022 +0200
netlink_delinearize: also postprocess OP_AND in set element context
Pablo reports:
add rule netdev nt y update @macset { vlan id timeout 5s }
listing still shows the raw expression:
update @macset { @ll,112,16 & 0xfff timeout 5s }
so also cover the 'set element' case.
Reported-by: Pablo Neira Ayuso <pablo@netfilter.org>
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Phil Sutter <psutter@redhat.com>
---
include/netlink.h | 4 +++-
src/netlink_delinearize.c | 2 ++
.../sets/dumps/0070stacked_l2_headers.nft | 14 ++++++++++++++
3 files changed, 19 insertions(+), 1 deletion(-)
diff --git a/include/netlink.h b/include/netlink.h
index 71c888f..63d07ed 100644
--- a/include/netlink.h
+++ b/include/netlink.h
@@ -44,8 +44,10 @@ struct netlink_parse_ctx {
#define RULE_PP_IN_CONCATENATION (1 << 0)
+#define RULE_PP_IN_SET_ELEM (1 << 1)
-#define RULE_PP_REMOVE_OP_AND (RULE_PP_IN_CONCATENATION)
+#define RULE_PP_REMOVE_OP_AND (RULE_PP_IN_CONCATENATION | \
+ RULE_PP_IN_SET_ELEM)
struct rule_pp_ctx {
struct proto_ctx pctx;
diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c
index 0b5519d..c6ad84d 100644
--- a/src/netlink_delinearize.c
+++ b/src/netlink_delinearize.c
@@ -2660,7 +2660,9 @@ static void expr_postprocess(struct rule_pp_ctx *ctx, struct expr **exprp)
expr_postprocess(ctx, &expr->prefix);
break;
case EXPR_SET_ELEM:
+ ctx->flags |= RULE_PP_IN_SET_ELEM;
expr_postprocess(ctx, &expr->key);
+ ctx->flags &= ~RULE_PP_IN_SET_ELEM;
break;
case EXPR_EXTHDR:
exthdr_dependency_kill(&ctx->pdctx, expr, ctx->pctx.family);
diff --git a/tests/shell/testcases/sets/dumps/0070stacked_l2_headers.nft b/tests/shell/testcases/sets/dumps/0070stacked_l2_headers.nft
index ef254b9..0057e9c 100644
--- a/tests/shell/testcases/sets/dumps/0070stacked_l2_headers.nft
+++ b/tests/shell/testcases/sets/dumps/0070stacked_l2_headers.nft
@@ -1,14 +1,28 @@
table netdev nt {
+ set vlanidset {
+ typeof vlan id
+ size 1024
+ flags dynamic,timeout
+ }
+
set macset {
typeof ether saddr . vlan id
size 1024
flags dynamic,timeout
}
+ set ipset {
+ typeof vlan id . ip saddr
+ size 1024
+ flags dynamic,timeout
+ }
+
chain nc {
update @macset { ether saddr . vlan id timeout 5s } counter packets 0 bytes 0
ether saddr . vlan id @macset
vlan pcp 1
ether saddr 0a:0b:0c:0d:0e:0f vlan id 42
+ update @vlanidset { vlan id timeout 5s } counter packets 0 bytes 0
+ update @ipset { vlan id . ip saddr timeout 5s } counter packets 0 bytes 0
}
}
--
2.39.1

View File

@ -0,0 +1,198 @@
From 71fb4e3be07548216a831dda28f4aedfc37b2df1 Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Thu, 9 Feb 2023 10:27:58 +0100
Subject: [PATCH] evaluate: search stacked header list for matching payload dep
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2094887
Upstream Status: nftables commit 87c3041bfd244
commit 87c3041bfd244aaf39e644d33c0df4fe04079e1c
Author: Florian Westphal <fw@strlen.de>
Date: Mon Jul 25 20:02:28 2022 +0200
evaluate: search stacked header list for matching payload dep
"ether saddr 0:1:2:3:4:6 vlan id 2" works, but reverse fails:
"vlan id 2 ether saddr 0:1:2:3:4:6" will give
Error: conflicting protocols specified: vlan vs. ether
After "proto: track full stack of seen l2 protocols, not just cumulative offset",
we have a list of all l2 headers, so search those to see if we had this
proto base in the past before rejecting this.
Reported-by: Eric Garver <eric@garver.life>
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Phil Sutter <psutter@redhat.com>
---
src/evaluate.c | 21 +++++++---
tests/py/bridge/vlan.t | 3 ++
tests/py/bridge/vlan.t.json | 56 +++++++++++++++++++++++++++
tests/py/bridge/vlan.t.payload | 16 ++++++++
tests/py/bridge/vlan.t.payload.netdev | 20 ++++++++++
5 files changed, 110 insertions(+), 6 deletions(-)
diff --git a/src/evaluate.c b/src/evaluate.c
index 9246064..d67f915 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -659,13 +659,22 @@ static int resolve_protocol_conflict(struct eval_ctx *ctx,
struct stmt *nstmt = NULL;
int link, err;
- if (payload->payload.base == PROTO_BASE_LL_HDR &&
- proto_is_dummy(desc)) {
- err = meta_iiftype_gen_dependency(ctx, payload, &nstmt);
- if (err < 0)
- return err;
+ if (payload->payload.base == PROTO_BASE_LL_HDR) {
+ if (proto_is_dummy(desc)) {
+ err = meta_iiftype_gen_dependency(ctx, payload, &nstmt);
+ if (err < 0)
+ return err;
- rule_stmt_insert_at(ctx->rule, nstmt, ctx->stmt);
+ rule_stmt_insert_at(ctx->rule, nstmt, ctx->stmt);
+ } else {
+ unsigned int i;
+
+ /* payload desc stored in the L2 header stack? No conflict. */
+ for (i = 0; i < ctx->pctx.stacked_ll_count; i++) {
+ if (ctx->pctx.stacked_ll[i] == payload->payload.desc)
+ return 0;
+ }
+ }
}
assert(base <= PROTO_BASE_MAX);
diff --git a/tests/py/bridge/vlan.t b/tests/py/bridge/vlan.t
index 924ed4e..4920601 100644
--- a/tests/py/bridge/vlan.t
+++ b/tests/py/bridge/vlan.t
@@ -47,3 +47,6 @@ ether type ip vlan id 1 ip saddr 10.0.0.1;fail
# mangling
vlan id 1 vlan id set 2;ok
+
+ether saddr 00:01:02:03:04:05 vlan id 1;ok
+vlan id 2 ether saddr 0:1:2:3:4:6;ok;ether saddr 00:01:02:03:04:06 vlan id 2
diff --git a/tests/py/bridge/vlan.t.json b/tests/py/bridge/vlan.t.json
index e7640f9..58d4a40 100644
--- a/tests/py/bridge/vlan.t.json
+++ b/tests/py/bridge/vlan.t.json
@@ -761,3 +761,59 @@
}
}
]
+
+# ether saddr 00:01:02:03:04:05 vlan id 1
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ether"
+ }
+ },
+ "op": "==",
+ "right": "00:01:02:03:04:05"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "id",
+ "protocol": "vlan"
+ }
+ },
+ "op": "==",
+ "right": 1
+ }
+ }
+]
+
+# vlan id 2 ether saddr 0:1:2:3:4:6
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ether"
+ }
+ },
+ "op": "==",
+ "right": "00:01:02:03:04:06"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "id",
+ "protocol": "vlan"
+ }
+ },
+ "op": "==",
+ "right": 2
+ }
+ }
+]
diff --git a/tests/py/bridge/vlan.t.payload b/tests/py/bridge/vlan.t.payload
index 6c8d595..713670e 100644
--- a/tests/py/bridge/vlan.t.payload
+++ b/tests/py/bridge/vlan.t.payload
@@ -276,3 +276,19 @@ bridge
[ payload load 2b @ link header + 14 => reg 1 ]
[ bitwise reg 1 = ( reg 1 & 0x000000f0 ) ^ 0x00000200 ]
[ payload write reg 1 => 2b @ link header + 14 csum_type 0 csum_off 0 csum_flags 0x0 ]
+
+# ether saddr 00:01:02:03:04:05 vlan id 1
+bridge test-bridge input
+ [ payload load 8b @ link header + 6 => reg 1 ]
+ [ cmp eq reg 1 0x03020100 0x00810504 ]
+ [ payload load 2b @ link header + 14 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000100 ]
+
+# vlan id 2 ether saddr 0:1:2:3:4:6
+bridge test-bridge input
+ [ payload load 8b @ link header + 6 => reg 1 ]
+ [ cmp eq reg 1 0x03020100 0x00810604 ]
+ [ payload load 2b @ link header + 14 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000200 ]
diff --git a/tests/py/bridge/vlan.t.payload.netdev b/tests/py/bridge/vlan.t.payload.netdev
index d2c7d74..98a2a2b 100644
--- a/tests/py/bridge/vlan.t.payload.netdev
+++ b/tests/py/bridge/vlan.t.payload.netdev
@@ -322,3 +322,23 @@ netdev
[ payload load 2b @ link header + 14 => reg 1 ]
[ bitwise reg 1 = ( reg 1 & 0x000000f0 ) ^ 0x00000200 ]
[ payload write reg 1 => 2b @ link header + 14 csum_type 0 csum_off 0 csum_flags 0x0 ]
+
+# vlan id 2 ether saddr 0:1:2:3:4:6
+netdev test-netdev ingress
+ [ meta load iiftype => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 8b @ link header + 6 => reg 1 ]
+ [ cmp eq reg 1 0x03020100 0x00810604 ]
+ [ payload load 2b @ link header + 14 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000200 ]
+
+# ether saddr 00:01:02:03:04:05 vlan id 1
+netdev test-netdev ingress
+ [ meta load iiftype => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 8b @ link header + 6 => reg 1 ]
+ [ cmp eq reg 1 0x03020100 0x00810504 ]
+ [ payload load 2b @ link header + 14 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000100 ]
--
2.39.1

View File

@ -0,0 +1,223 @@
From 99e943834fc6708fb8bd8f329988979433db19e8 Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Thu, 9 Feb 2023 10:27:58 +0100
Subject: [PATCH] src: allow anon set concatenation with ether and vlan
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2094887
Upstream Status: nftables commit c1c223f1b5818
commit c1c223f1b58188542222ee2d9a4a8cc133d1dc3b
Author: Florian Westphal <fw@strlen.de>
Date: Mon Jul 25 21:34:52 2022 +0200
src: allow anon set concatenation with ether and vlan
vlan id uses integer type (which has a length of 0).
Using it was possible, but listing would assert:
python: mergesort.c:24: concat_expr_msort_value: Assertion `ilen > 0' failed.
There are two reasons for this.
First reason is that the udata/typeof information lacks the 'vlan id'
part, because internally this is 'payload . binop(payload AND mask)'.
binop lacks an udata store. It makes little sense to store it,
'typeof' keyword expects normal match syntax.
So, when storing udata, store the left hand side of the binary
operation, i.e. the load of the 2-byte key.
With that resolved, delinerization could work, but concat_elem_expr()
would splice 12 bits off the elements value, but it should be 16 (on
a byte boundary).
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Phil Sutter <psutter@redhat.com>
---
src/expression.c | 17 +++++++++--
src/netlink.c | 10 +++++--
tests/py/bridge/vlan.t | 2 ++
tests/py/bridge/vlan.t.json | 41 +++++++++++++++++++++++++++
tests/py/bridge/vlan.t.payload | 12 ++++++++
tests/py/bridge/vlan.t.payload.netdev | 14 +++++++++
6 files changed, 91 insertions(+), 5 deletions(-)
diff --git a/src/expression.c b/src/expression.c
index deb649e..7390089 100644
--- a/src/expression.c
+++ b/src/expression.c
@@ -879,17 +879,30 @@ static void concat_expr_print(const struct expr *expr, struct output_ctx *octx)
#define NFTNL_UDATA_SET_KEY_CONCAT_SUB_DATA 1
#define NFTNL_UDATA_SET_KEY_CONCAT_SUB_MAX 2
+static struct expr *expr_build_udata_recurse(struct expr *e)
+{
+ switch (e->etype) {
+ case EXPR_BINOP:
+ return e->left;
+ default:
+ break;
+ }
+
+ return e;
+}
+
static int concat_expr_build_udata(struct nftnl_udata_buf *udbuf,
const struct expr *concat_expr)
{
struct nftnl_udata *nest;
+ struct expr *expr, *tmp;
unsigned int i = 0;
- struct expr *expr;
- list_for_each_entry(expr, &concat_expr->expressions, list) {
+ list_for_each_entry_safe(expr, tmp, &concat_expr->expressions, list) {
struct nftnl_udata *nest_expr;
int err;
+ expr = expr_build_udata_recurse(expr);
if (!expr_ops(expr)->build_udata || i >= NFT_REG32_SIZE)
return -1;
diff --git a/src/netlink.c b/src/netlink.c
index 89d864e..799cf9b 100644
--- a/src/netlink.c
+++ b/src/netlink.c
@@ -1114,17 +1114,21 @@ static struct expr *concat_elem_expr(struct expr *key,
struct expr *data, int *off)
{
const struct datatype *subtype;
+ unsigned int sub_length;
struct expr *expr;
if (key) {
(*off)--;
- expr = constant_expr_splice(data, key->len);
+ sub_length = round_up(key->len, BITS_PER_BYTE);
+
+ expr = constant_expr_splice(data, sub_length);
expr->dtype = datatype_get(key->dtype);
expr->byteorder = key->byteorder;
expr->len = key->len;
} else {
subtype = concat_subtype_lookup(dtype->type, --(*off));
- expr = constant_expr_splice(data, subtype->size);
+ sub_length = round_up(subtype->size, BITS_PER_BYTE);
+ expr = constant_expr_splice(data, sub_length);
expr->dtype = subtype;
expr->byteorder = subtype->byteorder;
}
@@ -1136,7 +1140,7 @@ static struct expr *concat_elem_expr(struct expr *key,
expr->dtype->basetype->type == TYPE_BITMASK)
expr = bitmask_expr_to_binops(expr);
- data->len -= netlink_padding_len(expr->len);
+ data->len -= netlink_padding_len(sub_length);
return expr;
}
diff --git a/tests/py/bridge/vlan.t b/tests/py/bridge/vlan.t
index 4920601..95bdff4 100644
--- a/tests/py/bridge/vlan.t
+++ b/tests/py/bridge/vlan.t
@@ -50,3 +50,5 @@ vlan id 1 vlan id set 2;ok
ether saddr 00:01:02:03:04:05 vlan id 1;ok
vlan id 2 ether saddr 0:1:2:3:4:6;ok;ether saddr 00:01:02:03:04:06 vlan id 2
+
+ether saddr . vlan id { 0a:0b:0c:0d:0e:0f . 42, 0a:0b:0c:0d:0e:0f . 4095 };ok
diff --git a/tests/py/bridge/vlan.t.json b/tests/py/bridge/vlan.t.json
index 58d4a40..f77756f 100644
--- a/tests/py/bridge/vlan.t.json
+++ b/tests/py/bridge/vlan.t.json
@@ -817,3 +817,44 @@
}
}
]
+
+# ether saddr . vlan id { 0a:0b:0c:0d:0e:0f . 42, 0a:0b:0c:0d:0e:0f . 4095 }
+[
+ {
+ "match": {
+ "left": {
+ "concat": [
+ {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ether"
+ }
+ },
+ {
+ "payload": {
+ "field": "id",
+ "protocol": "vlan"
+ }
+ }
+ ]
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ {
+ "concat": [
+ "0a:0b:0c:0d:0e:0f",
+ 42
+ ]
+ },
+ {
+ "concat": [
+ "0a:0b:0c:0d:0e:0f",
+ 4095
+ ]
+ }
+ ]
+ }
+ }
+ }
+]
diff --git a/tests/py/bridge/vlan.t.payload b/tests/py/bridge/vlan.t.payload
index 713670e..62e4b89 100644
--- a/tests/py/bridge/vlan.t.payload
+++ b/tests/py/bridge/vlan.t.payload
@@ -292,3 +292,15 @@ bridge test-bridge input
[ payload load 2b @ link header + 14 => reg 1 ]
[ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
[ cmp eq reg 1 0x00000200 ]
+
+# ether saddr . vlan id { 0a:0b:0c:0d:0e:0f . 42, 0a:0b:0c:0d:0e:0f . 4095 }
+__set%d test-bridge 3 size 2
+__set%d test-bridge 0
+ element 0d0c0b0a 00000f0e 00002a00 : 0 [end] element 0d0c0b0a 00000f0e 0000ff0f : 0 [end]
+bridge test-bridge input
+ [ payload load 2b @ link header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x00000081 ]
+ [ payload load 6b @ link header + 6 => reg 1 ]
+ [ payload load 2b @ link header + 14 => reg 10 ]
+ [ bitwise reg 10 = ( reg 10 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ lookup reg 1 set __set%d ]
diff --git a/tests/py/bridge/vlan.t.payload.netdev b/tests/py/bridge/vlan.t.payload.netdev
index 98a2a2b..1018d4c 100644
--- a/tests/py/bridge/vlan.t.payload.netdev
+++ b/tests/py/bridge/vlan.t.payload.netdev
@@ -342,3 +342,17 @@ netdev test-netdev ingress
[ payload load 2b @ link header + 14 => reg 1 ]
[ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
[ cmp eq reg 1 0x00000100 ]
+
+# ether saddr . vlan id { 0a:0b:0c:0d:0e:0f . 42, 0a:0b:0c:0d:0e:0f . 4095 }
+__set%d test-netdev 3 size 2
+__set%d test-netdev 0
+ element 0d0c0b0a 00000f0e 00002a00 : 0 [end] element 0d0c0b0a 00000f0e 0000ff0f : 0 [end]
+netdev test-netdev ingress
+ [ meta load iiftype => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 2b @ link header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x00000081 ]
+ [ payload load 6b @ link header + 6 => reg 1 ]
+ [ payload load 2b @ link header + 14 => reg 10 ]
+ [ bitwise reg 10 = ( reg 10 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ lookup reg 1 set __set%d ]
--
2.39.1

View File

@ -0,0 +1,200 @@
From 5a23da04e253a012adc877a82fcdec5e2f4a1534 Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Thu, 9 Feb 2023 12:45:30 +0100
Subject: [PATCH] evaluate: set eval ctx for add/update statements with integer
constants
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2094894
Upstream Status: nftables commit 4cc6b20d31498
commit 4cc6b20d31498d90e90ff574ce8b70276afcee8f
Author: Florian Westphal <fw@strlen.de>
Date: Mon Jan 23 19:03:28 2023 +0100
evaluate: set eval ctx for add/update statements with integer constants
Eric reports that nft asserts when using integer basetype constants with
'typeof' sets. Example:
table netdev t {
set s {
typeof ether saddr . vlan id
flags dynamic,timeout
}
chain c { }
}
loads fine. But adding a rule with add/update statement fails:
nft 'add rule netdev t c set update ether saddr . 0 @s'
nft: netlink_linearize.c:867: netlink_gen_expr: Assertion `dreg < ctx->reg_low' failed.
When the 'ether saddr . 0' concat expression is processed, there is
no set definition available anymore to deduce the required size of the
integer constant.
nft eval step then derives the required length using the data types.
'0' has integer basetype, so the deduced length is 0.
The assertion triggers because serialization step finds that it
needs one more register.
2 are needed to store the ethernet address, another register is
needed for the vlan id.
Update eval step to make the expression context store the set key
information when processing the preceeding set reference, then
let stmt_evaluate_set() preserve the existing context instead of
zeroing it again via stmt_evaluate_arg().
This makes concat expression evaluation compute the total size
needed based on the sets key definition.
Reported-by: Eric Garver <eric@garver.life>
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Phil Sutter <psutter@redhat.com>
---
src/evaluate.c | 32 +++++++++++++++++--
.../maps/dumps/typeof_maps_concat.nft | 11 +++++++
tests/shell/testcases/maps/typeof_maps_concat | 6 ++++
.../sets/dumps/typeof_sets_concat.nft | 12 +++++++
tests/shell/testcases/sets/typeof_sets_concat | 6 ++++
5 files changed, 65 insertions(+), 2 deletions(-)
create mode 100644 tests/shell/testcases/maps/dumps/typeof_maps_concat.nft
create mode 100755 tests/shell/testcases/maps/typeof_maps_concat
create mode 100644 tests/shell/testcases/sets/dumps/typeof_sets_concat.nft
create mode 100755 tests/shell/testcases/sets/typeof_sets_concat
diff --git a/src/evaluate.c b/src/evaluate.c
index d67f915..7f81411 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -1526,6 +1526,14 @@ static int interval_set_eval(struct eval_ctx *ctx, struct set *set,
return ret;
}
+static void expr_evaluate_set_ref(struct eval_ctx *ctx, struct expr *expr)
+{
+ struct set *set = expr->set;
+
+ expr_set_context(&ctx->ectx, set->key->dtype, set->key->len);
+ ctx->ectx.key = set->key;
+}
+
static int expr_evaluate_set(struct eval_ctx *ctx, struct expr **expr)
{
struct expr *set = *expr, *i, *next;
@@ -2388,6 +2396,7 @@ static int expr_evaluate(struct eval_ctx *ctx, struct expr **expr)
case EXPR_VARIABLE:
return expr_evaluate_variable(ctx, expr);
case EXPR_SET_REF:
+ expr_evaluate_set_ref(ctx, *expr);
return 0;
case EXPR_VALUE:
return expr_evaluate_value(ctx, expr);
@@ -2550,6 +2559,25 @@ static int stmt_evaluate_arg(struct eval_ctx *ctx, struct stmt *stmt,
return __stmt_evaluate_arg(ctx, stmt, dtype, len, byteorder, expr);
}
+/* like stmt_evaluate_arg, but keep existing context created
+ * by previous expr_evaluate().
+ *
+ * This is needed for add/update statements:
+ * ctx->ectx.key has the set key, which may be needed for 'typeof'
+ * sets: the 'add/update' expression might contain integer data types.
+ *
+ * Without the key we cannot derive the element size.
+ */
+static int stmt_evaluate_key(struct eval_ctx *ctx, struct stmt *stmt,
+ const struct datatype *dtype, unsigned int len,
+ enum byteorder byteorder, struct expr **expr)
+{
+ if (expr_evaluate(ctx, expr) < 0)
+ return -1;
+
+ return __stmt_evaluate_arg(ctx, stmt, dtype, len, byteorder, expr);
+}
+
static int stmt_evaluate_verdict(struct eval_ctx *ctx, struct stmt *stmt)
{
if (stmt_evaluate_arg(ctx, stmt, &verdict_type, 0, 0, &stmt->expr) < 0)
@@ -3762,7 +3790,7 @@ static int stmt_evaluate_set(struct eval_ctx *ctx, struct stmt *stmt)
return expr_error(ctx->msgs, stmt->set.set,
"Expression does not refer to a set");
- if (stmt_evaluate_arg(ctx, stmt,
+ if (stmt_evaluate_key(ctx, stmt,
stmt->set.set->set->key->dtype,
stmt->set.set->set->key->len,
stmt->set.set->set->key->byteorder,
@@ -3805,7 +3833,7 @@ static int stmt_evaluate_map(struct eval_ctx *ctx, struct stmt *stmt)
return expr_error(ctx->msgs, stmt->map.set,
"Expression does not refer to a set");
- if (stmt_evaluate_arg(ctx, stmt,
+ if (stmt_evaluate_key(ctx, stmt,
stmt->map.set->set->key->dtype,
stmt->map.set->set->key->len,
stmt->map.set->set->key->byteorder,
diff --git a/tests/shell/testcases/maps/dumps/typeof_maps_concat.nft b/tests/shell/testcases/maps/dumps/typeof_maps_concat.nft
new file mode 100644
index 0000000..1ca98d8
--- /dev/null
+++ b/tests/shell/testcases/maps/dumps/typeof_maps_concat.nft
@@ -0,0 +1,11 @@
+table netdev t {
+ map m {
+ typeof ether saddr . vlan id : meta mark
+ size 1234
+ flags dynamic,timeout
+ }
+
+ chain c {
+ ether type != 8021q update @m { ether daddr . 123 timeout 1m : 0x0000002a } counter packets 0 bytes 0 return
+ }
+}
diff --git a/tests/shell/testcases/maps/typeof_maps_concat b/tests/shell/testcases/maps/typeof_maps_concat
new file mode 100755
index 0000000..07820b7
--- /dev/null
+++ b/tests/shell/testcases/maps/typeof_maps_concat
@@ -0,0 +1,6 @@
+#!/bin/bash
+
+set -e
+dumpfile=$(dirname $0)/dumps/$(basename $0).nft
+
+$NFT -f "$dumpfile"
diff --git a/tests/shell/testcases/sets/dumps/typeof_sets_concat.nft b/tests/shell/testcases/sets/dumps/typeof_sets_concat.nft
new file mode 100644
index 0000000..dbaf7cd
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/typeof_sets_concat.nft
@@ -0,0 +1,12 @@
+table netdev t {
+ set s {
+ typeof ether saddr . vlan id
+ size 2048
+ flags dynamic,timeout
+ }
+
+ chain c {
+ ether type != 8021q add @s { ether saddr . 0 timeout 5s } counter packets 0 bytes 0 return
+ ether type != 8021q update @s { ether daddr . 123 timeout 1m } counter packets 0 bytes 0 return
+ }
+}
diff --git a/tests/shell/testcases/sets/typeof_sets_concat b/tests/shell/testcases/sets/typeof_sets_concat
new file mode 100755
index 0000000..07820b7
--- /dev/null
+++ b/tests/shell/testcases/sets/typeof_sets_concat
@@ -0,0 +1,6 @@
+#!/bin/bash
+
+set -e
+dumpfile=$(dirname $0)/dumps/$(basename $0).nft
+
+$NFT -f "$dumpfile"
--
2.39.1

View File

@ -0,0 +1,107 @@
From ef0f28bc8efdc5292ceb593c9c5a646f030e0994 Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Thu, 9 Feb 2023 15:25:37 +0100
Subject: [PATCH] monitor: Sanitize startup race condition
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2130721
Upstream Status: nftables commit 545edb7a8ef0a
commit 545edb7a8ef0a8acf991b1b7857fddc24d7b151a
Author: Phil Sutter <phil@nwl.cc>
Date: Wed Sep 28 23:26:42 2022 +0200
monitor: Sanitize startup race condition
During startup, 'nft monitor' first fetches the current ruleset and then
keeps this cache up to date based on received events. This is racey, as
any ruleset changes in between the initial fetch and the socket opening
are not recognized.
This script demonstrates the problem:
| #!/bin/bash
|
| while true; do
| nft flush ruleset
| iptables-nft -A FORWARD
| done &
| maniploop=$!
|
| trap "kill $maniploop; kill \$!; wait" EXIT
|
| while true; do
| nft monitor rules >/dev/null &
| sleep 0.2
| kill $!
| done
If the table add event is missed, the rule add event callback fails to
deserialize the rule and calls abort().
Avoid the inconvenient program exit by returning NULL from
netlink_delinearize_rule() instead of aborting and make callers check
the return value.
Signed-off-by: Phil Sutter <phil@nwl.cc>
Signed-off-by: Phil Sutter <psutter@redhat.com>
---
src/cache.c | 1 +
src/monitor.c | 5 +++++
src/netlink_delinearize.c | 5 ++++-
3 files changed, 10 insertions(+), 1 deletion(-)
diff --git a/src/cache.c b/src/cache.c
index fd8df88..701aec6 100644
--- a/src/cache.c
+++ b/src/cache.c
@@ -490,6 +490,7 @@ static int list_rule_cb(struct nftnl_rule *nlr, void *data)
netlink_dump_rule(nlr, ctx);
rule = netlink_delinearize_rule(ctx, nlr);
+ assert(rule);
list_add_tail(&rule->list, &ctx->list);
return 0;
diff --git a/src/monitor.c b/src/monitor.c
index 7fa92eb..a6b30a1 100644
--- a/src/monitor.c
+++ b/src/monitor.c
@@ -551,6 +551,10 @@ static int netlink_events_rule_cb(const struct nlmsghdr *nlh, int type,
nlr = netlink_rule_alloc(nlh);
r = netlink_delinearize_rule(monh->ctx, nlr);
+ if (!r) {
+ fprintf(stderr, "W: Received event for an unknown table.\n");
+ goto out_free_nlr;
+ }
nlr_for_each_set(nlr, rule_map_decompose_cb, NULL,
&monh->ctx->nft->cache);
cmd = netlink_msg2cmd(type, nlh->nlmsg_flags);
@@ -587,6 +591,7 @@ static int netlink_events_rule_cb(const struct nlmsghdr *nlh, int type,
break;
}
rule_free(r);
+out_free_nlr:
nftnl_rule_free(nlr);
return MNL_CB_OK;
}
diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c
index c6ad84d..1d47c74 100644
--- a/src/netlink_delinearize.c
+++ b/src/netlink_delinearize.c
@@ -3194,7 +3194,10 @@ struct rule *netlink_delinearize_rule(struct netlink_ctx *ctx,
pctx->rule = rule_alloc(&netlink_location, &h);
pctx->table = table_cache_find(&ctx->nft->cache.table_cache,
h.table.name, h.family);
- assert(pctx->table != NULL);
+ if (!pctx->table) {
+ errno = ENOENT;
+ return NULL;
+ }
pctx->rule->comment = nftnl_rule_get_comment(nlr);
--
2.39.1

View File

@ -307,7 +307,10 @@ bridge/vlan.t: ERROR: line 40: add rule netdev test-netdev egress ether type 802
bridge/vlan.t: ERROR: line 41: add rule netdev test-netdev egress ether type 8021ad vlan id 1 vlan type 8021q vlan id 2 vlan type ip counter: This rule should not have failed.
bridge/vlan.t: ERROR: line 42: add rule netdev test-netdev egress ether type 8021ad vlan id 1 vlan type 8021q vlan id 2 vlan type ip ip protocol 6: This rule should not have failed.
bridge/vlan.t: ERROR: line 49: add rule netdev test-netdev egress vlan id 1 vlan id set 2: This rule should not have failed.
bridge/vlan.t: ERROR: line 49: The chain egress does not exist in netdev test-netdev. I cannot delete it.
bridge/vlan.t: ERROR: line 51: add rule netdev test-netdev egress ether saddr 00:01:02:03:04:05 vlan id 1: This rule should not have failed.
bridge/vlan.t: ERROR: line 52: add rule netdev test-netdev egress vlan id 2 ether saddr 0:1:2:3:4:6: This rule should not have failed.
bridge/vlan.t: ERROR: line 54: add rule netdev test-netdev egress ether saddr . vlan id { 0a:0b:0c:0d:0e:0f . 42, 0a:0b:0c:0d:0e:0f . 4095 }: This rule should not have failed.
bridge/vlan.t: ERROR: line 54: The chain egress does not exist in netdev test-netdev. I cannot delete it.
inet/dccp.t: ERROR: line 3: I cannot create the chain 'egress'
inet/dccp.t: ERROR: line 10: add rule netdev test-netdev egress dccp sport 21-35: This rule should not have failed.
inet/dccp.t: ERROR: line 11: add rule netdev test-netdev egress dccp sport != 21-35: This rule should not have failed.

View File

@ -1,5 +1,5 @@
%define rpmversion 1.0.4
%define specrelease 7
%define specrelease 8
Name: nftables
Version: %{rpmversion}
@ -24,6 +24,22 @@ Patch2: 0002-rule-collapse-set-element-commands.patch
Patch3: 0003-intervals-do-not-report-exact-overlaps-for-new-eleme.patch
Patch4: 0004-intervals-do-not-empty-cache-for-maps.patch
Patch5: 0005-intervals-Do-not-sort-cached-set-elements-over-and-o.patch
Patch6: 0006-doc-Document-limitations-of-ipsec-expression-with-xf.patch
Patch7: 0007-tests-py-Add-a-test-for-failing-ipsec-after-counter.patch
Patch8: 0008-parser-add-missing-synproxy-scope-closure.patch
Patch9: 0009-scanner-don-t-pop-active-flex-scanner-scope.patch
Patch10: 0010-intervals-fix-crash-when-trying-to-remove-element-in.patch
Patch11: 0011-intervals-check-for-EXPR_F_REMOVE-in-case-of-element.patch
Patch12: 0012-netlink_delinearize-allow-postprocessing-on-concaten.patch
Patch13: 0013-netlink_delinearize-postprocess-binary-ands-in-conca.patch
Patch14: 0014-proto-track-full-stack-of-seen-l2-protocols-not-just.patch
Patch15: 0015-debug-dump-the-l2-protocol-stack.patch
Patch16: 0016-tests-add-a-test-case-for-ether-and-vlan-listing.patch
Patch17: 0017-netlink_delinearize-also-postprocess-OP_AND-in-set-e.patch
Patch18: 0018-evaluate-search-stacked-header-list-for-matching-pay.patch
Patch19: 0019-src-allow-anon-set-concatenation-with-ether-and-vlan.patch
Patch20: 0020-evaluate-set-eval-ctx-for-add-update-statements-with.patch
Patch21: 0021-monitor-Sanitize-startup-race-condition.patch
BuildRequires: autoconf
BuildRequires: automake
@ -135,6 +151,24 @@ sed -i -e 's/\(sofile=\)".*"/\1"'$sofile'"/' \
%{python3_sitelib}/nftables/
%changelog
* Thu Feb 09 2023 Phil Sutter <psutter@redhat.com> [1.0.4-8.el9]
- monitor: Sanitize startup race condition (Phil Sutter) [2130721]
- evaluate: set eval ctx for add/update statements with integer constants (Phil Sutter) [2094894]
- src: allow anon set concatenation with ether and vlan (Phil Sutter) [2094887]
- evaluate: search stacked header list for matching payload dep (Phil Sutter) [2094887]
- netlink_delinearize: also postprocess OP_AND in set element context (Phil Sutter) [2094887]
- tests: add a test case for ether and vlan listing (Phil Sutter) [2094887]
- debug: dump the l2 protocol stack (Phil Sutter) [2094887]
- proto: track full stack of seen l2 protocols, not just cumulative offset (Phil Sutter) [2094887]
- netlink_delinearize: postprocess binary ands in concatenations (Phil Sutter) [2094887]
- netlink_delinearize: allow postprocessing on concatenated elements (Phil Sutter) [2094887]
- intervals: check for EXPR_F_REMOVE in case of element mismatch (Phil Sutter) [2115627]
- intervals: fix crash when trying to remove element in empty set (Phil Sutter) [2115627]
- scanner: don't pop active flex scanner scope (Phil Sutter) [2113874]
- parser: add missing synproxy scope closure (Phil Sutter) [2113874]
- tests/py: Add a test for failing ipsec after counter (Phil Sutter) [2113874]
- doc: Document limitations of ipsec expression with xfrm_interface (Phil Sutter) [1806431]
* Tue Jan 31 2023 Phil Sutter <psutter@redhat.com> [1.0.4-7.el9]
- One more attempt at fixing expected error records (Phil Sutter) [1973687]

View File

@ -1,6 +1,7 @@
W: [FAILED] ././tests/shell/testcases/cache/0010_implicit_chain_0
W: [FAILED] ././tests/shell/testcases/chains/0021prio_0
W: [FAILED] ././tests/shell/testcases/chains/0041chain_binding_0
W: [FAILED] ././tests/shell/testcases/maps/typeof_integer_0
W: [FAILED] ././tests/shell/testcases/maps/typeof_raw_0
W: [FAILED] ././tests/shell/testcases/sets/typeof_raw_0
W: [FAILED] ././tests/shell/testcases/cache/0010_implicit_chain_0
W: [FAILED] ././tests/shell/testcases/chains/0021prio_0
W: [FAILED] ././tests/shell/testcases/chains/0041chain_binding_0
W: [FAILED] ././tests/shell/testcases/maps/typeof_integer_0
W: [DUMP FAIL] ././tests/shell/testcases/maps/typeof_maps_concat
W: [FAILED] ././tests/shell/testcases/maps/typeof_raw_0
W: [FAILED] ././tests/shell/testcases/sets/typeof_raw_0