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

netfilter: nf_tables: honor NLM_F_CREATE and NLM_F_EXCL in event notification

Include the NLM_F_CREATE and NLM_F_EXCL flags in netlink event
notifications, otherwise userspace cannot distiguish between create and
add commands.

Fixes: 96518518cc41 ("netfilter: add nftables")
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>

+37 -14
+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
+35 -12
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); ··· 2953 2945 } 2954 2946 if (ctx->flags & (NLM_F_APPEND | NLM_F_REPLACE)) 2955 2947 flags |= NLM_F_APPEND; 2948 + if (ctx->flags & (NLM_F_CREATE | NLM_F_EXCL)) 2949 + flags |= ctx->flags & (NLM_F_CREATE | NLM_F_EXCL); 2956 2950 2957 2951 err = nf_tables_fill_rule_info(skb, ctx->net, ctx->portid, ctx->seq, 2958 2952 event, flags, ctx->family, ctx->table, ··· 3967 3957 gfp_t gfp_flags) 3968 3958 { 3969 3959 struct nftables_pernet *nft_net = nft_pernet(ctx->net); 3970 - struct sk_buff *skb; 3971 3960 u32 portid = ctx->portid; 3961 + struct sk_buff *skb; 3962 + u16 flags = 0; 3972 3963 int err; 3973 3964 3974 3965 if (!ctx->report && ··· 3980 3969 if (skb == NULL) 3981 3970 goto err; 3982 3971 3983 - err = nf_tables_fill_set(skb, ctx, set, event, 0); 3972 + if (ctx->flags & (NLM_F_CREATE | NLM_F_EXCL)) 3973 + flags |= ctx->flags & (NLM_F_CREATE | NLM_F_EXCL); 3974 + 3975 + err = nf_tables_fill_set(skb, ctx, set, event, flags); 3984 3976 if (err < 0) { 3985 3977 kfree_skb(skb); 3986 3978 goto err; ··· 5259 5245 static void nf_tables_setelem_notify(const struct nft_ctx *ctx, 5260 5246 const struct nft_set *set, 5261 5247 const struct nft_set_elem *elem, 5262 - int event, u16 flags) 5248 + int event) 5263 5249 { 5264 5250 struct nftables_pernet *nft_net; 5265 5251 struct net *net = ctx->net; 5266 5252 u32 portid = ctx->portid; 5267 5253 struct sk_buff *skb; 5254 + u16 flags = 0; 5268 5255 int err; 5269 5256 5270 5257 if (!ctx->report && !nfnetlink_has_listeners(net, NFNLGRP_NFTABLES)) ··· 5274 5259 skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); 5275 5260 if (skb == NULL) 5276 5261 goto err; 5262 + 5263 + if (ctx->flags & (NLM_F_CREATE | NLM_F_EXCL)) 5264 + flags |= ctx->flags & (NLM_F_CREATE | NLM_F_EXCL); 5277 5265 5278 5266 err = nf_tables_fill_setelem_info(skb, ctx, 0, portid, event, flags, 5279 5267 set, elem); ··· 6953 6935 6954 6936 void nft_obj_notify(struct net *net, const struct nft_table *table, 6955 6937 struct nft_object *obj, u32 portid, u32 seq, int event, 6956 - int family, int report, gfp_t gfp) 6938 + u16 flags, int family, int report, gfp_t gfp) 6957 6939 { 6958 6940 struct nftables_pernet *nft_net = nft_pernet(net); 6959 6941 struct sk_buff *skb; ··· 6978 6960 if (skb == NULL) 6979 6961 goto err; 6980 6962 6981 - err = nf_tables_fill_obj_info(skb, net, portid, seq, event, 0, family, 6982 - table, obj, false); 6963 + err = nf_tables_fill_obj_info(skb, net, portid, seq, event, 6964 + flags & (NLM_F_CREATE | NLM_F_EXCL), 6965 + family, table, obj, false); 6983 6966 if (err < 0) { 6984 6967 kfree_skb(skb); 6985 6968 goto err; ··· 6997 6978 struct nft_object *obj, int event) 6998 6979 { 6999 6980 nft_obj_notify(ctx->net, ctx->table, obj, ctx->portid, ctx->seq, event, 7000 - ctx->family, ctx->report, GFP_KERNEL); 6981 + ctx->flags, ctx->family, ctx->report, GFP_KERNEL); 7001 6982 } 7002 6983 7003 6984 /* ··· 7778 7759 { 7779 7760 struct nftables_pernet *nft_net = nft_pernet(ctx->net); 7780 7761 struct sk_buff *skb; 7762 + u16 flags = 0; 7781 7763 int err; 7782 7764 7783 7765 if (!ctx->report && ··· 7789 7769 if (skb == NULL) 7790 7770 goto err; 7791 7771 7772 + if (ctx->flags & (NLM_F_CREATE | NLM_F_EXCL)) 7773 + flags |= ctx->flags & (NLM_F_CREATE | NLM_F_EXCL); 7774 + 7792 7775 err = nf_tables_fill_flowtable_info(skb, ctx->net, ctx->portid, 7793 - ctx->seq, event, 0, 7776 + ctx->seq, event, flags, 7794 7777 ctx->family, flowtable, hook_list); 7795 7778 if (err < 0) { 7796 7779 kfree_skb(skb); ··· 8671 8648 nft_setelem_activate(net, te->set, &te->elem); 8672 8649 nf_tables_setelem_notify(&trans->ctx, te->set, 8673 8650 &te->elem, 8674 - NFT_MSG_NEWSETELEM, 0); 8651 + NFT_MSG_NEWSETELEM); 8675 8652 nft_trans_destroy(trans); 8676 8653 break; 8677 8654 case NFT_MSG_DELSETELEM: ··· 8679 8656 8680 8657 nf_tables_setelem_notify(&trans->ctx, te->set, 8681 8658 &te->elem, 8682 - NFT_MSG_DELSETELEM, 0); 8659 + NFT_MSG_DELSETELEM); 8683 8660 nft_setelem_remove(net, te->set, &te->elem); 8684 8661 if (!nft_setelem_is_catchall(te->set, &te->elem)) { 8685 8662 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[],