Skip to content

Commit 1e1fb6f

Browse files
committed
netfilter: nf_tables: reject table flag and netdev basechain updates
netdev basechain updates are stored in the transaction object hook list. When setting on the table dormant flag, it iterates over the existing hooks in the basechain. Thus, skipping the hooks that are being added/deleted in this transaction, which leaves hook registration in inconsistent state. Reject table flag updates in combination with netdev basechain updates in the same batch: - Update table flags and add/delete basechain: Check from basechain update path if there are pending flag updates for this table. - add/delete basechain and update table flags: Iterate over the transaction list to search for basechain updates from the table update path. In both cases, the batch is rejected. Based on suggestion from Florian Westphal. Fixes: b9703ed ("netfilter: nf_tables: support for adding new devices to an existing netdev chain") Fixes: 7d937b1 ("netfilter: nf_tables: support for deleting devices in an existing netdev chain") Signed-off-by: Pablo Neira Ayuso <[email protected]>
1 parent b32ca27 commit 1e1fb6f

File tree

1 file changed

+30
-1
lines changed

1 file changed

+30
-1
lines changed

net/netfilter/nf_tables_api.c

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1200,6 +1200,25 @@ static void nf_tables_table_disable(struct net *net, struct nft_table *table)
12001200
__NFT_TABLE_F_WAS_AWAKEN | \
12011201
__NFT_TABLE_F_WAS_ORPHAN)
12021202

1203+
static bool nft_table_pending_update(const struct nft_ctx *ctx)
1204+
{
1205+
struct nftables_pernet *nft_net = nft_pernet(ctx->net);
1206+
struct nft_trans *trans;
1207+
1208+
if (ctx->table->flags & __NFT_TABLE_F_UPDATE)
1209+
return true;
1210+
1211+
list_for_each_entry(trans, &nft_net->commit_list, list) {
1212+
if ((trans->msg_type == NFT_MSG_NEWCHAIN ||
1213+
trans->msg_type == NFT_MSG_DELCHAIN) &&
1214+
trans->ctx.table == ctx->table &&
1215+
nft_trans_chain_update(trans))
1216+
return true;
1217+
}
1218+
1219+
return false;
1220+
}
1221+
12031222
static int nf_tables_updtable(struct nft_ctx *ctx)
12041223
{
12051224
struct nft_trans *trans;
@@ -1226,7 +1245,7 @@ static int nf_tables_updtable(struct nft_ctx *ctx)
12261245
return -EOPNOTSUPP;
12271246

12281247
/* No dormant off/on/off/on games in single transaction */
1229-
if (ctx->table->flags & __NFT_TABLE_F_UPDATE)
1248+
if (nft_table_pending_update(ctx))
12301249
return -EINVAL;
12311250

12321251
trans = nft_trans_alloc(ctx, NFT_MSG_NEWTABLE,
@@ -2631,6 +2650,13 @@ static int nf_tables_updchain(struct nft_ctx *ctx, u8 genmask, u8 policy,
26312650
}
26322651
}
26332652

2653+
if (table->flags & __NFT_TABLE_F_UPDATE &&
2654+
!list_empty(&hook.list)) {
2655+
NL_SET_BAD_ATTR(extack, attr);
2656+
err = -EOPNOTSUPP;
2657+
goto err_hooks;
2658+
}
2659+
26342660
if (!(table->flags & NFT_TABLE_F_DORMANT) &&
26352661
nft_is_base_chain(chain) &&
26362662
!list_empty(&hook.list)) {
@@ -2860,6 +2886,9 @@ static int nft_delchain_hook(struct nft_ctx *ctx,
28602886
struct nft_trans *trans;
28612887
int err;
28622888

2889+
if (ctx->table->flags & __NFT_TABLE_F_UPDATE)
2890+
return -EOPNOTSUPP;
2891+
28632892
err = nft_chain_parse_hook(ctx->net, basechain, nla, &chain_hook,
28642893
ctx->family, chain->flags, extack);
28652894
if (err < 0)

0 commit comments

Comments
 (0)