aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJiri Benc <jbenc@redhat.com>2017-11-02 15:04:38 -0400
committerDavid S. Miller <davem@davemloft.net>2017-11-05 07:49:17 -0500
commit79e1ad148c844f5c8b9d76b36b26e3886dca95ae (patch)
tree5f627e30c0f3972db04c2e012474dc5486d8955b
parent9354d452034273a50a4fd703bea31e5d6b1fc20b (diff)
rtnetlink: use netnsid to query interface
Currently, when an application gets netnsid from the kernel (for example as the result of RTM_GETLINK call on one end of the veth pair), it's not much useful. There's no reliable way to get to the netns fd from the netnsid, nor does any kernel API accept netnsid. Extend the RTM_GETLINK call to also accept netnsid. It will operate on the netns with the given netnsid in such case. Of course, the calling process needs to have enough capabilities in the target name space; for now, require CAP_NET_ADMIN. This can be relaxed in the future. To signal to the calling process that the kernel understood the new IFLA_IF_NETNSID attribute in the query, it will include it in the response. This is needed to detect older kernels, as they will just ignore IFLA_IF_NETNSID and query in the current name space. This patch implemetns IFLA_IF_NETNSID only for get and dump. For set operations, this can be extended later. Signed-off-by: Jiri Benc <jbenc@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/uapi/linux/if_link.h1
-rw-r--r--net/core/rtnetlink.c103
2 files changed, 86 insertions, 18 deletions
diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h
index b3cf5639ac8f..19fc02660e0c 100644
--- a/include/uapi/linux/if_link.h
+++ b/include/uapi/linux/if_link.h
@@ -160,6 +160,7 @@ enum {
160 IFLA_XDP, 160 IFLA_XDP,
161 IFLA_EVENT, 161 IFLA_EVENT,
162 IFLA_NEW_NETNSID, 162 IFLA_NEW_NETNSID,
163 IFLA_IF_NETNSID,
163 __IFLA_MAX 164 __IFLA_MAX
164}; 165};
165 166
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index de24d394c69e..8a8c51937edf 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -921,7 +921,8 @@ static noinline size_t if_nlmsg_size(const struct net_device *dev,
921 + nla_total_size(4) /* IFLA_EVENT */ 921 + nla_total_size(4) /* IFLA_EVENT */
922 + nla_total_size(4) /* IFLA_NEW_NETNSID */ 922 + nla_total_size(4) /* IFLA_NEW_NETNSID */
923 + nla_total_size(1); /* IFLA_PROTO_DOWN */ 923 + nla_total_size(1); /* IFLA_PROTO_DOWN */
924 924 + nla_total_size(4) /* IFLA_IF_NETNSID */
925 + 0;
925} 926}
926 927
927static int rtnl_vf_ports_fill(struct sk_buff *skb, struct net_device *dev) 928static int rtnl_vf_ports_fill(struct sk_buff *skb, struct net_device *dev)
@@ -1370,13 +1371,14 @@ static noinline_for_stack int nla_put_ifalias(struct sk_buff *skb,
1370} 1371}
1371 1372
1372static int rtnl_fill_link_netnsid(struct sk_buff *skb, 1373static int rtnl_fill_link_netnsid(struct sk_buff *skb,
1373 const struct net_device *dev) 1374 const struct net_device *dev,
1375 struct net *src_net)
1374{ 1376{
1375 if (dev->rtnl_link_ops && dev->rtnl_link_ops->get_link_net) { 1377 if (dev->rtnl_link_ops && dev->rtnl_link_ops->get_link_net) {
1376 struct net *link_net = dev->rtnl_link_ops->get_link_net(dev); 1378 struct net *link_net = dev->rtnl_link_ops->get_link_net(dev);
1377 1379
1378 if (!net_eq(dev_net(dev), link_net)) { 1380 if (!net_eq(dev_net(dev), link_net)) {
1379 int id = peernet2id_alloc(dev_net(dev), link_net); 1381 int id = peernet2id_alloc(src_net, link_net);
1380 1382
1381 if (nla_put_s32(skb, IFLA_LINK_NETNSID, id)) 1383 if (nla_put_s32(skb, IFLA_LINK_NETNSID, id))
1382 return -EMSGSIZE; 1384 return -EMSGSIZE;
@@ -1427,10 +1429,11 @@ static int rtnl_fill_link_af(struct sk_buff *skb,
1427 return 0; 1429 return 0;
1428} 1430}
1429 1431
1430static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev, 1432static int rtnl_fill_ifinfo(struct sk_buff *skb,
1433 struct net_device *dev, struct net *src_net,
1431 int type, u32 pid, u32 seq, u32 change, 1434 int type, u32 pid, u32 seq, u32 change,
1432 unsigned int flags, u32 ext_filter_mask, 1435 unsigned int flags, u32 ext_filter_mask,
1433 u32 event, int *new_nsid) 1436 u32 event, int *new_nsid, int tgt_netnsid)
1434{ 1437{
1435 struct ifinfomsg *ifm; 1438 struct ifinfomsg *ifm;
1436 struct nlmsghdr *nlh; 1439 struct nlmsghdr *nlh;
@@ -1448,6 +1451,9 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev,
1448 ifm->ifi_flags = dev_get_flags(dev); 1451 ifm->ifi_flags = dev_get_flags(dev);
1449 ifm->ifi_change = change; 1452 ifm->ifi_change = change;
1450 1453
1454 if (tgt_netnsid >= 0 && nla_put_s32(skb, IFLA_IF_NETNSID, tgt_netnsid))
1455 goto nla_put_failure;
1456
1451 if (nla_put_string(skb, IFLA_IFNAME, dev->name) || 1457 if (nla_put_string(skb, IFLA_IFNAME, dev->name) ||
1452 nla_put_u32(skb, IFLA_TXQLEN, dev->tx_queue_len) || 1458 nla_put_u32(skb, IFLA_TXQLEN, dev->tx_queue_len) ||
1453 nla_put_u8(skb, IFLA_OPERSTATE, 1459 nla_put_u8(skb, IFLA_OPERSTATE,
@@ -1513,7 +1519,7 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev,
1513 goto nla_put_failure; 1519 goto nla_put_failure;
1514 } 1520 }
1515 1521
1516 if (rtnl_fill_link_netnsid(skb, dev)) 1522 if (rtnl_fill_link_netnsid(skb, dev, src_net))
1517 goto nla_put_failure; 1523 goto nla_put_failure;
1518 1524
1519 if (new_nsid && 1525 if (new_nsid &&
@@ -1571,6 +1577,7 @@ static const struct nla_policy ifla_policy[IFLA_MAX+1] = {
1571 [IFLA_XDP] = { .type = NLA_NESTED }, 1577 [IFLA_XDP] = { .type = NLA_NESTED },
1572 [IFLA_EVENT] = { .type = NLA_U32 }, 1578 [IFLA_EVENT] = { .type = NLA_U32 },
1573 [IFLA_GROUP] = { .type = NLA_U32 }, 1579 [IFLA_GROUP] = { .type = NLA_U32 },
1580 [IFLA_IF_NETNSID] = { .type = NLA_S32 },
1574}; 1581};
1575 1582
1576static const struct nla_policy ifla_info_policy[IFLA_INFO_MAX+1] = { 1583static const struct nla_policy ifla_info_policy[IFLA_INFO_MAX+1] = {
@@ -1674,9 +1681,28 @@ static bool link_dump_filtered(struct net_device *dev,
1674 return false; 1681 return false;
1675} 1682}
1676 1683
1684static struct net *get_target_net(struct sk_buff *skb, int netnsid)
1685{
1686 struct net *net;
1687
1688 net = get_net_ns_by_id(sock_net(skb->sk), netnsid);
1689 if (!net)
1690 return ERR_PTR(-EINVAL);
1691
1692 /* For now, the caller is required to have CAP_NET_ADMIN in
1693 * the user namespace owning the target net ns.
1694 */
1695 if (!netlink_ns_capable(skb, net->user_ns, CAP_NET_ADMIN)) {
1696 put_net(net);
1697 return ERR_PTR(-EACCES);
1698 }
1699 return net;
1700}
1701
1677static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb) 1702static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
1678{ 1703{
1679 struct net *net = sock_net(skb->sk); 1704 struct net *net = sock_net(skb->sk);
1705 struct net *tgt_net = net;
1680 int h, s_h; 1706 int h, s_h;
1681 int idx = 0, s_idx; 1707 int idx = 0, s_idx;
1682 struct net_device *dev; 1708 struct net_device *dev;
@@ -1686,6 +1712,7 @@ static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
1686 const struct rtnl_link_ops *kind_ops = NULL; 1712 const struct rtnl_link_ops *kind_ops = NULL;
1687 unsigned int flags = NLM_F_MULTI; 1713 unsigned int flags = NLM_F_MULTI;
1688 int master_idx = 0; 1714 int master_idx = 0;
1715 int netnsid = -1;
1689 int err; 1716 int err;
1690 int hdrlen; 1717 int hdrlen;
1691 1718
@@ -1704,6 +1731,15 @@ static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
1704 1731
1705 if (nlmsg_parse(cb->nlh, hdrlen, tb, IFLA_MAX, 1732 if (nlmsg_parse(cb->nlh, hdrlen, tb, IFLA_MAX,
1706 ifla_policy, NULL) >= 0) { 1733 ifla_policy, NULL) >= 0) {
1734 if (tb[IFLA_IF_NETNSID]) {
1735 netnsid = nla_get_s32(tb[IFLA_IF_NETNSID]);
1736 tgt_net = get_target_net(skb, netnsid);
1737 if (IS_ERR(tgt_net)) {
1738 tgt_net = net;
1739 netnsid = -1;
1740 }
1741 }
1742
1707 if (tb[IFLA_EXT_MASK]) 1743 if (tb[IFLA_EXT_MASK])
1708 ext_filter_mask = nla_get_u32(tb[IFLA_EXT_MASK]); 1744 ext_filter_mask = nla_get_u32(tb[IFLA_EXT_MASK]);
1709 1745
@@ -1719,17 +1755,19 @@ static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
1719 1755
1720 for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) { 1756 for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) {
1721 idx = 0; 1757 idx = 0;
1722 head = &net->dev_index_head[h]; 1758 head = &tgt_net->dev_index_head[h];
1723 hlist_for_each_entry(dev, head, index_hlist) { 1759 hlist_for_each_entry(dev, head, index_hlist) {
1724 if (link_dump_filtered(dev, master_idx, kind_ops)) 1760 if (link_dump_filtered(dev, master_idx, kind_ops))
1725 goto cont; 1761 goto cont;
1726 if (idx < s_idx) 1762 if (idx < s_idx)
1727 goto cont; 1763 goto cont;
1728 err = rtnl_fill_ifinfo(skb, dev, RTM_NEWLINK, 1764 err = rtnl_fill_ifinfo(skb, dev, net,
1765 RTM_NEWLINK,
1729 NETLINK_CB(cb->skb).portid, 1766 NETLINK_CB(cb->skb).portid,
1730 cb->nlh->nlmsg_seq, 0, 1767 cb->nlh->nlmsg_seq, 0,
1731 flags, 1768 flags,
1732 ext_filter_mask, 0, NULL); 1769 ext_filter_mask, 0, NULL,
1770 netnsid);
1733 1771
1734 if (err < 0) { 1772 if (err < 0) {
1735 if (likely(skb->len)) 1773 if (likely(skb->len))
@@ -1748,6 +1786,8 @@ out_err:
1748 cb->args[0] = h; 1786 cb->args[0] = h;
1749 cb->seq = net->dev_base_seq; 1787 cb->seq = net->dev_base_seq;
1750 nl_dump_check_consistent(cb, nlmsg_hdr(skb)); 1788 nl_dump_check_consistent(cb, nlmsg_hdr(skb));
1789 if (netnsid >= 0)
1790 put_net(tgt_net);
1751 1791
1752 return err; 1792 return err;
1753} 1793}
@@ -2360,6 +2400,9 @@ static int rtnl_setlink(struct sk_buff *skb, struct nlmsghdr *nlh,
2360 if (err < 0) 2400 if (err < 0)
2361 goto errout; 2401 goto errout;
2362 2402
2403 if (tb[IFLA_IF_NETNSID])
2404 return -EOPNOTSUPP;
2405
2363 if (tb[IFLA_IFNAME]) 2406 if (tb[IFLA_IFNAME])
2364 nla_strlcpy(ifname, tb[IFLA_IFNAME], IFNAMSIZ); 2407 nla_strlcpy(ifname, tb[IFLA_IFNAME], IFNAMSIZ);
2365 else 2408 else
@@ -2454,6 +2497,9 @@ static int rtnl_dellink(struct sk_buff *skb, struct nlmsghdr *nlh,
2454 if (err < 0) 2497 if (err < 0)
2455 return err; 2498 return err;
2456 2499
2500 if (tb[IFLA_IF_NETNSID])
2501 return -EOPNOTSUPP;
2502
2457 if (tb[IFLA_IFNAME]) 2503 if (tb[IFLA_IFNAME])
2458 nla_strlcpy(ifname, tb[IFLA_IFNAME], IFNAMSIZ); 2504 nla_strlcpy(ifname, tb[IFLA_IFNAME], IFNAMSIZ);
2459 2505
@@ -2585,6 +2631,9 @@ replay:
2585 if (err < 0) 2631 if (err < 0)
2586 return err; 2632 return err;
2587 2633
2634 if (tb[IFLA_IF_NETNSID])
2635 return -EOPNOTSUPP;
2636
2588 if (tb[IFLA_IFNAME]) 2637 if (tb[IFLA_IFNAME])
2589 nla_strlcpy(ifname, tb[IFLA_IFNAME], IFNAMSIZ); 2638 nla_strlcpy(ifname, tb[IFLA_IFNAME], IFNAMSIZ);
2590 else 2639 else
@@ -2818,11 +2867,13 @@ static int rtnl_getlink(struct sk_buff *skb, struct nlmsghdr *nlh,
2818 struct netlink_ext_ack *extack) 2867 struct netlink_ext_ack *extack)
2819{ 2868{
2820 struct net *net = sock_net(skb->sk); 2869 struct net *net = sock_net(skb->sk);
2870 struct net *tgt_net = net;
2821 struct ifinfomsg *ifm; 2871 struct ifinfomsg *ifm;
2822 char ifname[IFNAMSIZ]; 2872 char ifname[IFNAMSIZ];
2823 struct nlattr *tb[IFLA_MAX+1]; 2873 struct nlattr *tb[IFLA_MAX+1];
2824 struct net_device *dev = NULL; 2874 struct net_device *dev = NULL;
2825 struct sk_buff *nskb; 2875 struct sk_buff *nskb;
2876 int netnsid = -1;
2826 int err; 2877 int err;
2827 u32 ext_filter_mask = 0; 2878 u32 ext_filter_mask = 0;
2828 2879
@@ -2830,35 +2881,50 @@ static int rtnl_getlink(struct sk_buff *skb, struct nlmsghdr *nlh,
2830 if (err < 0) 2881 if (err < 0)
2831 return err; 2882 return err;
2832 2883
2884 if (tb[IFLA_IF_NETNSID]) {
2885 netnsid = nla_get_s32(tb[IFLA_IF_NETNSID]);
2886 tgt_net = get_target_net(skb, netnsid);
2887 if (IS_ERR(tgt_net))
2888 return PTR_ERR(tgt_net);
2889 }
2890
2833 if (tb[IFLA_IFNAME]) 2891 if (tb[IFLA_IFNAME])
2834 nla_strlcpy(ifname, tb[IFLA_IFNAME], IFNAMSIZ); 2892 nla_strlcpy(ifname, tb[IFLA_IFNAME], IFNAMSIZ);
2835 2893
2836 if (tb[IFLA_EXT_MASK]) 2894 if (tb[IFLA_EXT_MASK])
2837 ext_filter_mask = nla_get_u32(tb[IFLA_EXT_MASK]); 2895 ext_filter_mask = nla_get_u32(tb[IFLA_EXT_MASK]);
2838 2896
2897 err = -EINVAL;
2839 ifm = nlmsg_data(nlh); 2898 ifm = nlmsg_data(nlh);
2840 if (ifm->ifi_index > 0) 2899 if (ifm->ifi_index > 0)
2841 dev = __dev_get_by_index(net, ifm->ifi_index); 2900 dev = __dev_get_by_index(tgt_net, ifm->ifi_index);
2842 else if (tb[IFLA_IFNAME]) 2901 else if (tb[IFLA_IFNAME])
2843 dev = __dev_get_by_name(net, ifname); 2902 dev = __dev_get_by_name(tgt_net, ifname);
2844 else 2903 else
2845 return -EINVAL; 2904 goto out;
2846 2905
2906 err = -ENODEV;
2847 if (dev == NULL) 2907 if (dev == NULL)
2848 return -ENODEV; 2908 goto out;
2849 2909
2910 err = -ENOBUFS;
2850 nskb = nlmsg_new(if_nlmsg_size(dev, ext_filter_mask), GFP_KERNEL); 2911 nskb = nlmsg_new(if_nlmsg_size(dev, ext_filter_mask), GFP_KERNEL);
2851 if (nskb == NULL) 2912 if (nskb == NULL)
2852 return -ENOBUFS; 2913 goto out;
2853 2914
2854 err = rtnl_fill_ifinfo(nskb, dev, RTM_NEWLINK, NETLINK_CB(skb).portid, 2915 err = rtnl_fill_ifinfo(nskb, dev, net,
2855 nlh->nlmsg_seq, 0, 0, ext_filter_mask, 0, NULL); 2916 RTM_NEWLINK, NETLINK_CB(skb).portid,
2917 nlh->nlmsg_seq, 0, 0, ext_filter_mask,
2918 0, NULL, netnsid);
2856 if (err < 0) { 2919 if (err < 0) {
2857 /* -EMSGSIZE implies BUG in if_nlmsg_size */ 2920 /* -EMSGSIZE implies BUG in if_nlmsg_size */
2858 WARN_ON(err == -EMSGSIZE); 2921 WARN_ON(err == -EMSGSIZE);
2859 kfree_skb(nskb); 2922 kfree_skb(nskb);
2860 } else 2923 } else
2861 err = rtnl_unicast(nskb, net, NETLINK_CB(skb).portid); 2924 err = rtnl_unicast(nskb, net, NETLINK_CB(skb).portid);
2925out:
2926 if (netnsid >= 0)
2927 put_net(tgt_net);
2862 2928
2863 return err; 2929 return err;
2864} 2930}
@@ -2948,8 +3014,9 @@ struct sk_buff *rtmsg_ifinfo_build_skb(int type, struct net_device *dev,
2948 if (skb == NULL) 3014 if (skb == NULL)
2949 goto errout; 3015 goto errout;
2950 3016
2951 err = rtnl_fill_ifinfo(skb, dev, type, 0, 0, change, 0, 0, event, 3017 err = rtnl_fill_ifinfo(skb, dev, dev_net(dev),
2952 new_nsid); 3018 type, 0, 0, change, 0, 0, event,
3019 new_nsid, -1);
2953 if (err < 0) { 3020 if (err < 0) {
2954 /* -EMSGSIZE implies BUG in if_nlmsg_size() */ 3021 /* -EMSGSIZE implies BUG in if_nlmsg_size() */
2955 WARN_ON(err == -EMSGSIZE); 3022 WARN_ON(err == -EMSGSIZE);