Skip to content

Commit 7d937b1

Browse files
committed
netfilter: nf_tables: support for deleting devices in an existing netdev chain
This patch allows for deleting devices in an existing netdev chain. Signed-off-by: Pablo Neira Ayuso <[email protected]>
1 parent b9703ed commit 7d937b1

File tree

1 file changed

+88
-11
lines changed

1 file changed

+88
-11
lines changed

net/netfilter/nf_tables_api.c

Lines changed: 88 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1646,7 +1646,7 @@ static int nf_tables_fill_chain_info(struct sk_buff *skb, struct net *net,
16461646
NFTA_CHAIN_PAD))
16471647
goto nla_put_failure;
16481648

1649-
if (event == NFT_MSG_DELCHAIN) {
1649+
if (event == NFT_MSG_DELCHAIN && !hook_list) {
16501650
nlmsg_end(skb, nlh);
16511651
return 0;
16521652
}
@@ -2667,6 +2667,59 @@ static int nf_tables_newchain(struct sk_buff *skb, const struct nfnl_info *info,
26672667
return nf_tables_addchain(&ctx, family, genmask, policy, flags, extack);
26682668
}
26692669

2670+
static int nft_delchain_hook(struct nft_ctx *ctx, struct nft_chain *chain,
2671+
struct netlink_ext_ack *extack)
2672+
{
2673+
const struct nlattr * const *nla = ctx->nla;
2674+
struct nft_chain_hook chain_hook = {};
2675+
struct nft_base_chain *basechain;
2676+
struct nft_hook *this, *hook;
2677+
LIST_HEAD(chain_del_list);
2678+
struct nft_trans *trans;
2679+
int err;
2680+
2681+
if (!nft_is_base_chain(chain))
2682+
return -EOPNOTSUPP;
2683+
2684+
basechain = nft_base_chain(chain);
2685+
err = nft_chain_parse_hook(ctx->net, basechain, nla, &chain_hook,
2686+
ctx->family, extack);
2687+
if (err < 0)
2688+
return err;
2689+
2690+
list_for_each_entry(this, &chain_hook.list, list) {
2691+
hook = nft_hook_list_find(&basechain->hook_list, this);
2692+
if (!hook) {
2693+
err = -ENOENT;
2694+
goto err_chain_del_hook;
2695+
}
2696+
list_move(&hook->list, &chain_del_list);
2697+
}
2698+
2699+
trans = nft_trans_alloc(ctx, NFT_MSG_DELCHAIN,
2700+
sizeof(struct nft_trans_chain));
2701+
if (!trans) {
2702+
err = -ENOMEM;
2703+
goto err_chain_del_hook;
2704+
}
2705+
2706+
nft_trans_basechain(trans) = basechain;
2707+
nft_trans_chain_update(trans) = true;
2708+
INIT_LIST_HEAD(&nft_trans_chain_hooks(trans));
2709+
list_splice(&chain_del_list, &nft_trans_chain_hooks(trans));
2710+
nft_chain_release_hook(&chain_hook);
2711+
2712+
nft_trans_commit_list_add_tail(ctx->net, trans);
2713+
2714+
return 0;
2715+
2716+
err_chain_del_hook:
2717+
list_splice(&chain_del_list, &basechain->hook_list);
2718+
nft_chain_release_hook(&chain_hook);
2719+
2720+
return err;
2721+
}
2722+
26702723
static int nf_tables_delchain(struct sk_buff *skb, const struct nfnl_info *info,
26712724
const struct nlattr * const nla[])
26722725
{
@@ -2707,12 +2760,19 @@ static int nf_tables_delchain(struct sk_buff *skb, const struct nfnl_info *info,
27072760
return PTR_ERR(chain);
27082761
}
27092762

2763+
nft_ctx_init(&ctx, net, skb, info->nlh, family, table, chain, nla);
2764+
2765+
if (nla[NFTA_CHAIN_HOOK]) {
2766+
if (chain->flags & NFT_CHAIN_HW_OFFLOAD)
2767+
return -EOPNOTSUPP;
2768+
2769+
return nft_delchain_hook(&ctx, chain, extack);
2770+
}
2771+
27102772
if (info->nlh->nlmsg_flags & NLM_F_NONREC &&
27112773
chain->use > 0)
27122774
return -EBUSY;
27132775

2714-
nft_ctx_init(&ctx, net, skb, info->nlh, family, table, chain, nla);
2715-
27162776
use = chain->use;
27172777
list_for_each_entry(rule, &chain->rules, list) {
27182778
if (!nft_is_active_next(net, rule))
@@ -8812,7 +8872,10 @@ static void nft_commit_release(struct nft_trans *trans)
88128872
break;
88138873
case NFT_MSG_DELCHAIN:
88148874
case NFT_MSG_DESTROYCHAIN:
8815-
nf_tables_chain_destroy(&trans->ctx);
8875+
if (nft_trans_chain_update(trans))
8876+
nft_hooks_destroy(&nft_trans_chain_hooks(trans));
8877+
else
8878+
nf_tables_chain_destroy(&trans->ctx);
88168879
break;
88178880
case NFT_MSG_DELRULE:
88188881
case NFT_MSG_DESTROYRULE:
@@ -9304,11 +9367,20 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
93049367
break;
93059368
case NFT_MSG_DELCHAIN:
93069369
case NFT_MSG_DESTROYCHAIN:
9307-
nft_chain_del(trans->ctx.chain);
9308-
nf_tables_chain_notify(&trans->ctx, trans->msg_type, NULL);
9309-
nf_tables_unregister_hook(trans->ctx.net,
9310-
trans->ctx.table,
9311-
trans->ctx.chain);
9370+
if (nft_trans_chain_update(trans)) {
9371+
nf_tables_chain_notify(&trans->ctx, NFT_MSG_DELCHAIN,
9372+
&nft_trans_chain_hooks(trans));
9373+
nft_netdev_unregister_hooks(net,
9374+
&nft_trans_chain_hooks(trans),
9375+
true);
9376+
} else {
9377+
nft_chain_del(trans->ctx.chain);
9378+
nf_tables_chain_notify(&trans->ctx, NFT_MSG_DELCHAIN,
9379+
NULL);
9380+
nf_tables_unregister_hook(trans->ctx.net,
9381+
trans->ctx.table,
9382+
trans->ctx.chain);
9383+
}
93129384
break;
93139385
case NFT_MSG_NEWRULE:
93149386
nft_clear(trans->ctx.net, nft_trans_rule(trans));
@@ -9558,8 +9630,13 @@ static int __nf_tables_abort(struct net *net, enum nfnl_abort_action action)
95589630
break;
95599631
case NFT_MSG_DELCHAIN:
95609632
case NFT_MSG_DESTROYCHAIN:
9561-
trans->ctx.table->use++;
9562-
nft_clear(trans->ctx.net, trans->ctx.chain);
9633+
if (nft_trans_chain_update(trans)) {
9634+
list_splice(&nft_trans_chain_hooks(trans),
9635+
&nft_trans_basechain(trans)->hook_list);
9636+
} else {
9637+
trans->ctx.table->use++;
9638+
nft_clear(trans->ctx.net, trans->ctx.chain);
9639+
}
95639640
nft_trans_destroy(trans);
95649641
break;
95659642
case NFT_MSG_NEWRULE:

0 commit comments

Comments
 (0)