Commit 005e528c authored by Paolo Abeni's avatar Paolo Abeni
Browse files
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: default avatarPaolo Abeni <pabeni@redhat.com>
parents 7e6f4b2a 15fba562
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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
+42 −8
Original line number Diff line number Diff line
@@ -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;
@@ -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,
@@ -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)) {
@@ -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)
@@ -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)) {
@@ -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));
				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,
@@ -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)) {
				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);