Version in base suite: 0.9.8-3.1+deb11u1 Base version: nftables_0.9.8-3.1+deb11u1 Target version: nftables_0.9.8-3.1+deb11u2 Base file: /srv/ftp-master.debian.org/ftp/pool/main/n/nftables/nftables_0.9.8-3.1+deb11u1.dsc Target file: /srv/ftp-master.debian.org/policy/pool/main/n/nftables/nftables_0.9.8-3.1+deb11u2.dsc changelog | 15 patches/cache-rename-chain_htable-to-cache_chain_ht.patch | 98 ++++ patches/evaluate-init-cmd-pointer-for-new-on-stack-context.patch | 48 ++ patches/rule-add-helper-function-to-expand-chain-rules-into-.patch | 83 ++++ patches/rule-expand-standalone-chain-that-contains-rules.patch | 116 +++++ patches/rule_fix_for_potential_off-by-one_in_cmd_add_loc.patch | 2 patches/series | 6 patches/src-expand-table-command-before-evaluation.patch | 202 ++++++++++ patches/src-split-chain-list-in-table.patch | 188 +++++++++ 9 files changed, 757 insertions(+), 1 deletion(-) diff -Nru nftables-0.9.8/debian/changelog nftables-0.9.8/debian/changelog --- nftables-0.9.8/debian/changelog 2022-09-04 08:34:11.000000000 +0000 +++ nftables-0.9.8/debian/changelog 2023-10-10 20:28:38.000000000 +0000 @@ -1,3 +1,18 @@ +nftables (0.9.8-3.1+deb11u2) bullseye; urgency=medium + + * d/p/rule_fix_for_potential_off-by-one_in_cmd_add_loc.patch: fix fuzz + * Fix incorrect bytecode generation hit with new kernel check that + rejects adding rules to bound chains + + - cache: rename chain_htable to cache_chain_ht + - src: split chain list in table + - evaluate: init cmd pointer for new on-stack context + - rule: add helper function to expand chain rules into commands + - rule: expand standalone chain that contains rules + - src: expand table command before evaluation + + -- Jeremy Sowden Tue, 10 Oct 2023 21:28:38 +0100 + nftables (0.9.8-3.1+deb11u1) bullseye; urgency=medium * d/p/rule_fix_for_potential_off-by-one_in_cmd_add_loc.patch diff -Nru nftables-0.9.8/debian/patches/cache-rename-chain_htable-to-cache_chain_ht.patch nftables-0.9.8/debian/patches/cache-rename-chain_htable-to-cache_chain_ht.patch --- nftables-0.9.8/debian/patches/cache-rename-chain_htable-to-cache_chain_ht.patch 1970-01-01 00:00:00.000000000 +0000 +++ nftables-0.9.8/debian/patches/cache-rename-chain_htable-to-cache_chain_ht.patch 2023-10-10 20:28:38.000000000 +0000 @@ -0,0 +1,98 @@ +From 0a39091a75b6255422832126df4cbf73c86845cd Mon Sep 17 00:00:00 2001 +From: Pablo Neira Ayuso +Date: Thu, 1 Apr 2021 22:18:29 +0200 +Subject: [PATCH nft 0.9.8] cache: rename chain_htable to cache_chain_ht + +upstream 3542e49cf539ecfcef6ef7c2d4befb7896ade2cd commit. + +Rename the hashtable chain that is used for fast cache lookups. + +Signed-off-by: Pablo Neira Ayuso +--- + include/rule.h | 4 ++-- + src/cache.c | 6 +++--- + src/rule.c | 6 +++--- + 3 files changed, 8 insertions(+), 8 deletions(-) + +diff --git a/include/rule.h b/include/rule.h +index 330a09aa77fa..43872db8947a 100644 +--- a/include/rule.h ++++ b/include/rule.h +@@ -154,7 +154,7 @@ struct table { + struct handle handle; + struct location location; + struct scope scope; +- struct list_head *chain_htable; ++ struct list_head *cache_chain_ht; + struct list_head chains; + struct list_head sets; + struct list_head objs; +@@ -220,7 +220,7 @@ struct hook_spec { + */ + struct chain { + struct list_head list; +- struct list_head hlist; ++ struct list_head cache_hlist; + struct handle handle; + struct location location; + unsigned int refcnt; +diff --git a/src/cache.c b/src/cache.c +index ed2609008e22..7101b74160be 100644 +--- a/src/cache.c ++++ b/src/cache.c +@@ -194,7 +194,7 @@ static int chain_cache_cb(struct nftnl_chain *nlc, void *arg) + if (chain->flags & CHAIN_F_BINDING) { + list_add_tail(&chain->list, &ctx->table->chain_bindings); + } else { +- list_add_tail(&chain->hlist, &ctx->table->chain_htable[hash]); ++ list_add_tail(&chain->cache_hlist, &ctx->table->cache_chain_ht[hash]); + list_add_tail(&chain->list, &ctx->table->chains); + } + +@@ -238,7 +238,7 @@ void chain_cache_add(struct chain *chain, struct table *table) + uint32_t hash; + + hash = djb_hash(chain->handle.chain.name) % NFT_CACHE_HSIZE; +- list_add_tail(&chain->hlist, &table->chain_htable[hash]); ++ list_add_tail(&chain->cache_hlist, &table->cache_chain_ht[hash]); + list_add_tail(&chain->list, &table->chains); + } + +@@ -249,7 +249,7 @@ struct chain *chain_cache_find(const struct table *table, + uint32_t hash; + + hash = djb_hash(handle->chain.name) % NFT_CACHE_HSIZE; +- list_for_each_entry(chain, &table->chain_htable[hash], hlist) { ++ list_for_each_entry(chain, &table->cache_chain_ht[hash], cache_hlist) { + if (!strcmp(chain->handle.chain.name, handle->chain.name)) + return chain; + } +diff --git a/src/rule.c b/src/rule.c +index e4bb6bae276a..3b445851f657 100644 +--- a/src/rule.c ++++ b/src/rule.c +@@ -1328,10 +1328,10 @@ struct table *table_alloc(void) + init_list_head(&table->scope.symbols); + table->refcnt = 1; + +- table->chain_htable = ++ table->cache_chain_ht = + xmalloc(sizeof(struct list_head) * NFT_CACHE_HSIZE); + for (i = 0; i < NFT_CACHE_HSIZE; i++) +- init_list_head(&table->chain_htable[i]); ++ init_list_head(&table->cache_chain_ht[i]); + + return table; + } +@@ -1359,7 +1359,7 @@ void table_free(struct table *table) + obj_free(obj); + handle_free(&table->handle); + scope_release(&table->scope); +- xfree(table->chain_htable); ++ xfree(table->cache_chain_ht); + xfree(table); + } + +-- +2.30.2 + diff -Nru nftables-0.9.8/debian/patches/evaluate-init-cmd-pointer-for-new-on-stack-context.patch nftables-0.9.8/debian/patches/evaluate-init-cmd-pointer-for-new-on-stack-context.patch --- nftables-0.9.8/debian/patches/evaluate-init-cmd-pointer-for-new-on-stack-context.patch 1970-01-01 00:00:00.000000000 +0000 +++ nftables-0.9.8/debian/patches/evaluate-init-cmd-pointer-for-new-on-stack-context.patch 2023-10-10 20:28:38.000000000 +0000 @@ -0,0 +1,48 @@ +From 5af65a30a12396281c751e635509ab1d9363f4bc Mon Sep 17 00:00:00 2001 +From: Florian Westphal +Date: Fri, 4 Mar 2022 11:30:55 +0100 +Subject: [PATCH nft 0.9.8] evaluate: init cmd pointer for new on-stack + context + +upstream 4e718641397c876315a87db441afc53139863122 commit + +else, this will segfault when trying to print the +"table 'x' doesn't exist" error message. + +Signed-off-by: Florian Westphal +--- + src/evaluate.c | 1 + + tests/shell/testcases/chains/0041chain_binding_0 | 6 ++++++ + 2 files changed, 7 insertions(+) + +diff --git a/src/evaluate.c b/src/evaluate.c +index c830dcdbd965..f546667131e1 100644 +--- a/src/evaluate.c ++++ b/src/evaluate.c +@@ -3211,6 +3211,7 @@ static int stmt_evaluate_chain(struct eval_ctx *ctx, struct stmt *stmt) + struct eval_ctx rule_ctx = { + .nft = ctx->nft, + .msgs = ctx->msgs, ++ .cmd = ctx->cmd, + }; + struct handle h2 = {}; + +diff --git a/tests/shell/testcases/chains/0041chain_binding_0 b/tests/shell/testcases/chains/0041chain_binding_0 +index 59bdbe9f0ba9..4b541bb55c30 100755 +--- a/tests/shell/testcases/chains/0041chain_binding_0 ++++ b/tests/shell/testcases/chains/0041chain_binding_0 +@@ -1,5 +1,11 @@ + #!/bin/bash + ++# no table x, caused segfault in earlier nft releases ++$NFT insert rule inet x y handle 107 'goto { log prefix "MOO! "; }' ++if [ $? -ne 1 ]; then ++ exit 1 ++fi ++ + set -e + + EXPECTED="table inet x { +-- +2.30.2 + diff -Nru nftables-0.9.8/debian/patches/rule-add-helper-function-to-expand-chain-rules-into-.patch nftables-0.9.8/debian/patches/rule-add-helper-function-to-expand-chain-rules-into-.patch --- nftables-0.9.8/debian/patches/rule-add-helper-function-to-expand-chain-rules-into-.patch 1970-01-01 00:00:00.000000000 +0000 +++ nftables-0.9.8/debian/patches/rule-add-helper-function-to-expand-chain-rules-into-.patch 2023-10-10 20:28:38.000000000 +0000 @@ -0,0 +1,83 @@ +From 0f559011ee7e805df883be635b88396639fbb87e Mon Sep 17 00:00:00 2001 +From: Pablo Neira Ayuso +Date: Tue, 12 Sep 2023 23:22:46 +0200 +Subject: [PATCH nft 0.9.8] rule: add helper function to expand chain rules + into commands + +upstream 784597a4ed63b9decb10d74fdb49a1b021e22728 commit. + +This patch adds a helper function to expand chain rules into commands. +This comes in preparation for the follow up patch. + +Signed-off-by: Pablo Neira Ayuso +--- + src/rule.c | 39 ++++++++++++++++++++++----------------- + 1 file changed, 22 insertions(+), 17 deletions(-) + +diff --git a/src/rule.c b/src/rule.c +index f76c27c9d091..3fbf4271accd 100644 +--- a/src/rule.c ++++ b/src/rule.c +@@ -1503,6 +1503,25 @@ void cmd_add_loc(struct cmd *cmd, uint16_t offset, const struct location *loc) + cmd->num_attrs++; + } + ++static void nft_cmd_expand_chain(struct chain *chain, struct list_head *new_cmds) ++{ ++ struct rule *rule; ++ struct handle h; ++ struct cmd *new; ++ ++ list_for_each_entry(rule, &chain->rules, list) { ++ memset(&h, 0, sizeof(h)); ++ handle_merge(&h, &rule->handle); ++ if (chain->flags & CHAIN_F_BINDING) { ++ rule->handle.chain_id = chain->handle.chain_id; ++ rule->handle.chain.location = chain->location; ++ } ++ new = cmd_alloc(CMD_ADD, CMD_OBJ_RULE, &h, ++ &rule->location, rule_get(rule)); ++ list_add_tail(&new->list, new_cmds); ++ } ++} ++ + void nft_cmd_expand(struct cmd *cmd) + { + struct list_head new_cmds; +@@ -1510,7 +1529,6 @@ void nft_cmd_expand(struct cmd *cmd) + struct flowtable *ft; + struct table *table; + struct chain *chain; +- struct rule *rule; + struct obj *obj; + struct cmd *new; + struct handle h; +@@ -1555,22 +1573,9 @@ void nft_cmd_expand(struct cmd *cmd) + &ft->location, flowtable_get(ft)); + list_add_tail(&new->list, &new_cmds); + } +- list_for_each_entry(chain, &table->chains, list) { +- list_for_each_entry(rule, &chain->rules, list) { +- memset(&h, 0, sizeof(h)); +- handle_merge(&h, &rule->handle); +- if (chain->flags & CHAIN_F_BINDING) { +- rule->handle.chain_id = +- chain->handle.chain_id; +- rule->handle.chain.location = +- chain->location; +- } +- new = cmd_alloc(CMD_ADD, CMD_OBJ_RULE, &h, +- &rule->location, +- rule_get(rule)); +- list_add_tail(&new->list, &new_cmds); +- } +- } ++ list_for_each_entry(chain, &table->chains, list) ++ nft_cmd_expand_chain(chain, &new_cmds); ++ + list_splice(&new_cmds, &cmd->list); + break; + case CMD_OBJ_SET: +-- +2.30.2 + diff -Nru nftables-0.9.8/debian/patches/rule-expand-standalone-chain-that-contains-rules.patch nftables-0.9.8/debian/patches/rule-expand-standalone-chain-that-contains-rules.patch --- nftables-0.9.8/debian/patches/rule-expand-standalone-chain-that-contains-rules.patch 1970-01-01 00:00:00.000000000 +0000 +++ nftables-0.9.8/debian/patches/rule-expand-standalone-chain-that-contains-rules.patch 2023-10-10 20:28:38.000000000 +0000 @@ -0,0 +1,116 @@ +From f03bc399d75ef724fcbed184f74fc306ca8ef324 Mon Sep 17 00:00:00 2001 +From: Pablo Neira Ayuso +Date: Mon, 6 Feb 2023 15:28:41 +0100 +Subject: [PATCH nft 0.9.8] rule: expand standalone chain that contains + rules + +upstream 27c753e4a8d4744f479345e3f5e34cafef751602 commit. + +Otherwise rules that this chain contains are ignored when expressed +using the following syntax: + +chain inet filter input2 { + type filter hook input priority filter; policy accept; + ip saddr 1.2.3.4 tcp dport { 22, 443, 123 } drop +} + +When expanding the chain, remove the rule so the new CMD_OBJ_CHAIN +case does not expand it again. + +Closes: https://bugzilla.netfilter.org/show_bug.cgi?id=1655 +Signed-off-by: Pablo Neira Ayuso +--- + src/rule.c | 15 +++++++++--- + .../testcases/include/0020include_chain_0 | 23 +++++++++++++++++++ + .../include/dumps/0020include_chain_0.nft | 6 +++++ + 3 files changed, 41 insertions(+), 3 deletions(-) + create mode 100755 tests/shell/testcases/include/0020include_chain_0 + create mode 100644 tests/shell/testcases/include/dumps/0020include_chain_0.nft + +diff --git a/src/rule.c b/src/rule.c +index 3fbf4271accd..9139418e1bf8 100644 +--- a/src/rule.c ++++ b/src/rule.c +@@ -1505,11 +1505,12 @@ void cmd_add_loc(struct cmd *cmd, uint16_t offset, const struct location *loc) + + static void nft_cmd_expand_chain(struct chain *chain, struct list_head *new_cmds) + { +- struct rule *rule; ++ struct rule *rule, *next; + struct handle h; + struct cmd *new; + +- list_for_each_entry(rule, &chain->rules, list) { ++ list_for_each_entry_safe(rule, next, &chain->rules, list) { ++ list_del(&rule->list); + memset(&h, 0, sizeof(h)); + handle_merge(&h, &rule->handle); + if (chain->flags & CHAIN_F_BINDING) { +@@ -1517,7 +1518,7 @@ static void nft_cmd_expand_chain(struct chain *chain, struct list_head *new_cmds + rule->handle.chain.location = chain->location; + } + new = cmd_alloc(CMD_ADD, CMD_OBJ_RULE, &h, +- &rule->location, rule_get(rule)); ++ &rule->location, rule); + list_add_tail(&new->list, new_cmds); + } + } +@@ -1578,6 +1579,14 @@ void nft_cmd_expand(struct cmd *cmd) + + list_splice(&new_cmds, &cmd->list); + break; ++ case CMD_OBJ_CHAIN: ++ chain = cmd->chain; ++ if (!chain || list_empty(&chain->rules)) ++ break; ++ ++ nft_cmd_expand_chain(chain, &new_cmds); ++ list_splice(&new_cmds, &cmd->list); ++ break; + case CMD_OBJ_SET: + case CMD_OBJ_MAP: + set = cmd->set; +diff --git a/tests/shell/testcases/include/0020include_chain_0 b/tests/shell/testcases/include/0020include_chain_0 +new file mode 100755 +index 000000000000..2ff83c92fda8 +--- /dev/null ++++ b/tests/shell/testcases/include/0020include_chain_0 +@@ -0,0 +1,23 @@ ++#!/bin/bash ++ ++set -e ++ ++tmpfile1=$(mktemp -p .) ++if [ ! -w $tmpfile1 ] ; then ++ echo "Failed to create tmp file" >&2 ++ exit 0 ++fi ++ ++trap "rm -rf $tmpfile1" EXIT # cleanup if aborted ++ ++RULESET="table inet filter { } ++include \"$tmpfile1\"" ++ ++RULESET2="chain inet filter input2 { ++ type filter hook input priority filter; policy accept; ++ ip saddr 1.2.3.4 tcp dport { 22, 443, 123 } drop ++}" ++ ++echo "$RULESET2" > $tmpfile1 ++ ++$NFT -f - <<< $RULESET +diff --git a/tests/shell/testcases/include/dumps/0020include_chain_0.nft b/tests/shell/testcases/include/dumps/0020include_chain_0.nft +new file mode 100644 +index 000000000000..3ad6db14d2f5 +--- /dev/null ++++ b/tests/shell/testcases/include/dumps/0020include_chain_0.nft +@@ -0,0 +1,6 @@ ++table inet filter { ++ chain input2 { ++ type filter hook input priority filter; policy accept; ++ ip saddr 1.2.3.4 tcp dport { 22, 123, 443 } drop ++ } ++} +-- +2.30.2 + diff -Nru nftables-0.9.8/debian/patches/rule_fix_for_potential_off-by-one_in_cmd_add_loc.patch nftables-0.9.8/debian/patches/rule_fix_for_potential_off-by-one_in_cmd_add_loc.patch --- nftables-0.9.8/debian/patches/rule_fix_for_potential_off-by-one_in_cmd_add_loc.patch 2022-09-04 08:34:11.000000000 +0000 +++ nftables-0.9.8/debian/patches/rule_fix_for_potential_off-by-one_in_cmd_add_loc.patch 2023-10-10 20:28:38.000000000 +0000 @@ -18,7 +18,7 @@ index dbbe744e..92daf2f3 100644 --- a/src/rule.c +++ b/src/rule.c -@@ -1275,7 +1275,7 @@ struct cmd *cmd_alloc(enum cmd_ops op, enum cmd_obj obj, +@@ -1491,7 +1491,7 @@ struct cmd *cmd_alloc(enum cmd_ops op, enum cmd_obj obj, void cmd_add_loc(struct cmd *cmd, uint16_t offset, const struct location *loc) { diff -Nru nftables-0.9.8/debian/patches/series nftables-0.9.8/debian/patches/series --- nftables-0.9.8/debian/patches/series 2022-09-04 08:34:11.000000000 +0000 +++ nftables-0.9.8/debian/patches/series 2023-10-10 20:28:38.000000000 +0000 @@ -1,2 +1,8 @@ payload-check-icmp-dependency-before-removing-previo.patch rule_fix_for_potential_off-by-one_in_cmd_add_loc.patch +cache-rename-chain_htable-to-cache_chain_ht.patch +src-split-chain-list-in-table.patch +evaluate-init-cmd-pointer-for-new-on-stack-context.patch +rule-add-helper-function-to-expand-chain-rules-into-.patch +rule-expand-standalone-chain-that-contains-rules.patch +src-expand-table-command-before-evaluation.patch diff -Nru nftables-0.9.8/debian/patches/src-expand-table-command-before-evaluation.patch nftables-0.9.8/debian/patches/src-expand-table-command-before-evaluation.patch --- nftables-0.9.8/debian/patches/src-expand-table-command-before-evaluation.patch 1970-01-01 00:00:00.000000000 +0000 +++ nftables-0.9.8/debian/patches/src-expand-table-command-before-evaluation.patch 2023-10-10 20:28:38.000000000 +0000 @@ -0,0 +1,202 @@ +From 050e0b7a85016b733e1a59285df501d1c05eec0b Mon Sep 17 00:00:00 2001 +From: Pablo Neira Ayuso +Date: Tue, 12 Sep 2023 23:25:27 +0200 +Subject: [PATCH nft 0.9.8] src: expand table command before evaluation + +upstream 3975430b12d97c92cdf03753342f2269153d5624 commit. + +The nested syntax notation results in one single table command which +includes all other objects. This differs from the flat notation where +there is usually one command per object. + +This patch adds a previous step to the evaluation phase to expand the +objects that are contained in the table into independent commands, so +both notations have similar representations. + +Remove the code to evaluate the nested representation in the evaluation +phase since commands are independently evaluated after the expansion. + +The commands are expanded after the set element collapse step, in case +that there is a long list of singleton element commands to be added to +the set, to shorten the command list iteration. + +This approach also avoids interference with the object cache that is +populated in the evaluation, which might refer to objects coming in the +existing command list that is being processed. + +There is still a post_expand phase to detach the elements from the set +which could be consolidated by updating the evaluation step to handle +the CMD_OBJ_SETELEMS command type. + +This patch fixes 27c753e4a8d4 ("rule: expand standalone chain that +contains rules") which broke rule addition/insertion by index because +the expansion code after the evaluation messes up the cache. + +Fixes: 27c753e4a8d4 ("rule: expand standalone chain that contains rules") +Signed-off-by: Pablo Neira Ayuso +--- + include/rule.h | 1 + + src/evaluate.c | 39 --------------------------------------- + src/libnftables.c | 9 ++++++++- + src/rule.c | 21 +++++++++++++++++++-- + 4 files changed, 28 insertions(+), 42 deletions(-) + +--- a/include/rule.h ++++ b/include/rule.h +@@ -717,6 +717,7 @@ + const struct handle *h, const struct location *loc, + void *data); + extern void nft_cmd_expand(struct cmd *cmd); ++extern void nft_cmd_post_expand(struct cmd *cmd); + extern struct cmd *cmd_alloc_obj_ct(enum cmd_ops op, int type, + const struct handle *h, + const struct location *loc, struct obj *obj); +--- a/src/evaluate.c ++++ b/src/evaluate.c +@@ -4067,7 +4067,6 @@ + static int chain_evaluate(struct eval_ctx *ctx, struct chain *chain) + { + struct table *table; +- struct rule *rule; + + table = table_lookup_global(ctx); + if (table == NULL) +@@ -4121,11 +4120,6 @@ + } + } + +- list_for_each_entry(rule, &chain->rules, list) { +- handle_merge(&rule->handle, &chain->handle); +- if (rule_evaluate(ctx, rule, CMD_INVALID) < 0) +- return -1; +- } + return 0; + } + +@@ -4182,11 +4176,6 @@ + + static int table_evaluate(struct eval_ctx *ctx, struct table *table) + { +- struct flowtable *ft; +- struct chain *chain; +- struct set *set; +- struct obj *obj; +- + if (table_lookup(&ctx->cmd->handle, &ctx->nft->cache) == NULL) { + if (table == NULL) { + table = table_alloc(); +@@ -4197,34 +4186,6 @@ + } + } + +- if (ctx->cmd->table == NULL) +- return 0; +- +- ctx->table = table; +- list_for_each_entry(set, &table->sets, list) { +- expr_set_context(&ctx->ectx, NULL, 0); +- handle_merge(&set->handle, &table->handle); +- if (set_evaluate(ctx, set) < 0) +- return -1; +- } +- list_for_each_entry(chain, &table->chains, list) { +- handle_merge(&chain->handle, &table->handle); +- ctx->cmd->handle.chain.location = chain->location; +- if (chain_evaluate(ctx, chain) < 0) +- return -1; +- } +- list_for_each_entry(ft, &table->flowtables, list) { +- handle_merge(&ft->handle, &table->handle); +- if (flowtable_evaluate(ctx, ft) < 0) +- return -1; +- } +- list_for_each_entry(obj, &table->objs, list) { +- handle_merge(&obj->handle, &table->handle); +- if (obj_evaluate(ctx, obj) < 0) +- return -1; +- } +- +- ctx->table = NULL; + return 0; + } + +--- a/src/libnftables.c ++++ b/src/libnftables.c +@@ -421,6 +421,13 @@ + return -1; + + list_for_each_entry(cmd, cmds, list) { ++ if (cmd->op != CMD_ADD) ++ continue; ++ ++ nft_cmd_expand(cmd); ++ } ++ ++ list_for_each_entry(cmd, cmds, list) { + struct eval_ctx ectx = { + .nft = nft, + .msgs = msgs, +@@ -437,7 +444,7 @@ + if (cmd->op != CMD_ADD) + continue; + +- nft_cmd_expand(cmd); ++ nft_cmd_post_expand(cmd); + } + + return 0; +--- a/src/rule.c ++++ b/src/rule.c +@@ -1511,8 +1511,9 @@ + + list_for_each_entry_safe(rule, next, &chain->rules, list) { + list_del(&rule->list); ++ handle_merge(&rule->handle, &chain->handle); + memset(&h, 0, sizeof(h)); +- handle_merge(&h, &rule->handle); ++ handle_merge(&h, &chain->handle); + if (chain->flags & CHAIN_F_BINDING) { + rule->handle.chain_id = chain->handle.chain_id; + rule->handle.chain.location = chain->location; +@@ -1526,10 +1527,10 @@ + void nft_cmd_expand(struct cmd *cmd) + { + struct list_head new_cmds; +- struct set *set, *newset; + struct flowtable *ft; + struct table *table; + struct chain *chain; ++ struct set *set; + struct obj *obj; + struct cmd *new; + struct handle h; +@@ -1543,6 +1544,7 @@ + return; + + list_for_each_entry(chain, &table->chains, list) { ++ handle_merge(&chain->handle, &table->handle); + memset(&h, 0, sizeof(h)); + handle_merge(&h, &chain->handle); + h.chain_id = chain->handle.chain_id; +@@ -1587,6 +1589,21 @@ + 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, *newset; ++ 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; diff -Nru nftables-0.9.8/debian/patches/src-split-chain-list-in-table.patch nftables-0.9.8/debian/patches/src-split-chain-list-in-table.patch --- nftables-0.9.8/debian/patches/src-split-chain-list-in-table.patch 1970-01-01 00:00:00.000000000 +0000 +++ nftables-0.9.8/debian/patches/src-split-chain-list-in-table.patch 2023-10-10 20:28:38.000000000 +0000 @@ -0,0 +1,188 @@ +From f37e4261130b021edf068e4d5c6ca062ce4e2ac1 Mon Sep 17 00:00:00 2001 +From: Pablo Neira Ayuso +Date: Thu, 1 Apr 2021 22:19:30 +0200 +Subject: [PATCH nft 0.9.8] src: split chain list in table + +upstream a3ac2527724dd27628e12caaa55f731b109e4586 commit. + +This patch splits table->lists in two: + +- Chains that reside in the cache are stored in the new + tables->cache_chain and tables->cache_chain_ht. The hashtable chain + cache allows for fast chain lookups. + +- Chains that defined via command line / ruleset file reside in + tables->chains. + +Note that chains in the cache (already in the kernel) are not placed in +the table->chains. + +By keeping separated lists, chains defined via command line / ruleset +file can be added to cache. + +Signed-off-by: Pablo Neira Ayuso +--- + include/rule.h | 2 ++ + src/cache.c | 6 +++--- + src/json.c | 6 +++--- + src/rule.c | 18 +++++++++++------- + 4 files changed, 19 insertions(+), 13 deletions(-) + +diff --git a/include/rule.h b/include/rule.h +index 43872db8947a..dde32367f48f 100644 +--- a/include/rule.h ++++ b/include/rule.h +@@ -155,6 +155,7 @@ struct table { + struct location location; + struct scope scope; + struct list_head *cache_chain_ht; ++ struct list_head cache_chain; + struct list_head chains; + struct list_head sets; + struct list_head objs; +@@ -221,6 +222,7 @@ struct hook_spec { + struct chain { + struct list_head list; + struct list_head cache_hlist; ++ struct list_head cache_list; + struct handle handle; + struct location location; + unsigned int refcnt; +diff --git a/src/cache.c b/src/cache.c +index 7101b74160be..32e6eea4ac5c 100644 +--- a/src/cache.c ++++ b/src/cache.c +@@ -192,10 +192,10 @@ static int chain_cache_cb(struct nftnl_chain *nlc, void *arg) + chain = netlink_delinearize_chain(ctx->nlctx, nlc); + + if (chain->flags & CHAIN_F_BINDING) { +- list_add_tail(&chain->list, &ctx->table->chain_bindings); ++ list_add_tail(&chain->cache_list, &ctx->table->chain_bindings); + } else { + list_add_tail(&chain->cache_hlist, &ctx->table->cache_chain_ht[hash]); +- list_add_tail(&chain->list, &ctx->table->chains); ++ list_add_tail(&chain->cache_list, &ctx->table->cache_chain); + } + + nftnl_chain_list_del(nlc); +@@ -239,7 +239,7 @@ void chain_cache_add(struct chain *chain, struct table *table) + + hash = djb_hash(chain->handle.chain.name) % NFT_CACHE_HSIZE; + list_add_tail(&chain->cache_hlist, &table->cache_chain_ht[hash]); +- list_add_tail(&chain->list, &table->chains); ++ list_add_tail(&chain->cache_list, &table->cache_chain); + } + + struct chain *chain_cache_find(const struct table *table, +diff --git a/src/json.c b/src/json.c +index 585d35326ac0..737e73b08b5a 100644 +--- a/src/json.c ++++ b/src/json.c +@@ -1594,7 +1594,7 @@ static json_t *table_print_json_full(struct netlink_ctx *ctx, + tmp = flowtable_print_json(flowtable); + json_array_append_new(root, tmp); + } +- list_for_each_entry(chain, &table->chains, list) { ++ list_for_each_entry(chain, &table->cache_chain, cache_list) { + tmp = chain_print_json(chain); + json_array_append_new(root, tmp); + +@@ -1656,7 +1656,7 @@ static json_t *do_list_chain_json(struct netlink_ctx *ctx, + struct chain *chain; + struct rule *rule; + +- list_for_each_entry(chain, &table->chains, list) { ++ list_for_each_entry(chain, &table->cache_chain, cache_list) { + if (chain->handle.family != cmd->handle.family || + strcmp(cmd->handle.chain.name, chain->handle.chain.name)) + continue; +@@ -1684,7 +1684,7 @@ static json_t *do_list_chains_json(struct netlink_ctx *ctx, struct cmd *cmd) + cmd->handle.family != table->handle.family) + continue; + +- list_for_each_entry(chain, &table->chains, list) { ++ list_for_each_entry(chain, &table->cache_chain, cache_list) { + json_t *tmp = chain_print_json(chain); + + json_array_append_new(root, tmp); +diff --git a/src/rule.c b/src/rule.c +index 3b445851f657..f76c27c9d091 100644 +--- a/src/rule.c ++++ b/src/rule.c +@@ -953,7 +953,7 @@ struct chain *chain_lookup(const struct table *table, const struct handle *h) + { + struct chain *chain; + +- list_for_each_entry(chain, &table->chains, list) { ++ list_for_each_entry(chain, &table->cache_chain, cache_list) { + if (!strcmp(chain->handle.chain.name, h->chain.name)) + return chain; + } +@@ -965,7 +965,7 @@ struct chain *chain_binding_lookup(const struct table *table, + { + struct chain *chain; + +- list_for_each_entry(chain, &table->chain_bindings, list) { ++ list_for_each_entry(chain, &table->chain_bindings, cache_list) { + if (!strcmp(chain->handle.chain.name, chain_name)) + return chain; + } +@@ -983,7 +983,7 @@ struct chain *chain_lookup_fuzzy(const struct handle *h, + string_misspell_init(&st); + + list_for_each_entry(table, &cache->list, list) { +- list_for_each_entry(chain, &table->chains, list) { ++ list_for_each_entry(chain, &table->cache_chain, cache_list) { + if (!strcmp(chain->handle.chain.name, h->chain.name)) { + *t = table; + return chain; +@@ -1321,6 +1321,7 @@ struct table *table_alloc(void) + + table = xzalloc(sizeof(*table)); + init_list_head(&table->chains); ++ init_list_head(&table->cache_chain); + init_list_head(&table->sets); + init_list_head(&table->objs); + init_list_head(&table->flowtables); +@@ -1349,7 +1350,10 @@ void table_free(struct table *table) + xfree(table->comment); + list_for_each_entry_safe(chain, next, &table->chains, list) + chain_free(chain); +- list_for_each_entry_safe(chain, next, &table->chain_bindings, list) ++ list_for_each_entry_safe(chain, next, &table->chain_bindings, cache_list) ++ chain_free(chain); ++ /* this is implicitly releasing chains in the hashtable cache */ ++ list_for_each_entry_safe(chain, next, &table->cache_chain, cache_list) + chain_free(chain); + list_for_each_entry_safe(set, nset, &table->sets, list) + set_free(set); +@@ -1465,7 +1469,7 @@ static void table_print(const struct table *table, struct output_ctx *octx) + flowtable_print(flowtable, octx); + delim = "\n"; + } +- list_for_each_entry(chain, &table->chains, list) { ++ list_for_each_entry(chain, &table->cache_chain, cache_list) { + nft_print(octx, "%s", delim); + chain_print(chain, octx); + delim = "\n"; +@@ -2555,7 +2559,7 @@ static int do_list_chain(struct netlink_ctx *ctx, struct cmd *cmd, + + table_print_declaration(table, &ctx->nft->output); + +- list_for_each_entry(chain, &table->chains, list) { ++ list_for_each_entry(chain, &table->cache_chain, cache_list) { + if (chain->handle.family != cmd->handle.family || + strcmp(cmd->handle.chain.name, chain->handle.chain.name) != 0) + continue; +@@ -2580,7 +2584,7 @@ static int do_list_chains(struct netlink_ctx *ctx, struct cmd *cmd) + + table_print_declaration(table, &ctx->nft->output); + +- list_for_each_entry(chain, &table->chains, list) { ++ list_for_each_entry(chain, &table->cache_chain, cache_list) { + chain_print_declaration(chain, &ctx->nft->output); + nft_print(&ctx->nft->output, "\t}\n"); + } +-- +2.30.2 +