Skip to content

Commit

Permalink
Merge tag 'nf-24-03-28' of git://git.kernel.org/pub/scm/linux/kernel/…
Browse files Browse the repository at this point in the history
…git/netfilter/nf

Pablo Neira Ayuso says:

====================
Netfilter fixes for net

The following patchset contains Netfilter fixes for net:

Patch #1 reject destroy chain command to delete device hooks in netdev
         family, hence, only delchain commands are allowed.

Patch #2 reject table flag update interference with netdev basechain
	 hook updates, this can leave hooks in inconsistent
	 registration/unregistration state.

Patch #3 do not unregister netdev basechain hooks if table is dormant.
	 Otherwise, splat with double unregistration is possible.

Patch #4 fixes Kconfig to allow to restore IP_NF_ARPTABLES,
	 from Kuniyuki Iwashima.

There are a more fixes still in progress on my side that need more work.

* tag 'nf-24-03-28' of git://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf:
  netfilter: arptables: Select NETFILTER_FAMILY_ARP when building arp_tables.c
  netfilter: nf_tables: skip netdev hook unregistration if table is dormant
  netfilter: nf_tables: reject table flag and netdev basechain updates
  netfilter: nf_tables: reject destroy command to remove basechain hooks
====================

Link: https://lore.kernel.org/r/20240328031855.2063-1-pablo@netfilter.org
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
  • Loading branch information
Paolo Abeni committed Mar 28, 2024
2 parents 7e6f4b2 + 15fba56 commit 005e528
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 8 deletions.
1 change: 1 addition & 0 deletions net/ipv4/netfilter/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,7 @@ config NFT_COMPAT_ARP
config IP_NF_ARPFILTER
tristate "arptables-legacy packet filtering support"
select IP_NF_ARPTABLES
select NETFILTER_FAMILY_ARP
depends on NETFILTER_XTABLES
help
ARP packet filtering defines a table `filter', which has a series of
Expand Down
50 changes: 42 additions & 8 deletions net/netfilter/nf_tables_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -1200,6 +1200,25 @@ static void nf_tables_table_disable(struct net *net, struct nft_table *table)
__NFT_TABLE_F_WAS_AWAKEN | \
__NFT_TABLE_F_WAS_ORPHAN)

static bool nft_table_pending_update(const struct nft_ctx *ctx)
{
struct nftables_pernet *nft_net = nft_pernet(ctx->net);
struct nft_trans *trans;

if (ctx->table->flags & __NFT_TABLE_F_UPDATE)
return true;

list_for_each_entry(trans, &nft_net->commit_list, list) {
if ((trans->msg_type == NFT_MSG_NEWCHAIN ||
trans->msg_type == NFT_MSG_DELCHAIN) &&
trans->ctx.table == ctx->table &&
nft_trans_chain_update(trans))
return true;
}

return false;
}

static int nf_tables_updtable(struct nft_ctx *ctx)
{
struct nft_trans *trans;
Expand All @@ -1226,7 +1245,7 @@ static int nf_tables_updtable(struct nft_ctx *ctx)
return -EOPNOTSUPP;

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

trans = nft_trans_alloc(ctx, NFT_MSG_NEWTABLE,
Expand Down Expand Up @@ -2631,6 +2650,13 @@ static int nf_tables_updchain(struct nft_ctx *ctx, u8 genmask, u8 policy,
}
}

if (table->flags & __NFT_TABLE_F_UPDATE &&
!list_empty(&hook.list)) {
NL_SET_BAD_ATTR(extack, attr);
err = -EOPNOTSUPP;
goto err_hooks;
}

if (!(table->flags & NFT_TABLE_F_DORMANT) &&
nft_is_base_chain(chain) &&
!list_empty(&hook.list)) {
Expand Down Expand Up @@ -2860,6 +2886,9 @@ static int nft_delchain_hook(struct nft_ctx *ctx,
struct nft_trans *trans;
int err;

if (ctx->table->flags & __NFT_TABLE_F_UPDATE)
return -EOPNOTSUPP;

err = nft_chain_parse_hook(ctx->net, basechain, nla, &chain_hook,
ctx->family, chain->flags, extack);
if (err < 0)
Expand Down Expand Up @@ -2944,7 +2973,8 @@ static int nf_tables_delchain(struct sk_buff *skb, const struct nfnl_info *info,
nft_ctx_init(&ctx, net, skb, info->nlh, family, table, chain, nla);

if (nla[NFTA_CHAIN_HOOK]) {
if (chain->flags & NFT_CHAIN_HW_OFFLOAD)
if (NFNL_MSG_TYPE(info->nlh->nlmsg_type) == NFT_MSG_DESTROYCHAIN ||
chain->flags & NFT_CHAIN_HW_OFFLOAD)
return -EOPNOTSUPP;

if (nft_is_base_chain(chain)) {
Expand Down Expand Up @@ -10182,9 +10212,11 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
if (nft_trans_chain_update(trans)) {
nf_tables_chain_notify(&trans->ctx, NFT_MSG_DELCHAIN,
&nft_trans_chain_hooks(trans));
nft_netdev_unregister_hooks(net,
&nft_trans_chain_hooks(trans),
true);
if (!(trans->ctx.table->flags & NFT_TABLE_F_DORMANT)) {
nft_netdev_unregister_hooks(net,
&nft_trans_chain_hooks(trans),
true);
}
} else {
nft_chain_del(trans->ctx.chain);
nf_tables_chain_notify(&trans->ctx, NFT_MSG_DELCHAIN,
Expand Down Expand Up @@ -10460,9 +10492,11 @@ static int __nf_tables_abort(struct net *net, enum nfnl_abort_action action)
break;
case NFT_MSG_NEWCHAIN:
if (nft_trans_chain_update(trans)) {
nft_netdev_unregister_hooks(net,
&nft_trans_chain_hooks(trans),
true);
if (!(trans->ctx.table->flags & NFT_TABLE_F_DORMANT)) {
nft_netdev_unregister_hooks(net,
&nft_trans_chain_hooks(trans),
true);
}
free_percpu(nft_trans_chain_stats(trans));
kfree(nft_trans_chain_name(trans));
nft_trans_destroy(trans);
Expand Down

0 comments on commit 005e528

Please sign in to comment.