Bail out if userspace creates an anonymous set which remains unbound after this transaction. Add a list of pending objects, this list is never used in iterations as it stores object of different type. Signed-off-by: Pablo Neira Ayuso <pablo@xxxxxxxxxxxxx> --- include/net/netfilter/nf_tables.h | 3 +++ net/netfilter/nf_tables_api.c | 17 +++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/include/net/netfilter/nf_tables.h b/include/net/netfilter/nf_tables.h index 66e5c7a8ec21..d24146b526a1 100644 --- a/include/net/netfilter/nf_tables.h +++ b/include/net/netfilter/nf_tables.h @@ -511,6 +511,7 @@ struct nft_set_elem_expr { * * @list: table set list node * @bindings: list of set bindings + * @pending_list: list of pending anonymous set not yet bound to rule * @table: table this set belongs to * @net: netnamespace this set belongs to * @name: name of the set @@ -540,6 +541,7 @@ struct nft_set_elem_expr { struct nft_set { struct list_head list; struct list_head bindings; + struct list_head pending_list; struct nft_table *table; possible_net_t net; char *name; @@ -1707,6 +1709,7 @@ struct nftables_pernet { struct list_head commit_list; struct list_head module_list; struct list_head notify_list; + struct list_head pending_list; struct mutex commit_mutex; u64 table_handle; unsigned int base_seq; diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c index 69bceefaa5c8..11beb6750531 100644 --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c @@ -4926,6 +4926,12 @@ static int nf_tables_newset(struct sk_buff *skb, const struct nfnl_info *info, if (err < 0) goto err_set_expr_alloc; + if (nft_set_is_anonymous(set)) { + struct nftables_pernet *nft_net = nft_pernet(net); + + list_add_tail(&set->pending_list, &nft_net->pending_list); + } + list_add_tail_rcu(&set->list, &table->sets); table->use++; return 0; @@ -5108,6 +5114,9 @@ int nf_tables_bind_set(const struct nft_ctx *ctx, struct nft_set *set, } bind: binding->chain = ctx->chain; + if (nft_set_is_anonymous(set)) + list_del(&set->pending_list); + list_add_tail_rcu(&binding->list, &set->bindings); nft_set_trans_bind(ctx, set); set->use++; @@ -8792,6 +8801,11 @@ static int nf_tables_validate(struct net *net) struct nftables_pernet *nft_net = nft_pernet(net); struct nft_table *table; + if (!list_empty(&nft_net->pending_list)) { + pr_warn_once("rejecting nftables ruleset with pending objects\n"); + return -EINVAL; + } + list_for_each_entry(table, &nft_net->tables, list) { switch (table->validate_state) { case NFT_VALIDATE_SKIP: @@ -9727,6 +9741,8 @@ static int __nf_tables_abort(struct net *net, enum nfnl_abort_action action) if (nft_trans_set_bound(trans)) { nft_trans_destroy(trans); break; + } else if (nft_set_is_anonymous(nft_trans_set(trans))) { + list_del(&nft_trans_set(trans)->pending_list); } list_del_rcu(&nft_trans_set(trans)->list); break; @@ -10599,6 +10615,7 @@ static int __net_init nf_tables_init_net(struct net *net) INIT_LIST_HEAD(&nft_net->commit_list); INIT_LIST_HEAD(&nft_net->module_list); INIT_LIST_HEAD(&nft_net->notify_list); + INIT_LIST_HEAD(&nft_net->pending_list); mutex_init(&nft_net->commit_mutex); nft_net->base_seq = 1; -- 2.30.2