netlink: ensure to loop over all netns in genlmsg_multicast_allns()
authorNicolas Dichtel <nicolas.dichtel@6wind.com>
Tue, 6 Feb 2018 13:48:32 +0000 (14:48 +0100)
committerSasha Levin <alexander.levin@microsoft.com>
Wed, 21 Mar 2018 03:49:48 +0000 (23:49 -0400)
[ Upstream commit cb9f7a9a5c96a773bbc9c70660dc600cfff82f82 ]

Nowadays, nlmsg_multicast() returns only 0 or -ESRCH but this was not the
case when commit 134e63756d5f was pushed.
However, there was no reason to stop the loop if a netns does not have
listeners.
Returns -ESRCH only if there was no listeners in all netns.

To avoid having the same problem in the future, I didn't take the
assumption that nlmsg_multicast() returns only 0 or -ESRCH.

Fixes: 134e63756d5f ("genetlink: make netns aware")
CC: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Nicolas Dichtel <nicolas.dichtel@6wind.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Sasha Levin <alexander.levin@microsoft.com>
net/netlink/genetlink.c

index 3d111b053e3e0d70e0611c99deac3c8aac01632c..97c22c8181345023a47ec8422fa527ede8009a7b 100644 (file)
@@ -1118,6 +1118,7 @@ static int genlmsg_mcast(struct sk_buff *skb, u32 portid, unsigned long group,
 {
        struct sk_buff *tmp;
        struct net *net, *prev = NULL;
+       bool delivered = false;
        int err;
 
        for_each_net_rcu(net) {
@@ -1129,14 +1130,21 @@ static int genlmsg_mcast(struct sk_buff *skb, u32 portid, unsigned long group,
                        }
                        err = nlmsg_multicast(prev->genl_sock, tmp,
                                              portid, group, flags);
-                       if (err)
+                       if (!err)
+                               delivered = true;
+                       else if (err != -ESRCH)
                                goto error;
                }
 
                prev = net;
        }
 
-       return nlmsg_multicast(prev->genl_sock, skb, portid, group, flags);
+       err = nlmsg_multicast(prev->genl_sock, skb, portid, group, flags);
+       if (!err)
+               delivered = true;
+       else if (err != -ESRCH)
+               goto error;
+       return delivered ? 0 : -ESRCH;
  error:
        kfree_skb(skb);
        return err;