rtnetlink: always put IFLA_LINK for links with a link-netnsid [Linux 4.19.46]

rtnetlink: always put IFLA_LINK for links with a link-netnsid [Linux 4.19.46]

This Linux kernel change "rtnetlink: always put IFLA_LINK for links with a link-netnsid" is included in the Linux 4.19.46 release. This change is authored by Sabrina Dubroca <sd [at] queasysnail.net> on Tue May 14 15:12:19 2019 +0200. The commit for this change in Linux stable tree is 2636da6 (patch) which is from upstream commit feadc4b. The same Linux upstream change may have been applied to various maintained Linux releases and you can find all Linux releases containing changes from upstream feadc4b.

rtnetlink: always put IFLA_LINK for links with a link-netnsid

[ Upstream commit feadc4b6cf42a53a8a93c918a569a0b7e62bd350 ]

Currently, nla_put_iflink() doesn't put the IFLA_LINK attribute when
iflink == ifindex.

In some cases, a device can be created in a different netns with the
same ifindex as its parent. That device will not dump its IFLA_LINK
attribute, which can confuse some userspace software that expects it.
For example, if the last ifindex created in init_net and foo are both
8, these commands will trigger the issue:

    ip link add parent type dummy                   # ifindex 9
    ip link add link parent netns foo type macvlan  # ifindex 9 in ns foo

So, in case a device puts the IFLA_LINK_NETNSID attribute in a dump,
always put the IFLA_LINK attribute as well.

Thanks to Dan Winship for analyzing the original OpenShift bug down to
the missing netlink attribute.

v2: change Fixes tag, it's been here forever, as Nicolas Dichtel said
    add Nicolas' ack
v3: change Fixes tag
    fix subject typo, spotted by Edward Cree

Analyzed-by: Dan Winship <danw@redhat.com>
Fixes: d8a5ec672768 ("[NET]: netlink support for moving devices between network namespaces.")
Signed-off-by: Sabrina Dubroca <sd@queasysnail.net>
Acked-by: Nicolas Dichtel <nicolas.dichtel@6wind.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

There are 16 lines of Linux source code added/deleted in this change. Code changes to Linux kernel are as follows.

 net/core/rtnetlink.c | 16 ++++++++++------
 1 file changed, 10 insertions(+), 6 deletions(-)

diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index ebde98b..3932eed 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -1496,14 +1496,15 @@ static int put_master_ifindex(struct sk_buff *skb, struct net_device *dev)
    return ret;
 }

-static int nla_put_iflink(struct sk_buff *skb, const struct net_device *dev)
+static int nla_put_iflink(struct sk_buff *skb, const struct net_device *dev,
+             bool force)
 {
    int ifindex = dev_get_iflink(dev);

-   if (dev->ifindex == ifindex)
-       return 0;
+   if (force || dev->ifindex != ifindex)
+       return nla_put_u32(skb, IFLA_LINK, ifindex);

-   return nla_put_u32(skb, IFLA_LINK, ifindex);
+   return 0;
 }

 static noinline_for_stack int nla_put_ifalias(struct sk_buff *skb,
@@ -1520,6 +1521,8 @@ static int rtnl_fill_link_netnsid(struct sk_buff *skb,
                  const struct net_device *dev,
                  struct net *src_net)
 {
+   bool put_iflink = false;
+
    if (dev->rtnl_link_ops && dev->rtnl_link_ops->get_link_net) {
        struct net *link_net = dev->rtnl_link_ops->get_link_net(dev);

@@ -1528,10 +1531,12 @@ static int rtnl_fill_link_netnsid(struct sk_buff *skb,

            if (nla_put_s32(skb, IFLA_LINK_NETNSID, id))
                return -EMSGSIZE;
+
+           put_iflink = true;
        }
    }

-   return 0;
+   return nla_put_iflink(skb, dev, put_iflink);
 }

 static int rtnl_fill_link_af(struct sk_buff *skb,
@@ -1617,7 +1622,6 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb,
 #ifdef CONFIG_RPS
        nla_put_u32(skb, IFLA_NUM_RX_QUEUES, dev->num_rx_queues) ||
 #endif
-       nla_put_iflink(skb, dev) ||
        put_master_ifindex(skb, dev) ||
        nla_put_u8(skb, IFLA_CARRIER, netif_carrier_ok(dev)) ||
        (dev->qdisc &&

Leave a Reply

Your email address will not be published. Required fields are marked *