]> www.infradead.org Git - users/dwmw2/linux.git/commitdiff
netfilter: nfnetlink: nfnetlink_unicast() reports EAGAIN instead of ENOBUFS
authorPablo Neira Ayuso <pablo@netfilter.org>
Sun, 23 Aug 2020 11:55:36 +0000 (13:55 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 9 Sep 2020 17:12:27 +0000 (19:12 +0200)
[ Upstream commit ee921183557af39c1a0475f982d43b0fcac25e2e ]

Frontend callback reports EAGAIN to nfnetlink to retry a command, this
is used to signal that module autoloading is required. Unfortunately,
nlmsg_unicast() reports EAGAIN in case the receiver socket buffer gets
full, so it enters a busy-loop.

This patch updates nfnetlink_unicast() to turn EAGAIN into ENOBUFS and
to use nlmsg_unicast(). Remove the flags field in nfnetlink_unicast()
since this is always MSG_DONTWAIT in the existing code which is exactly
what nlmsg_unicast() passes to netlink_unicast() as parameter.

Fixes: 96518518cc41 ("netfilter: add nftables")
Reported-by: Phil Sutter <phil@nwl.cc>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
include/linux/netfilter/nfnetlink.h
net/netfilter/nf_tables_api.c
net/netfilter/nfnetlink.c
net/netfilter/nfnetlink_log.c
net/netfilter/nfnetlink_queue.c

index 851425c3178f178d3c325773f2a77fa9ec6e3c40..89016d08f6a278d9a7703cc4256c277f05fa7173 100644 (file)
@@ -43,8 +43,7 @@ int nfnetlink_has_listeners(struct net *net, unsigned int group);
 int nfnetlink_send(struct sk_buff *skb, struct net *net, u32 portid,
                   unsigned int group, int echo, gfp_t flags);
 int nfnetlink_set_err(struct net *net, u32 portid, u32 group, int error);
-int nfnetlink_unicast(struct sk_buff *skb, struct net *net, u32 portid,
-                     int flags);
+int nfnetlink_unicast(struct sk_buff *skb, struct net *net, u32 portid);
 
 static inline u16 nfnl_msg_type(u8 subsys, u8 msg_type)
 {
index c1920adb27e62772858db3ebef1caa0f3a767a2e..2023650c272493b5792c23aebbbeea3fee6ee416 100644 (file)
@@ -744,11 +744,11 @@ static int nf_tables_gettable(struct net *net, struct sock *nlsk,
                                        nlh->nlmsg_seq, NFT_MSG_NEWTABLE, 0,
                                        family, table);
        if (err < 0)
-               goto err;
+               goto err_fill_table_info;
 
-       return nlmsg_unicast(nlsk, skb2, NETLINK_CB(skb).portid);
+       return nfnetlink_unicast(skb2, net, NETLINK_CB(skb).portid);
 
-err:
+err_fill_table_info:
        kfree_skb(skb2);
        return err;
 }
@@ -1443,11 +1443,11 @@ static int nf_tables_getchain(struct net *net, struct sock *nlsk,
                                        nlh->nlmsg_seq, NFT_MSG_NEWCHAIN, 0,
                                        family, table, chain);
        if (err < 0)
-               goto err;
+               goto err_fill_chain_info;
 
-       return nlmsg_unicast(nlsk, skb2, NETLINK_CB(skb).portid);
+       return nfnetlink_unicast(skb2, net, NETLINK_CB(skb).portid);
 
-err:
+err_fill_chain_info:
        kfree_skb(skb2);
        return err;
 }
@@ -2622,11 +2622,11 @@ static int nf_tables_getrule(struct net *net, struct sock *nlsk,
                                       nlh->nlmsg_seq, NFT_MSG_NEWRULE, 0,
                                       family, table, chain, rule, NULL);
        if (err < 0)
-               goto err;
+               goto err_fill_rule_info;
 
-       return nlmsg_unicast(nlsk, skb2, NETLINK_CB(skb).portid);
+       return nfnetlink_unicast(skb2, net, NETLINK_CB(skb).portid);
 
-err:
+err_fill_rule_info:
        kfree_skb(skb2);
        return err;
 }
@@ -3526,11 +3526,11 @@ static int nf_tables_getset(struct net *net, struct sock *nlsk,
 
        err = nf_tables_fill_set(skb2, &ctx, set, NFT_MSG_NEWSET, 0);
        if (err < 0)
-               goto err;
+               goto err_fill_set_info;
 
-       return nlmsg_unicast(nlsk, skb2, NETLINK_CB(skb).portid);
+       return nfnetlink_unicast(skb2, net, NETLINK_CB(skb).portid);
 
-err:
+err_fill_set_info:
        kfree_skb(skb2);
        return err;
 }
