diff options
author | Pablo Neira Ayuso <pablo@netfilter.org> | 2023-09-26 10:02:23 +0200 |
---|---|---|
committer | Pablo Neira Ayuso <pablo@netfilter.org> | 2023-09-27 10:58:16 +0200 |
commit | 27a2da23d5085cfa3765fb5172e93d9eb060e7df (patch) | |
tree | cd3e70e8031ca4d18b90a6b0787c56dc9c4377ad /src | |
parent | 57f5aca0006ebf984ffc1f66d48cf3b74a3d1f59 (diff) |
netlink_linearize: skip set element expression in map statement key
This fix is similar to 22d201010919 ("netlink_linearize: skip set element
expression in set statement key") to fix map statement.
netlink_gen_map_stmt() relies on the map key, that is expressed as a set
element. Use the set element key instead to skip the set element wrap,
otherwise get_register() abort execution:
nft: netlink_linearize.c:650: netlink_gen_expr: Assertion `dreg < ctx->reg_low' failed.
This includes JSON support to make this feature complete and it updates
tests/shell to cover for this support.
Reported-by: Luci Stanescu <luci@cnix.ro>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Diffstat (limited to 'src')
-rw-r--r-- | src/json.c | 19 | ||||
-rw-r--r-- | src/netlink_linearize.c | 6 | ||||
-rw-r--r-- | src/parser_json.c | 58 | ||||
-rw-r--r-- | src/statement.c | 1 |
4 files changed, 81 insertions, 3 deletions
@@ -1520,6 +1520,25 @@ json_t *set_stmt_json(const struct stmt *stmt, struct output_ctx *octx) return json_pack("{s:o}", "set", root); } +json_t *map_stmt_json(const struct stmt *stmt, struct output_ctx *octx) +{ + json_t *root; + + root = json_pack("{s:s, s:o, s:o, s:s+}", + "op", set_stmt_op_names[stmt->map.op], + "elem", expr_print_json(stmt->map.key, octx), + "data", expr_print_json(stmt->map.data, octx), + "map", "@", stmt->map.set->set->handle.set.name); + + if (!list_empty(&stmt->map.stmt_list)) { + json_object_set_new(root, "stmt", + set_stmt_list_json(&stmt->map.stmt_list, + octx)); + } + + return json_pack("{s:o}", "map", root); +} + json_t *objref_stmt_json(const struct stmt *stmt, struct output_ctx *octx) { const char *name; diff --git a/src/netlink_linearize.c b/src/netlink_linearize.c index 53a318aa..c9121158 100644 --- a/src/netlink_linearize.c +++ b/src/netlink_linearize.c @@ -1585,13 +1585,13 @@ static void netlink_gen_map_stmt(struct netlink_linearize_ctx *ctx, int num_stmts = 0; struct stmt *this; - sreg_key = get_register(ctx, stmt->map.key); - netlink_gen_expr(ctx, stmt->map.key, sreg_key); + sreg_key = get_register(ctx, stmt->map.key->key); + netlink_gen_expr(ctx, stmt->map.key->key, sreg_key); sreg_data = get_register(ctx, stmt->map.data); netlink_gen_expr(ctx, stmt->map.data, sreg_data); - release_register(ctx, stmt->map.key); + release_register(ctx, stmt->map.key->key); release_register(ctx, stmt->map.data); nle = alloc_nft_expr("dynset"); diff --git a/src/parser_json.c b/src/parser_json.c index 16961d60..f03037af 100644 --- a/src/parser_json.c +++ b/src/parser_json.c @@ -2416,6 +2416,63 @@ static struct stmt *json_parse_set_stmt(struct json_ctx *ctx, return stmt; } +static struct stmt *json_parse_map_stmt(struct json_ctx *ctx, + const char *key, json_t *value) +{ + struct expr *expr, *expr2, *expr_data; + json_t *elem, *data, *stmt_json; + const char *opstr, *set; + struct stmt *stmt; + int op; + + if (json_unpack_err(ctx, value, "{s:s, s:o, s:o, s:s}", + "op", &opstr, "elem", &elem, "data", &data, "map", &set)) + return NULL; + + if (!strcmp(opstr, "add")) { + op = NFT_DYNSET_OP_ADD; + } else if (!strcmp(opstr, "update")) { + op = NFT_DYNSET_OP_UPDATE; + } else if (!strcmp(opstr, "delete")) { + op = NFT_DYNSET_OP_DELETE; + } else { + json_error(ctx, "Unknown map statement op '%s'.", opstr); + return NULL; + } + + expr = json_parse_set_elem_expr_stmt(ctx, elem); + if (!expr) { + json_error(ctx, "Illegal map statement element."); + return NULL; + } + + expr_data = json_parse_set_elem_expr_stmt(ctx, data); + if (!expr_data) { + json_error(ctx, "Illegal map expression data."); + expr_free(expr); + return NULL; + } + + if (set[0] != '@') { + json_error(ctx, "Illegal map reference in map statement."); + expr_free(expr); + expr_free(expr_data); + return NULL; + } + expr2 = symbol_expr_alloc(int_loc, SYMBOL_SET, NULL, set + 1); + + stmt = map_stmt_alloc(int_loc); + stmt->map.op = op; + stmt->map.key = expr; + stmt->map.data = expr_data; + stmt->map.set = expr2; + + if (!json_unpack(value, "{s:o}", "stmt", &stmt_json)) + json_parse_set_stmt_list(ctx, &stmt->set.stmt_list, stmt_json); + + return stmt; +} + static int json_parse_log_flag(struct json_ctx *ctx, json_t *root, int *flags) { @@ -2840,6 +2897,7 @@ static struct stmt *json_parse_stmt(struct json_ctx *ctx, json_t *root) { "redirect", json_parse_nat_stmt }, { "reject", json_parse_reject_stmt }, { "set", json_parse_set_stmt }, + { "map", json_parse_map_stmt }, { "log", json_parse_log_stmt }, { "ct helper", json_parse_cthelper_stmt }, { "ct timeout", json_parse_cttimeout_stmt }, diff --git a/src/statement.c b/src/statement.c index 66424eb4..a9fefc36 100644 --- a/src/statement.c +++ b/src/statement.c @@ -848,6 +848,7 @@ static const struct stmt_ops map_stmt_ops = { .name = "map", .print = map_stmt_print, .destroy = map_stmt_destroy, + .json = map_stmt_json, }; struct stmt *map_stmt_alloc(const struct location *loc) |