Updating a table with the same flags more than once in single transaction failed if its previous flags is different from the new one. For example, the 2nd transaction below would fail: nft -f -<<EOF add table ip t { flags dormant ; } EOF nft -f -<<EOF add table ip t add chain ip t c1 { type filter hook input priority 1; } add table ip t add chain ip t c2 { type filter hook input priority 2; } EOF This was because nf_tables_updtable rejected all further updates made to a table after it was updated once, even though they are consistent with the first update. The intent of the check should be to reject dormant off/on/off games, the patch fixes the check to allow consitent updates. Fixes: c9bd26513b3a ("netfilter: nf_tables: disable toggling dormant table state more than once") Signed-off-by: Quan Tian <tianquan23@xxxxxxxxx> --- net/netfilter/nf_tables_api.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c index e93f905e60b6..8bad5dd427da 100644 --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c @@ -1225,24 +1225,25 @@ static int nf_tables_updtable(struct nft_ctx *ctx) if ((flags ^ ctx->table->flags) & NFT_TABLE_F_PERSIST) return -EOPNOTSUPP; - /* No dormant off/on/off/on games in single transaction */ - if (ctx->table->flags & __NFT_TABLE_F_UPDATE) - return -EINVAL; - trans = nft_trans_alloc(ctx, NFT_MSG_NEWTABLE, sizeof(struct nft_trans_table)); if (trans == NULL) return -ENOMEM; + ret = -EINVAL; if ((flags & NFT_TABLE_F_DORMANT) && !(ctx->table->flags & NFT_TABLE_F_DORMANT)) { - ctx->table->flags |= NFT_TABLE_F_DORMANT; - if (!(ctx->table->flags & __NFT_TABLE_F_UPDATE)) - ctx->table->flags |= __NFT_TABLE_F_WAS_AWAKEN; + /* No dormant on/off/on games in single transaction */ + if (ctx->table->flags & __NFT_TABLE_F_WAS_DORMANT) + goto err_flags; + ctx->table->flags |= NFT_TABLE_F_DORMANT | __NFT_TABLE_F_WAS_AWAKEN; } else if (!(flags & NFT_TABLE_F_DORMANT) && ctx->table->flags & NFT_TABLE_F_DORMANT) { + /* No dormant off/on/off games in single transaction */ + if (ctx->table->flags & __NFT_TABLE_F_WAS_AWAKEN) + goto err_flags; ctx->table->flags &= ~NFT_TABLE_F_DORMANT; - if (!(ctx->table->flags & __NFT_TABLE_F_UPDATE)) { + if (!(ctx->table->flags & __NFT_TABLE_F_WAS_DORMANT)) { ret = nf_tables_table_enable(ctx->net, ctx->table); if (ret < 0) goto err_register_hooks; @@ -1265,6 +1266,7 @@ static int nf_tables_updtable(struct nft_ctx *ctx) err_register_hooks: ctx->table->flags |= NFT_TABLE_F_DORMANT; +err_flags: nft_trans_destroy(trans); return ret; } -- 2.39.3 (Apple Git-145)