summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPablo Neira Ayuso <pablo@netfilter.org>2023-09-16 15:42:48 +0200
committerPablo Neira Ayuso <pablo@netfilter.org>2023-11-03 12:23:37 +0100
commitc6b749958d54ff74af39e0271b5f615dc14f743c (patch)
treef8f8e74173dba9906a41eb323854b1693dfe3c4b
parent672224d14b837b7a875f22d4bed06711947c9387 (diff)
evaluate: expand sets and maps before evaluation
commit 56c90a2dd2eb9cb63a6d74d0f5ce8075bef3895b upstream. 3975430b12d9 ("src: expand table command before evaluation") moved ruleset expansion before evaluation, except for sets and maps. For sets and maps there is still a post_expand() phase. This patch moves sets and map expansion to allocate an independent CMD_OBJ_SETELEMS command to add elements to named set and maps which is evaluated, this consolidates the ruleset expansion to happen always before the evaluation step for all objects, except for anonymous sets and maps. This approach avoids an interference with the set interval code which detects overlaps and merges of adjacents ranges. This set interval routine uses set->init to maintain a cache of existing elements. Then, the post_expand() phase incorrectly expands set->init cache and it triggers a bogus ENOENT errors due to incorrect bytecode (placing element addition before set creation) in combination with user declared sets using the flat syntax notation. Since the evaluation step (coming after the expansion) creates implicit/anonymous sets and maps, those are not expanded anymore. These anonymous sets still need to be evaluated from set_evaluate() path and the netlink bytecode generation path, ie. do_add_set(), needs to deal with anonymous sets. Note that, for named sets, do_add_set() does not use set->init. Such content is part of the existing cache, and the CMD_OBJ_SETELEMS command is responsible for adding elements to named sets. Fixes: 3975430b12d9 ("src: expand table command before evaluation") Reported-by: Jann Haber <jannh@selfnet.de> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
-rw-r--r--src/evaluate.c42
-rw-r--r--src/libnftables.c7
-rw-r--r--src/rule.c23
3 files changed, 32 insertions, 40 deletions
diff --git a/src/evaluate.c b/src/evaluate.c
index f7fdc91d..c183832b 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -4363,6 +4363,29 @@ static int set_expr_evaluate_concat(struct eval_ctx *ctx, struct expr **expr)
return 0;
}
+static int elems_evaluate(struct eval_ctx *ctx, struct set *set)
+{
+ ctx->set = set;
+ if (set->init != NULL) {
+ __expr_set_context(&ctx->ectx, set->key->dtype,
+ set->key->byteorder, set->key->len, 0);
+ if (expr_evaluate(ctx, &set->init) < 0)
+ return -1;
+ if (set->init->etype != EXPR_SET)
+ return expr_error(ctx->msgs, set->init, "Set %s: Unexpected initial type %s, missing { }?",
+ set->handle.set.name, expr_name(set->init));
+ }
+
+ if (set_is_interval(ctx->set->flags) &&
+ !(ctx->set->flags & NFT_SET_CONCAT) &&
+ interval_set_eval(ctx, ctx->set, set->init) < 0)
+ return -1;
+
+ ctx->set = NULL;
+
+ return 0;
+}
+
static int set_evaluate(struct eval_ctx *ctx, struct set *set)
{
struct set *existing_set = NULL;
@@ -4461,23 +4484,6 @@ static int set_evaluate(struct eval_ctx *ctx, struct set *set)
}
set->existing_set = existing_set;
- ctx->set = set;
- if (set->init != NULL) {
- __expr_set_context(&ctx->ectx, set->key->dtype,
- set->key->byteorder, set->key->len, 0);
- if (expr_evaluate(ctx, &set->init) < 0)
- return -1;
- if (set->init->etype != EXPR_SET)
- return expr_error(ctx->msgs, set->init, "Set %s: Unexpected initial type %s, missing { }?",
- set->handle.set.name, expr_name(set->init));
- }
-
- if (set_is_interval(ctx->set->flags) &&
- !(ctx->set->flags & NFT_SET_CONCAT) &&
- interval_set_eval(ctx, ctx->set, set->init) < 0)
- return -1;
-
- ctx->set = NULL;
return 0;
}
@@ -4940,6 +4946,8 @@ static int cmd_evaluate_add(struct eval_ctx *ctx, struct cmd *cmd)
case CMD_OBJ_SET:
handle_merge(&cmd->set->handle, &cmd->handle);
return set_evaluate(ctx, cmd->set);
+ case CMD_OBJ_SETELEMS:
+ return elems_evaluate(ctx, cmd->set);
case CMD_OBJ_RULE:
handle_merge(&cmd->rule->handle, &cmd->handle);
return rule_evaluate(ctx, cmd->rule, cmd->op);
diff --git a/src/libnftables.c b/src/libnftables.c
index 8537d700..b74429d5 100644
--- a/src/libnftables.c
+++ b/src/libnftables.c
@@ -547,13 +547,6 @@ static int nft_evaluate(struct nft_ctx *nft, struct list_head *msgs,
if (err < 0 || nft->state->nerrs)
return -1;
- list_for_each_entry(cmd, cmds, list) {
- if (cmd->op != CMD_ADD)
- continue;
-
- nft_cmd_post_expand(cmd);
- }
-
return 0;
}
diff --git a/src/rule.c b/src/rule.c
index 88bd5656..c4cdfa66 100644
--- a/src/rule.c
+++ b/src/rule.c
@@ -1396,21 +1396,6 @@ void nft_cmd_expand(struct cmd *cmd)
nft_cmd_expand_chain(chain, &new_cmds);
list_splice(&new_cmds, &cmd->list);
break;
- default:
- break;
- }
-}
-
-void nft_cmd_post_expand(struct cmd *cmd)
-{
- struct list_head new_cmds;
- struct set *set;
- struct cmd *new;
- struct handle h;
-
- init_list_head(&new_cmds);
-
- switch (cmd->obj) {
case CMD_OBJ_SET:
case CMD_OBJ_MAP:
set = cmd->set;
@@ -1641,7 +1626,13 @@ static int do_add_set(struct netlink_ctx *ctx, struct cmd *cmd,
return -1;
}
- return mnl_nft_set_add(ctx, cmd, flags);
+ if (mnl_nft_set_add(ctx, cmd, flags) < 0)
+ return -1;
+
+ if (set_is_anonymous(set->flags))
+ return __do_add_elements(ctx, cmd, set, set->init, flags);
+
+ return 0;
}
static int do_command_add(struct netlink_ctx *ctx, struct cmd *cmd, bool excl)