Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge tag 'nf-24-03-28' of git://git.kernel.org/pub/scm/linux/kernel/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>

+43 -8
+1
net/ipv4/netfilter/Kconfig
··· 329 329 config IP_NF_ARPFILTER 330 330 tristate "arptables-legacy packet filtering support" 331 331 select IP_NF_ARPTABLES 332 + select NETFILTER_FAMILY_ARP 332 333 depends on NETFILTER_XTABLES 333 334 help 334 335 ARP packet filtering defines a table `filter', which has a series of
+42 -8
net/netfilter/nf_tables_api.c
··· 1200 1200 __NFT_TABLE_F_WAS_AWAKEN | \ 1201 1201 __NFT_TABLE_F_WAS_ORPHAN) 1202 1202 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 + 1203 1222 static int nf_tables_updtable(struct nft_ctx *ctx) 1204 1223 { 1205 1224 struct nft_trans *trans; ··· 1245 1226 return -EOPNOTSUPP; 1246 1227 1247 1228 /* No dormant off/on/off/on games in single transaction */ 1248 - if (ctx->table->flags & __NFT_TABLE_F_UPDATE) 1229 + if (nft_table_pending_update(ctx)) 1249 1230 return -EINVAL; 1250 1231 1251 1232 trans = nft_trans_alloc(ctx, NFT_MSG_NEWTABLE, ··· 2650 2631 } 2651 2632 } 2652 2633 2634 + if (table->flags & __NFT_TABLE_F_UPDATE && 2635 + !list_empty(&hook.list)) { 2636 + NL_SET_BAD_ATTR(extack, attr); 2637 + err = -EOPNOTSUPP; 2638 + goto err_hooks; 2639 + } 2640 + 2653 2641 if (!(table->flags & NFT_TABLE_F_DORMANT) && 2654 2642 nft_is_base_chain(chain) && 2655 2643 !list_empty(&hook.list)) { ··· 2886 2860 struct nft_trans *trans; 2887 2861 int err; 2888 2862 2863 + if (ctx->table->flags & __NFT_TABLE_F_UPDATE) 2864 + return -EOPNOTSUPP; 2865 + 2889 2866 err = nft_chain_parse_hook(ctx->net, basechain, nla, &chain_hook, 2890 2867 ctx->family, chain->flags, extack); 2891 2868 if (err < 0) ··· 2973 2944 nft_ctx_init(&ctx, net, skb, info->nlh, family, table, chain, nla); 2974 2945 2975 2946 if (nla[NFTA_CHAIN_HOOK]) { 2976 - if (chain->flags & NFT_CHAIN_HW_OFFLOAD) 2947 + if (NFNL_MSG_TYPE(info->nlh->nlmsg_type) == NFT_MSG_DESTROYCHAIN || 2948 + chain->flags & NFT_CHAIN_HW_OFFLOAD) 2977 2949 return -EOPNOTSUPP; 2978 2950 2979 2951 if (nft_is_base_chain(chain)) { ··· 10212 10182 if (nft_trans_chain_update(trans)) { 10213 10183 nf_tables_chain_notify(&trans->ctx, NFT_MSG_DELCHAIN, 10214 10184 &nft_trans_chain_hooks(trans)); 10215 - nft_netdev_unregister_hooks(net, 10216 - &nft_trans_chain_hooks(trans), 10217 - true); 10185 + if (!(trans->ctx.table->flags & NFT_TABLE_F_DORMANT)) { 10186 + nft_netdev_unregister_hooks(net, 10187 + &nft_trans_chain_hooks(trans), 10188 + true); 10189 + } 10218 10190 } else { 10219 10191 nft_chain_del(trans->ctx.chain); 10220 10192 nf_tables_chain_notify(&trans->ctx, NFT_MSG_DELCHAIN, ··· 10492 10460 break; 10493 10461 case NFT_MSG_NEWCHAIN: 10494 10462 if (nft_trans_chain_update(trans)) { 10495 - nft_netdev_unregister_hooks(net, 10496 - &nft_trans_chain_hooks(trans), 10497 - true); 10463 + if (!(trans->ctx.table->flags & NFT_TABLE_F_DORMANT)) { 10464 + nft_netdev_unregister_hooks(net, 10465 + &nft_trans_chain_hooks(trans), 10466 + true); 10467 + } 10498 10468 free_percpu(nft_trans_chain_stats(trans)); 10499 10469 kfree(nft_trans_chain_name(trans)); 10500 10470 nft_trans_destroy(trans);