@@ -4305,24 +4305,18 @@ static int nft_get_set_elem(struct nft_ctx *ctx, struct nft_set *set,
        err = -ENOMEM;
        skb = nlmsg_new(NLMSG_GOODSIZE, GFP_ATOMIC);
        if (skb == NULL)
-               goto err1;
+               return err;
 
        err = nf_tables_fill_setelem_info(skb, ctx, ctx->seq, ctx->portid,
                                          NFT_MSG_NEWSETELEM, 0, set, &elem);
        if (err < 0)
-               goto err2;
+               goto err_fill_setelem;
 
-       err = nfnetlink_unicast(skb, ctx->net, ctx->portid, MSG_DONTWAIT);
-       /* This avoids a loop in nfnetlink. */
-       if (err < 0)
-               goto err1;
+       return nfnetlink_unicast(skb, ctx->net, ctx->portid);
 
-       return 0;
-err2:
+err_fill_setelem:
        kfree_skb(skb);
-err1:
-       /* this avoids a loop in nfnetlink. */
-       return err == -EAGAIN ? -ENOBUFS : err;
+       return err;
 }
 
 /* called with rcu_read_lock held */
@@ -5499,10 +5493,11 @@ static int nf_tables_getobj(struct net *net, struct sock *nlsk,
                                      nlh->nlmsg_seq, NFT_MSG_NEWOBJ, 0,
                                      family, table, obj, reset);
        if (err < 0)
-               goto err;
+               goto err_fill_obj_info;
 
-       return nlmsg_unicast(nlsk, skb2, NETLINK_CB(skb).portid);
-err:
+       return nfnetlink_unicast(skb2, net, NETLINK_CB(skb).portid);
+
+err_fill_obj_info:
        kfree_skb(skb2);
        return err;
 }
@@ -6174,10 +6169,11 @@ static int nf_tables_getflowtable(struct net *net, struct sock *nlsk,
                                            NFT_MSG_NEWFLOWTABLE, 0, family,
                                            flowtable);
        if (err < 0)
-               goto err;
+               goto err_fill_flowtable_info;
 
-       return nlmsg_unicast(nlsk, skb2, NETLINK_CB(skb).portid);
-err:
+       return nfnetlink_unicast(skb2, net, NETLINK_CB(skb).portid);
+
+err_fill_flowtable_info:
        kfree_skb(skb2);
        return err;
 }
@@ -6338,10 +6334,11 @@ static int nf_tables_getgen(struct net *net, struct sock *nlsk,
        err = nf_tables_fill_gen_info(skb2, net, NETLINK_CB(skb).portid,
                                      nlh->nlmsg_seq);
        if (err < 0)
-               goto err;
+               goto err_fill_gen_info;
 
-       return nlmsg_unicast(nlsk, skb2, NETLINK_CB(skb).portid);
-err:
+       return nfnetlink_unicast(skb2, net, NETLINK_CB(skb).portid);
+
+err_fill_gen_info:
        kfree_skb(skb2);
        return err;
 }
index 99127e2d95a842e5b8e45da4847715e62709ca4c..6d03b0909621097d8ace39bddf99a191e6a493e9 100644 (file)
@@ -148,10 +148,15 @@ int nfnetlink_set_err(struct net *net, u32 portid, u32 group, int error)
 }
 EXPORT_SYMBOL_GPL(nfnetlink_set_err);
 
-int nfnetlink_unicast(struct sk_buff *skb, struct net *net, u32 portid,
-                     int flags)
+int nfnetlink_unicast(struct sk_buff *skb, struct net *net, u32 portid)
 {
-       return netlink_unicast(net->nfnl, skb, portid, flags);
+       int err;
+
+       err = nlmsg_unicast(net->nfnl, skb, portid);
+       if (err == -EAGAIN)
+               err = -ENOBUFS;
+
+       return err;
 }
 EXPORT_SYMBOL_GPL(nfnetlink_unicast);
 
index 0ba020ca38e68cde127fca47439d5bb2a5a456d6..7ca2ca4bba05591119d04a61e772d9e62783c43b 100644 (file)
@@ -356,8 +356,7 @@ __nfulnl_send(struct nfulnl_instance *inst)
                        goto out;
                }
        }
-       nfnetlink_unicast(inst->skb, inst->net, inst->peer_portid,
-                         MSG_DONTWAIT);
+       nfnetlink_unicast(inst->skb, inst->net, inst->peer_portid);
 out:
        inst->qlen = 0;
        inst->skb = NULL;
index feabdfb22920b22d3e52a4d43ac960acca0db34c..6f0a2bad8ad5eecc4add1b56e08ae5b3b2b19a60 100644 (file)
@@ -681,7 +681,7 @@ __nfqnl_enqueue_packet(struct net *net, struct nfqnl_instance *queue,
        *packet_id_ptr = htonl(entry->id);
 
        /* nfnetlink_unicast will either free the nskb or add it to a socket */
-       err = nfnetlink_unicast(nskb, net, queue->peer_portid, MSG_DONTWAIT);
+       err = nfnetlink_unicast(nskb, net, queue->peer_portid);
        if (err < 0) {
                if (queue->flags & NFQA_CFG_F_FAIL_OPEN) {
                        failopen = 1;