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

Merge git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf

Pablo Neira Ayuso says:

====================
Netfilter fixes for net (v2)

The following patchset contains Netfilter fixes for net:

1) Move back the defrag users fields to the global netns_nf area.
Kernel fails to boot if conntrack is builtin and kernel is booted
with: nf_conntrack.enable_hooks=1. From Florian Westphal.

2) Rule event notification is missing relevant context such as
the position handle and the NLM_F_APPEND flag.

3) Rule replacement is expanded to add + delete using the existing
rule handle, reverse order of this operation so it makes sense
from rule notification standpoint.

4) Propagate to userspace the NLM_F_CREATE and NLM_F_EXCL flags
from the rule notification path.

Patches #2, #3 and #4 are used by 'nft monitor' and 'iptables-monitor'
userspace utilities which are not correctly representing the following
operations through netlink notifications:

- rule insertions
- rule addition/insertion from position handle
- create table/chain/set/map/flowtable/...
====================

Signed-off-by: David S. Miller <davem@davemloft.net>

+91 -68
-1
include/net/netfilter/ipv6/nf_defrag_ipv6.h
··· 17 17 struct nft_ct_frag6_pernet { 18 18 struct ctl_table_header *nf_frag_frags_hdr; 19 19 struct fqdir *fqdir; 20 - unsigned int users; 21 20 }; 22 21 23 22 #endif /* _NF_DEFRAG_IPV6_H */
+1 -1
include/net/netfilter/nf_tables.h
··· 1202 1202 1203 1203 void nft_obj_notify(struct net *net, const struct nft_table *table, 1204 1204 struct nft_object *obj, u32 portid, u32 seq, 1205 - int event, int family, int report, gfp_t gfp); 1205 + int event, u16 flags, int family, int report, gfp_t gfp); 1206 1206 1207 1207 /** 1208 1208 * struct nft_object_type - stateful object type
+6
include/net/netns/netfilter.h
··· 27 27 #if IS_ENABLED(CONFIG_DECNET) 28 28 struct nf_hook_entries __rcu *hooks_decnet[NF_DN_NUMHOOKS]; 29 29 #endif 30 + #if IS_ENABLED(CONFIG_NF_DEFRAG_IPV4) 31 + unsigned int defrag_ipv4_users; 32 + #endif 33 + #if IS_ENABLED(CONFIG_NF_DEFRAG_IPV6) 34 + unsigned int defrag_ipv6_users; 35 + #endif 30 36 }; 31 37 #endif
+9 -21
net/ipv4/netfilter/nf_defrag_ipv4.c
··· 20 20 #endif 21 21 #include <net/netfilter/nf_conntrack_zones.h> 22 22 23 - static unsigned int defrag4_pernet_id __read_mostly; 24 23 static DEFINE_MUTEX(defrag4_mutex); 25 - 26 - struct defrag4_pernet { 27 - unsigned int users; 28 - }; 29 24 30 25 static int nf_ct_ipv4_gather_frags(struct net *net, struct sk_buff *skb, 31 26 u_int32_t user) ··· 106 111 107 112 static void __net_exit defrag4_net_exit(struct net *net) 108 113 { 109 - struct defrag4_pernet *nf_defrag = net_generic(net, defrag4_pernet_id); 110 - 111 - if (nf_defrag->users) { 114 + if (net->nf.defrag_ipv4_users) { 112 115 nf_unregister_net_hooks(net, ipv4_defrag_ops, 113 116 ARRAY_SIZE(ipv4_defrag_ops)); 114 - nf_defrag->users = 0; 117 + net->nf.defrag_ipv4_users = 0; 115 118 } 116 119 } 117 120 118 121 static struct pernet_operations defrag4_net_ops = { 119 122 .exit = defrag4_net_exit, 120 - .id = &defrag4_pernet_id, 121 - .size = sizeof(struct defrag4_pernet), 122 123 }; 123 124 124 125 static int __init nf_defrag_init(void) ··· 129 138 130 139 int nf_defrag_ipv4_enable(struct net *net) 131 140 { 132 - struct defrag4_pernet *nf_defrag = net_generic(net, defrag4_pernet_id); 133 141 int err = 0; 134 142 135 143 mutex_lock(&defrag4_mutex); 136 - if (nf_defrag->users == UINT_MAX) { 144 + if (net->nf.defrag_ipv4_users == UINT_MAX) { 137 145 err = -EOVERFLOW; 138 146 goto out_unlock; 139 147 } 140 148 141 - if (nf_defrag->users) { 142 - nf_defrag->users++; 149 + if (net->nf.defrag_ipv4_users) { 150 + net->nf.defrag_ipv4_users++; 143 151 goto out_unlock; 144 152 } 145 153 146 154 err = nf_register_net_hooks(net, ipv4_defrag_ops, 147 155 ARRAY_SIZE(ipv4_defrag_ops)); 148 156 if (err == 0) 149 - nf_defrag->users = 1; 157 + net->nf.defrag_ipv4_users = 1; 150 158 151 159 out_unlock: 152 160 mutex_unlock(&defrag4_mutex); ··· 155 165 156 166 void nf_defrag_ipv4_disable(struct net *net) 157 167 { 158 - struct defrag4_pernet *nf_defrag = net_generic(net, defrag4_pernet_id); 159 - 160 168 mutex_lock(&defrag4_mutex); 161 - if (nf_defrag->users) { 162 - nf_defrag->users--; 163 - if (nf_defrag->users == 0) 169 + if (net->nf.defrag_ipv4_users) { 170 + net->nf.defrag_ipv4_users--; 171 + if (net->nf.defrag_ipv4_users == 0) 164 172 nf_unregister_net_hooks(net, ipv4_defrag_ops, 165 173 ARRAY_SIZE(ipv4_defrag_ops)); 166 174 }
+1 -1
net/ipv6/netfilter/nf_conntrack_reasm.c
··· 33 33 34 34 static const char nf_frags_cache_name[] = "nf-frags"; 35 35 36 - unsigned int nf_frag_pernet_id __read_mostly; 36 + static unsigned int nf_frag_pernet_id __read_mostly; 37 37 static struct inet_frags nf_frags; 38 38 39 39 static struct nft_ct_frag6_pernet *nf_frag_pernet(struct net *net)
+9 -16
net/ipv6/netfilter/nf_defrag_ipv6_hooks.c
··· 25 25 #include <net/netfilter/nf_conntrack_zones.h> 26 26 #include <net/netfilter/ipv6/nf_defrag_ipv6.h> 27 27 28 - extern unsigned int nf_frag_pernet_id; 29 - 30 28 static DEFINE_MUTEX(defrag6_mutex); 31 29 32 30 static enum ip6_defrag_users nf_ct6_defrag_user(unsigned int hooknum, ··· 89 91 90 92 static void __net_exit defrag6_net_exit(struct net *net) 91 93 { 92 - struct nft_ct_frag6_pernet *nf_frag = net_generic(net, nf_frag_pernet_id); 93 - 94 - if (nf_frag->users) { 94 + if (net->nf.defrag_ipv6_users) { 95 95 nf_unregister_net_hooks(net, ipv6_defrag_ops, 96 96 ARRAY_SIZE(ipv6_defrag_ops)); 97 - nf_frag->users = 0; 97 + net->nf.defrag_ipv6_users = 0; 98 98 } 99 99 } 100 100 ··· 130 134 131 135 int nf_defrag_ipv6_enable(struct net *net) 132 136 { 133 - struct nft_ct_frag6_pernet *nf_frag = net_generic(net, nf_frag_pernet_id); 134 137 int err = 0; 135 138 136 139 mutex_lock(&defrag6_mutex); 137 - if (nf_frag->users == UINT_MAX) { 140 + if (net->nf.defrag_ipv6_users == UINT_MAX) { 138 141 err = -EOVERFLOW; 139 142 goto out_unlock; 140 143 } 141 144 142 - if (nf_frag->users) { 143 - nf_frag->users++; 145 + if (net->nf.defrag_ipv6_users) { 146 + net->nf.defrag_ipv6_users++; 144 147 goto out_unlock; 145 148 } 146 149 147 150 err = nf_register_net_hooks(net, ipv6_defrag_ops, 148 151 ARRAY_SIZE(ipv6_defrag_ops)); 149 152 if (err == 0) 150 - nf_frag->users = 1; 153 + net->nf.defrag_ipv6_users = 1; 151 154 152 155 out_unlock: 153 156 mutex_unlock(&defrag6_mutex); ··· 156 161 157 162 void nf_defrag_ipv6_disable(struct net *net) 158 163 { 159 - struct nft_ct_frag6_pernet *nf_frag = net_generic(net, nf_frag_pernet_id); 160 - 161 164 mutex_lock(&defrag6_mutex); 162 - if (nf_frag->users) { 163 - nf_frag->users--; 164 - if (nf_frag->users == 0) 165 + if (net->nf.defrag_ipv6_users) { 166 + net->nf.defrag_ipv6_users--; 167 + if (net->nf.defrag_ipv6_users == 0) 165 168 nf_unregister_net_hooks(net, ipv6_defrag_ops, 166 169 ARRAY_SIZE(ipv6_defrag_ops)); 167 170 }
+64 -27
net/netfilter/nf_tables_api.c
··· 780 780 { 781 781 struct nftables_pernet *nft_net; 782 782 struct sk_buff *skb; 783 + u16 flags = 0; 783 784 int err; 784 785 785 786 if (!ctx->report && ··· 791 790 if (skb == NULL) 792 791 goto err; 793 792 793 + if (ctx->flags & (NLM_F_CREATE | NLM_F_EXCL)) 794 + flags |= ctx->flags & (NLM_F_CREATE | NLM_F_EXCL); 795 + 794 796 err = nf_tables_fill_table_info(skb, ctx->net, ctx->portid, ctx->seq, 795 - event, 0, ctx->family, ctx->table); 797 + event, flags, ctx->family, ctx->table); 796 798 if (err < 0) { 797 799 kfree_skb(skb); 798 800 goto err; ··· 1567 1563 { 1568 1564 struct nftables_pernet *nft_net; 1569 1565 struct sk_buff *skb; 1566 + u16 flags = 0; 1570 1567 int err; 1571 1568 1572 1569 if (!ctx->report && ··· 1578 1573 if (skb == NULL) 1579 1574 goto err; 1580 1575 1576 + if (ctx->flags & (NLM_F_CREATE | NLM_F_EXCL)) 1577 + flags |= ctx->flags & (NLM_F_CREATE | NLM_F_EXCL); 1578 + 1581 1579 err = nf_tables_fill_chain_info(skb, ctx->net, ctx->portid, ctx->seq, 1582 - event, 0, ctx->family, ctx->table, 1580 + event, flags, ctx->family, ctx->table, 1583 1581 ctx->chain); 1584 1582 if (err < 0) { 1585 1583 kfree_skb(skb); ··· 2874 2866 u32 flags, int family, 2875 2867 const struct nft_table *table, 2876 2868 const struct nft_chain *chain, 2877 - const struct nft_rule *rule, 2878 - const struct nft_rule *prule) 2869 + const struct nft_rule *rule, u64 handle) 2879 2870 { 2880 2871 struct nlmsghdr *nlh; 2881 2872 const struct nft_expr *expr, *next; ··· 2894 2887 NFTA_RULE_PAD)) 2895 2888 goto nla_put_failure; 2896 2889 2897 - if (event != NFT_MSG_DELRULE && prule) { 2898 - if (nla_put_be64(skb, NFTA_RULE_POSITION, 2899 - cpu_to_be64(prule->handle), 2890 + if (event != NFT_MSG_DELRULE && handle) { 2891 + if (nla_put_be64(skb, NFTA_RULE_POSITION, cpu_to_be64(handle), 2900 2892 NFTA_RULE_PAD)) 2901 2893 goto nla_put_failure; 2902 2894 } ··· 2931 2925 const struct nft_rule *rule, int event) 2932 2926 { 2933 2927 struct nftables_pernet *nft_net = nft_pernet(ctx->net); 2928 + const struct nft_rule *prule; 2934 2929 struct sk_buff *skb; 2930 + u64 handle = 0; 2931 + u16 flags = 0; 2935 2932 int err; 2936 2933 2937 2934 if (!ctx->report && ··· 2945 2936 if (skb == NULL) 2946 2937 goto err; 2947 2938 2939 + if (event == NFT_MSG_NEWRULE && 2940 + !list_is_first(&rule->list, &ctx->chain->rules) && 2941 + !list_is_last(&rule->list, &ctx->chain->rules)) { 2942 + prule = list_prev_entry(rule, list); 2943 + handle = prule->handle; 2944 + } 2945 + if (ctx->flags & (NLM_F_APPEND | NLM_F_REPLACE)) 2946 + flags |= NLM_F_APPEND; 2947 + if (ctx->flags & (NLM_F_CREATE | NLM_F_EXCL)) 2948 + flags |= ctx->flags & (NLM_F_CREATE | NLM_F_EXCL); 2949 + 2948 2950 err = nf_tables_fill_rule_info(skb, ctx->net, ctx->portid, ctx->seq, 2949 - event, 0, ctx->family, ctx->table, 2950 - ctx->chain, rule, NULL); 2951 + event, flags, ctx->family, ctx->table, 2952 + ctx->chain, rule, handle); 2951 2953 if (err < 0) { 2952 2954 kfree_skb(skb); 2953 2955 goto err; ··· 2984 2964 struct net *net = sock_net(skb->sk); 2985 2965 const struct nft_rule *rule, *prule; 2986 2966 unsigned int s_idx = cb->args[0]; 2967 + u64 handle; 2987 2968 2988 2969 prule = NULL; 2989 2970 list_for_each_entry_rcu(rule, &chain->rules, list) { ··· 2996 2975 memset(&cb->args[1], 0, 2997 2976 sizeof(cb->args) - sizeof(cb->args[0])); 2998 2977 } 2978 + if (prule) 2979 + handle = prule->handle; 2980 + else 2981 + handle = 0; 2982 + 2999 2983 if (nf_tables_fill_rule_info(skb, net, NETLINK_CB(cb->skb).portid, 3000 2984 cb->nlh->nlmsg_seq, 3001 2985 NFT_MSG_NEWRULE, 3002 2986 NLM_F_MULTI | NLM_F_APPEND, 3003 2987 table->family, 3004 - table, chain, rule, prule) < 0) 2988 + table, chain, rule, handle) < 0) 3005 2989 return 1; 3006 2990 3007 2991 nl_dump_check_consistent(cb, nlmsg_hdr(skb)); ··· 3169 3143 3170 3144 err = nf_tables_fill_rule_info(skb2, net, NETLINK_CB(skb).portid, 3171 3145 info->nlh->nlmsg_seq, NFT_MSG_NEWRULE, 0, 3172 - family, table, chain, rule, NULL); 3146 + family, table, chain, rule, 0); 3173 3147 if (err < 0) 3174 3148 goto err_fill_rule_info; 3175 3149 ··· 3429 3403 } 3430 3404 3431 3405 if (info->nlh->nlmsg_flags & NLM_F_REPLACE) { 3406 + err = nft_delrule(&ctx, old_rule); 3407 + if (err < 0) 3408 + goto err_destroy_flow_rule; 3409 + 3432 3410 trans = nft_trans_rule_add(&ctx, NFT_MSG_NEWRULE, rule); 3433 3411 if (trans == NULL) { 3434 3412 err = -ENOMEM; 3435 3413 goto err_destroy_flow_rule; 3436 3414 } 3437 - err = nft_delrule(&ctx, old_rule); 3438 - if (err < 0) { 3439 - nft_trans_destroy(trans); 3440 - goto err_destroy_flow_rule; 3441 - } 3442 - 3443 3415 list_add_tail_rcu(&rule->list, &old_rule->list); 3444 3416 } else { 3445 3417 trans = nft_trans_rule_add(&ctx, NFT_MSG_NEWRULE, rule); ··· 3967 3943 gfp_t gfp_flags) 3968 3944 { 3969 3945 struct nftables_pernet *nft_net = nft_pernet(ctx->net); 3970 - struct sk_buff *skb; 3971 3946 u32 portid = ctx->portid; 3947 + struct sk_buff *skb; 3948 + u16 flags = 0; 3972 3949 int err; 3973 3950 3974 3951 if (!ctx->report && ··· 3980 3955 if (skb == NULL) 3981 3956 goto err; 3982 3957 3983 - err = nf_tables_fill_set(skb, ctx, set, event, 0); 3958 + if (ctx->flags & (NLM_F_CREATE | NLM_F_EXCL)) 3959 + flags |= ctx->flags & (NLM_F_CREATE | NLM_F_EXCL); 3960 + 3961 + err = nf_tables_fill_set(skb, ctx, set, event, flags); 3984 3962 if (err < 0) { 3985 3963 kfree_skb(skb); 3986 3964 goto err; ··· 5259 5231 static void nf_tables_setelem_notify(const struct nft_ctx *ctx, 5260 5232 const struct nft_set *set, 5261 5233 const struct nft_set_elem *elem, 5262 - int event, u16 flags) 5234 + int event) 5263 5235 { 5264 5236 struct nftables_pernet *nft_net; 5265 5237 struct net *net = ctx->net; 5266 5238 u32 portid = ctx->portid; 5267 5239 struct sk_buff *skb; 5240 + u16 flags = 0; 5268 5241 int err; 5269 5242 5270 5243 if (!ctx->report && !nfnetlink_has_listeners(net, NFNLGRP_NFTABLES)) ··· 5274 5245 skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); 5275 5246 if (skb == NULL) 5276 5247 goto err; 5248 + 5249 + if (ctx->flags & (NLM_F_CREATE | NLM_F_EXCL)) 5250 + flags |= ctx->flags & (NLM_F_CREATE | NLM_F_EXCL); 5277 5251 5278 5252 err = nf_tables_fill_setelem_info(skb, ctx, 0, portid, event, flags, 5279 5253 set, elem); ··· 6953 6921 6954 6922 void nft_obj_notify(struct net *net, const struct nft_table *table, 6955 6923 struct nft_object *obj, u32 portid, u32 seq, int event, 6956 - int family, int report, gfp_t gfp) 6924 + u16 flags, int family, int report, gfp_t gfp) 6957 6925 { 6958 6926 struct nftables_pernet *nft_net = nft_pernet(net); 6959 6927 struct sk_buff *skb; ··· 6978 6946 if (skb == NULL) 6979 6947 goto err; 6980 6948 6981 - err = nf_tables_fill_obj_info(skb, net, portid, seq, event, 0, family, 6982 - table, obj, false); 6949 + err = nf_tables_fill_obj_info(skb, net, portid, seq, event, 6950 + flags & (NLM_F_CREATE | NLM_F_EXCL), 6951 + family, table, obj, false); 6983 6952 if (err < 0) { 6984 6953 kfree_skb(skb); 6985 6954 goto err; ··· 6997 6964 struct nft_object *obj, int event) 6998 6965 { 6999 6966 nft_obj_notify(ctx->net, ctx->table, obj, ctx->portid, ctx->seq, event, 7000 - ctx->family, ctx->report, GFP_KERNEL); 6967 + ctx->flags, ctx->family, ctx->report, GFP_KERNEL); 7001 6968 } 7002 6969 7003 6970 /* ··· 7778 7745 { 7779 7746 struct nftables_pernet *nft_net = nft_pernet(ctx->net); 7780 7747 struct sk_buff *skb; 7748 + u16 flags = 0; 7781 7749 int err; 7782 7750 7783 7751 if (!ctx->report && ··· 7789 7755 if (skb == NULL) 7790 7756 goto err; 7791 7757 7758 + if (ctx->flags & (NLM_F_CREATE | NLM_F_EXCL)) 7759 + flags |= ctx->flags & (NLM_F_CREATE | NLM_F_EXCL); 7760 + 7792 7761 err = nf_tables_fill_flowtable_info(skb, ctx->net, ctx->portid, 7793 - ctx->seq, event, 0, 7762 + ctx->seq, event, flags, 7794 7763 ctx->family, flowtable, hook_list); 7795 7764 if (err < 0) { 7796 7765 kfree_skb(skb); ··· 8671 8634 nft_setelem_activate(net, te->set, &te->elem); 8672 8635 nf_tables_setelem_notify(&trans->ctx, te->set, 8673 8636 &te->elem, 8674 - NFT_MSG_NEWSETELEM, 0); 8637 + NFT_MSG_NEWSETELEM); 8675 8638 nft_trans_destroy(trans); 8676 8639 break; 8677 8640 case NFT_MSG_DELSETELEM: ··· 8679 8642 8680 8643 nf_tables_setelem_notify(&trans->ctx, te->set, 8681 8644 &te->elem, 8682 - NFT_MSG_DELSETELEM, 0); 8645 + NFT_MSG_DELSETELEM); 8683 8646 nft_setelem_remove(net, te->set, &te->elem); 8684 8647 if (!nft_setelem_is_catchall(te->set, &te->elem)) { 8685 8648 atomic_dec(&te->set->nelems);
+1 -1
net/netfilter/nft_quota.c
··· 60 60 if (overquota && 61 61 !test_and_set_bit(NFT_QUOTA_DEPLETED_BIT, &priv->flags)) 62 62 nft_obj_notify(nft_net(pkt), obj->key.table, obj, 0, 0, 63 - NFT_MSG_NEWOBJ, nft_pf(pkt), 0, GFP_ATOMIC); 63 + NFT_MSG_NEWOBJ, 0, nft_pf(pkt), 0, GFP_ATOMIC); 64 64 } 65 65 66 66 static int nft_quota_do_init(const struct nlattr * const tb[],