Skip to content

Commit 79e1ad1

Browse files
Jiri Bencdavem330
Jiri Benc
authored andcommitted
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 <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 9354d45 commit 79e1ad1

File tree

2 files changed

+86
-18
lines changed

2 files changed

+86
-18
lines changed

include/uapi/linux/if_link.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,7 @@ enum {
160160
IFLA_XDP,
161161
IFLA_EVENT,
162162
IFLA_NEW_NETNSID,
163+
IFLA_IF_NETNSID,
163164
__IFLA_MAX
164165
};
165166

net/core/rtnetlink.c

Lines changed: 85 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -921,7 +921,8 @@ static noinline size_t if_nlmsg_size(const struct net_device *dev,
921921
+ nla_total_size(4) /* IFLA_EVENT */
922922
+ nla_total_size(4) /* IFLA_NEW_NETNSID */
923923
+ nla_total_size(1); /* IFLA_PROTO_DOWN */
924-
924+
+ nla_total_size(4) /* IFLA_IF_NETNSID */
925+
+ 0;
925926
}
926927

927928
static 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,
13701371
}
13711372

13721373
static 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)
13741376
{
13751377
if (dev->rtnl_link_ops && dev->rtnl_link_ops->get_link_net) {
13761378
struct net *link_net = dev->rtnl_link_ops->get_link_net(dev);
13771379

13781380
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);
13801382

13811383
if (nla_put_s32(skb, IFLA_LINK_NETNSID, id))
13821384
return -EMSGSIZE;
@@ -1427,10 +1429,11 @@ static int rtnl_fill_link_af(struct sk_buff *skb,
14271429
return 0;
14281430
}
14291431

1430-
static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev,
1432+
static int rtnl_fill_ifinfo(struct sk_buff *skb,
1433+
struct net_device *dev, struct net *src_net,
14311434
int type, u32 pid, u32 seq, u32 change,
14321435
unsigned int flags, u32 ext_filter_mask,
1433-
u32 event, int *new_nsid)
1436+
u32 event, int *new_nsid, int tgt_netnsid)
14341437
{
14351438
struct ifinfomsg *ifm;
14361439
struct nlmsghdr *nlh;
@@ -1448,6 +1451,9 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev,
14481451
ifm->ifi_flags = dev_get_flags(dev);
14491452
ifm->ifi_change = change;
14501453

1454+
if (tgt_netnsid >= 0 && nla_put_s32(skb, IFLA_IF_NETNSID, tgt_netnsid))
1455+
goto nla_put_failure;
1456+
14511457
if (nla_put_string(skb, IFLA_IFNAME, dev->name) ||
14521458
nla_put_u32(skb, IFLA_TXQLEN, dev->tx_queue_len) ||
14531459
nla_put_u8(skb, IFLA_OPERSTATE,
@@ -1513,7 +1519,7 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev,
15131519
goto nla_put_failure;
15141520
}
15151521

1516-
if (rtnl_fill_link_netnsid(skb, dev))
1522+
if (rtnl_fill_link_netnsid(skb, dev, src_net))
15171523
goto nla_put_failure;
15181524

15191525
if (new_nsid &&
@@ -1571,6 +1577,7 @@ static const struct nla_policy ifla_policy[IFLA_MAX+1] = {
15711577
[IFLA_XDP] = { .type = NLA_NESTED },
15721578
[IFLA_EVENT] = { .type = NLA_U32 },
15731579
[IFLA_GROUP] = { .type = NLA_U32 },
1580+
[IFLA_IF_NETNSID] = { .type = NLA_S32 },
15741581
};
15751582

15761583
static const struct nla_policy ifla_info_policy[IFLA_INFO_MAX+1] = {
@@ -1674,9 +1681,28 @@ static bool link_dump_filtered(struct net_device *dev,
16741681
return false;
16751682
}
16761683

1684+
static 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+
16771702
static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
16781703
{
16791704
struct net *net = sock_net(skb->sk);
1705+
struct net *tgt_net = net;
16801706
int h, s_h;
16811707
int idx = 0, s_idx;
16821708
struct net_device *dev;
@@ -1686,6 +1712,7 @@ static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
16861712
const struct rtnl_link_ops *kind_ops = NULL;
16871713
unsigned int flags = NLM_F_MULTI;
16881714
int master_idx = 0;
1715+
int netnsid = -1;
16891716
int err;
16901717
int hdrlen;
16911718

@@ -1704,6 +1731,15 @@ static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
17041731

17051732
if (nlmsg_parse(cb->nlh, hdrlen, tb, IFLA_MAX,
17061733
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+
17071743
if (tb[IFLA_EXT_MASK])
17081744
ext_filter_mask = nla_get_u32(tb[IFLA_EXT_MASK]);
17091745

@@ -1719,17 +1755,19 @@ static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
17191755

17201756
for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) {
17211757
idx = 0;
1722-
head = &net->dev_index_head[h];
1758+
head = &tgt_net->dev_index_head[h];
17231759
hlist_for_each_entry(dev, head, index_hlist) {
17241760
if (link_dump_filtered(dev, master_idx, kind_ops))
17251761
goto cont;
17261762
if (idx < s_idx)
17271763
goto cont;
1728-
err = rtnl_fill_ifinfo(skb, dev, RTM_NEWLINK,
1764+
err = rtnl_fill_ifinfo(skb, dev, net,
1765+
RTM_NEWLINK,
17291766
NETLINK_CB(cb->skb).portid,
17301767
cb->nlh->nlmsg_seq, 0,
17311768
flags,
1732-
ext_filter_mask, 0, NULL);
1769+
ext_filter_mask, 0, NULL,
1770+
netnsid);
17331771

17341772
if (err < 0) {
17351773
if (likely(skb->len))
@@ -1748,6 +1786,8 @@ static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
17481786
cb->args[0] = h;
17491787
cb->seq = net->dev_base_seq;
17501788
nl_dump_check_consistent(cb, nlmsg_hdr(skb));
1789+
if (netnsid >= 0)
1790+
put_net(tgt_net);
17511791

17521792
return err;
17531793
}
@@ -2360,6 +2400,9 @@ static int rtnl_setlink(struct sk_buff *skb, struct nlmsghdr *nlh,
23602400
if (err < 0)
23612401
goto errout;
23622402

2403+
if (tb[IFLA_IF_NETNSID])
2404+
return -EOPNOTSUPP;
2405+
23632406
if (tb[IFLA_IFNAME])
23642407
nla_strlcpy(ifname, tb[IFLA_IFNAME], IFNAMSIZ);
23652408
else
@@ -2454,6 +2497,9 @@ static int rtnl_dellink(struct sk_buff *skb, struct nlmsghdr *nlh,
24542497
if (err < 0)
24552498
return err;
24562499

2500+
if (tb[IFLA_IF_NETNSID])
2501+
return -EOPNOTSUPP;
2502+
24572503
if (tb[IFLA_IFNAME])
24582504
nla_strlcpy(ifname, tb[IFLA_IFNAME], IFNAMSIZ);
24592505

@@ -2585,6 +2631,9 @@ static int rtnl_newlink(struct sk_buff *skb, struct nlmsghdr *nlh,
25852631
if (err < 0)
25862632
return err;
25872633

2634+
if (tb[IFLA_IF_NETNSID])
2635+
return -EOPNOTSUPP;
2636+
25882637
if (tb[IFLA_IFNAME])
25892638
nla_strlcpy(ifname, tb[IFLA_IFNAME], IFNAMSIZ);
25902639
else
@@ -2818,47 +2867,64 @@ static int rtnl_getlink(struct sk_buff *skb, struct nlmsghdr *nlh,
28182867
struct netlink_ext_ack *extack)
28192868
{
28202869
struct net *net = sock_net(skb->sk);
2870+
struct net *tgt_net = net;
28212871
struct ifinfomsg *ifm;
28222872
char ifname[IFNAMSIZ];
28232873
struct nlattr *tb[IFLA_MAX+1];
28242874
struct net_device *dev = NULL;
28252875
struct sk_buff *nskb;
2876+
int netnsid = -1;
28262877
int err;
28272878
u32 ext_filter_mask = 0;
28282879

28292880
err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFLA_MAX, ifla_policy, extack);
28302881
if (err < 0)
28312882
return err;
28322883

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+
28332891
if (tb[IFLA_IFNAME])
28342892
nla_strlcpy(ifname, tb[IFLA_IFNAME], IFNAMSIZ);
28352893

28362894
if (tb[IFLA_EXT_MASK])
28372895
ext_filter_mask = nla_get_u32(tb[IFLA_EXT_MASK]);
28382896

2897+
err = -EINVAL;
28392898
ifm = nlmsg_data(nlh);
28402899
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);
28422901
else if (tb[IFLA_IFNAME])
2843-
dev = __dev_get_by_name(net, ifname);
2902+
dev = __dev_get_by_name(tgt_net, ifname);
28442903
else
2845-
return -EINVAL;
2904+
goto out;
28462905

2906+
err = -ENODEV;
28472907
if (dev == NULL)
2848-
return -ENODEV;
2908+
goto out;
28492909

2910+
err = -ENOBUFS;
28502911
nskb = nlmsg_new(if_nlmsg_size(dev, ext_filter_mask), GFP_KERNEL);
28512912
if (nskb == NULL)
2852-
return -ENOBUFS;
2913+
goto out;
28532914

2854-
err = rtnl_fill_ifinfo(nskb, dev, RTM_NEWLINK, NETLINK_CB(skb).portid,
2855-
nlh->nlmsg_seq, 0, 0, ext_filter_mask, 0, NULL);
2915+
err = rtnl_fill_ifinfo(nskb, dev, net,
2916+
RTM_NEWLINK, NETLINK_CB(skb).portid,
2917+
nlh->nlmsg_seq, 0, 0, ext_filter_mask,
2918+
0, NULL, netnsid);
28562919
if (err < 0) {
28572920
/* -EMSGSIZE implies BUG in if_nlmsg_size */
28582921
WARN_ON(err == -EMSGSIZE);
28592922
kfree_skb(nskb);
28602923
} else
28612924
err = rtnl_unicast(nskb, net, NETLINK_CB(skb).portid);
2925+
out:
2926+
if (netnsid >= 0)
2927+
put_net(tgt_net);
28622928

28632929
return err;
28642930
}
@@ -2948,8 +3014,9 @@ struct sk_buff *rtmsg_ifinfo_build_skb(int type, struct net_device *dev,
29483014
if (skb == NULL)
29493015
goto errout;
29503016

2951-
err = rtnl_fill_ifinfo(skb, dev, type, 0, 0, change, 0, 0, event,
2952-
new_nsid);
3017+
err = rtnl_fill_ifinfo(skb, dev, dev_net(dev),
3018+
type, 0, 0, change, 0, 0, event,
3019+
new_nsid, -1);
29533020
if (err < 0) {
29543021
/* -EMSGSIZE implies BUG in if_nlmsg_size() */
29553022
WARN_ON(err == -EMSGSIZE);

0 commit comments

Comments
 (0)