Skip to content

Commit 6ecf4c3

Browse files
braunerdavem330
authored andcommitted
ipv6: enable IFA_TARGET_NETNSID for RTM_GETADDR
- Backwards Compatibility: If userspace wants to determine whether ipv6 RTM_GETADDR requests support the new IFA_TARGET_NETNSID property it should verify that the reply includes the IFA_TARGET_NETNSID property. If it does not userspace should assume that IFA_TARGET_NETNSID is not supported for ipv6 RTM_GETADDR requests on this kernel. - From what I gather from current userspace tools that make use of RTM_GETADDR requests some of them pass down struct ifinfomsg when they should actually pass down struct ifaddrmsg. To not break existing tools that pass down the wrong struct we will do the same as for RTM_GETLINK | NLM_F_DUMP requests and not error out when the nlmsg_parse() fails. - Security: Callers must have CAP_NET_ADMIN in the owning user namespace of the target network namespace. Signed-off-by: Christian Brauner <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent d380714 commit 6ecf4c3

File tree

1 file changed

+58
-15
lines changed

1 file changed

+58
-15
lines changed

net/ipv6/addrconf.c

Lines changed: 58 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4491,6 +4491,7 @@ static const struct nla_policy ifa_ipv6_policy[IFA_MAX+1] = {
44914491
[IFA_CACHEINFO] = { .len = sizeof(struct ifa_cacheinfo) },
44924492
[IFA_FLAGS] = { .len = sizeof(u32) },
44934493
[IFA_RT_PRIORITY] = { .len = sizeof(u32) },
4494+
[IFA_TARGET_NETNSID] = { .type = NLA_S32 },
44944495
};
44954496

44964497
static int
@@ -4794,7 +4795,8 @@ static inline int inet6_ifaddr_msgsize(void)
47944795
}
47954796

47964797
static int inet6_fill_ifaddr(struct sk_buff *skb, struct inet6_ifaddr *ifa,
4797-
u32 portid, u32 seq, int event, unsigned int flags)
4798+
u32 portid, u32 seq, int event, unsigned int flags,
4799+
int netnsid)
47984800
{
47994801
struct nlmsghdr *nlh;
48004802
u32 preferred, valid;
@@ -4806,6 +4808,9 @@ static int inet6_fill_ifaddr(struct sk_buff *skb, struct inet6_ifaddr *ifa,
48064808
put_ifaddrmsg(nlh, ifa->prefix_len, ifa->flags, rt_scope(ifa->scope),
48074809
ifa->idev->dev->ifindex);
48084810

4811+
if (netnsid >= 0 && nla_put_s32(skb, IFA_TARGET_NETNSID, netnsid))
4812+
goto error;
4813+
48094814
if (!((ifa->flags&IFA_F_PERMANENT) &&
48104815
(ifa->prefered_lft == INFINITY_LIFE_TIME))) {
48114816
preferred = ifa->prefered_lft;
@@ -4855,7 +4860,8 @@ static int inet6_fill_ifaddr(struct sk_buff *skb, struct inet6_ifaddr *ifa,
48554860
}
48564861

48574862
static int inet6_fill_ifmcaddr(struct sk_buff *skb, struct ifmcaddr6 *ifmca,
4858-
u32 portid, u32 seq, int event, u16 flags)
4863+
u32 portid, u32 seq, int event, u16 flags,
4864+
int netnsid)
48594865
{
48604866
struct nlmsghdr *nlh;
48614867
u8 scope = RT_SCOPE_UNIVERSE;
@@ -4868,6 +4874,9 @@ static int inet6_fill_ifmcaddr(struct sk_buff *skb, struct ifmcaddr6 *ifmca,
48684874
if (!nlh)
48694875
return -EMSGSIZE;
48704876

4877+
if (netnsid >= 0 && nla_put_s32(skb, IFA_TARGET_NETNSID, netnsid))
4878+
return -EMSGSIZE;
4879+
48714880
put_ifaddrmsg(nlh, 128, IFA_F_PERMANENT, scope, ifindex);
48724881
if (nla_put_in6_addr(skb, IFA_MULTICAST, &ifmca->mca_addr) < 0 ||
48734882
put_cacheinfo(skb, ifmca->mca_cstamp, ifmca->mca_tstamp,
@@ -4881,7 +4890,8 @@ static int inet6_fill_ifmcaddr(struct sk_buff *skb, struct ifmcaddr6 *ifmca,
48814890
}
48824891

48834892
static int inet6_fill_ifacaddr(struct sk_buff *skb, struct ifacaddr6 *ifaca,
4884-
u32 portid, u32 seq, int event, unsigned int flags)
4893+
u32 portid, u32 seq, int event,
4894+
unsigned int flags, int netnsid)
48854895
{
48864896
struct net_device *dev = fib6_info_nh_dev(ifaca->aca_rt);
48874897
int ifindex = dev ? dev->ifindex : 1;
@@ -4895,6 +4905,9 @@ static int inet6_fill_ifacaddr(struct sk_buff *skb, struct ifacaddr6 *ifaca,
48954905
if (!nlh)
48964906
return -EMSGSIZE;
48974907

4908+
if (netnsid >= 0 && nla_put_s32(skb, IFA_TARGET_NETNSID, netnsid))
4909+
return -EMSGSIZE;
4910+
48984911
put_ifaddrmsg(nlh, 128, IFA_F_PERMANENT, scope, ifindex);
48994912
if (nla_put_in6_addr(skb, IFA_ANYCAST, &ifaca->aca_addr) < 0 ||
49004913
put_cacheinfo(skb, ifaca->aca_cstamp, ifaca->aca_tstamp,
@@ -4916,7 +4929,7 @@ enum addr_type_t {
49164929
/* called with rcu_read_lock() */
49174930
static int in6_dump_addrs(struct inet6_dev *idev, struct sk_buff *skb,
49184931
struct netlink_callback *cb, enum addr_type_t type,
4919-
int s_ip_idx, int *p_ip_idx)
4932+
int s_ip_idx, int *p_ip_idx, int netnsid)
49204933
{
49214934
struct ifmcaddr6 *ifmca;
49224935
struct ifacaddr6 *ifaca;
@@ -4936,7 +4949,7 @@ static int in6_dump_addrs(struct inet6_dev *idev, struct sk_buff *skb,
49364949
NETLINK_CB(cb->skb).portid,
49374950
cb->nlh->nlmsg_seq,
49384951
RTM_NEWADDR,
4939-
NLM_F_MULTI);
4952+
NLM_F_MULTI, netnsid);
49404953
if (err < 0)
49414954
break;
49424955
nl_dump_check_consistent(cb, nlmsg_hdr(skb));
@@ -4953,7 +4966,7 @@ static int in6_dump_addrs(struct inet6_dev *idev, struct sk_buff *skb,
49534966
NETLINK_CB(cb->skb).portid,
49544967
cb->nlh->nlmsg_seq,
49554968
RTM_GETMULTICAST,
4956-
NLM_F_MULTI);
4969+
NLM_F_MULTI, netnsid);
49574970
if (err < 0)
49584971
break;
49594972
}
@@ -4968,7 +4981,7 @@ static int in6_dump_addrs(struct inet6_dev *idev, struct sk_buff *skb,
49684981
NETLINK_CB(cb->skb).portid,
49694982
cb->nlh->nlmsg_seq,
49704983
RTM_GETANYCAST,
4971-
NLM_F_MULTI);
4984+
NLM_F_MULTI, netnsid);
49724985
if (err < 0)
49734986
break;
49744987
}
@@ -4985,6 +4998,9 @@ static int inet6_dump_addr(struct sk_buff *skb, struct netlink_callback *cb,
49854998
enum addr_type_t type)
49864999
{
49875000
struct net *net = sock_net(skb->sk);
5001+
struct nlattr *tb[IFA_MAX+1];
5002+
struct net *tgt_net = net;
5003+
int netnsid = -1;
49885004
int h, s_h;
49895005
int idx, ip_idx;
49905006
int s_idx, s_ip_idx;
@@ -4996,11 +5012,22 @@ static int inet6_dump_addr(struct sk_buff *skb, struct netlink_callback *cb,
49965012
s_idx = idx = cb->args[1];
49975013
s_ip_idx = ip_idx = cb->args[2];
49985014

5015+
if (nlmsg_parse(cb->nlh, sizeof(struct ifaddrmsg), tb, IFA_MAX,
5016+
ifa_ipv6_policy, NULL) >= 0) {
5017+
if (tb[IFA_TARGET_NETNSID]) {
5018+
netnsid = nla_get_s32(tb[IFA_TARGET_NETNSID]);
5019+
5020+
tgt_net = rtnl_get_net_ns_capable(skb->sk, netnsid);
5021+
if (IS_ERR(tgt_net))
5022+
return PTR_ERR(tgt_net);
5023+
}
5024+
}
5025+
49995026
rcu_read_lock();
5000-
cb->seq = atomic_read(&net->ipv6.dev_addr_genid) ^ net->dev_base_seq;
5027+
cb->seq = atomic_read(&tgt_net->ipv6.dev_addr_genid) ^ tgt_net->dev_base_seq;
50015028
for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) {
50025029
idx = 0;
5003-
head = &net->dev_index_head[h];
5030+
head = &tgt_net->dev_index_head[h];
50045031
hlist_for_each_entry_rcu(dev, head, index_hlist) {
50055032
if (idx < s_idx)
50065033
goto cont;
@@ -5012,7 +5039,7 @@ static int inet6_dump_addr(struct sk_buff *skb, struct netlink_callback *cb,
50125039
goto cont;
50135040

50145041
if (in6_dump_addrs(idev, skb, cb, type,
5015-
s_ip_idx, &ip_idx) < 0)
5042+
s_ip_idx, &ip_idx, netnsid) < 0)
50165043
goto done;
50175044
cont:
50185045
idx++;
@@ -5023,6 +5050,8 @@ static int inet6_dump_addr(struct sk_buff *skb, struct netlink_callback *cb,
50235050
cb->args[0] = h;
50245051
cb->args[1] = idx;
50255052
cb->args[2] = ip_idx;
5053+
if (netnsid >= 0)
5054+
put_net(tgt_net);
50265055

50275056
return skb->len;
50285057
}
@@ -5053,28 +5082,39 @@ static int inet6_rtm_getaddr(struct sk_buff *in_skb, struct nlmsghdr *nlh,
50535082
struct netlink_ext_ack *extack)
50545083
{
50555084
struct net *net = sock_net(in_skb->sk);
5085+
struct net *tgt_net = net;
50565086
struct ifaddrmsg *ifm;
50575087
struct nlattr *tb[IFA_MAX+1];
50585088
struct in6_addr *addr = NULL, *peer;
50595089
struct net_device *dev = NULL;
50605090
struct inet6_ifaddr *ifa;
50615091
struct sk_buff *skb;
5092+
int netnsid = -1;
50625093
int err;
50635094

50645095
err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv6_policy,
50655096
extack);
50665097
if (err < 0)
50675098
return err;
50685099

5100+
if (tb[IFA_TARGET_NETNSID]) {
5101+
netnsid = nla_get_s32(tb[IFA_TARGET_NETNSID]);
5102+
5103+
tgt_net = rtnl_get_net_ns_capable(NETLINK_CB(in_skb).sk,
5104+
netnsid);
5105+
if (IS_ERR(tgt_net))
5106+
return PTR_ERR(tgt_net);
5107+
}
5108+
50695109
addr = extract_addr(tb[IFA_ADDRESS], tb[IFA_LOCAL], &peer);
50705110
if (!addr)
50715111
return -EINVAL;
50725112

50735113
ifm = nlmsg_data(nlh);
50745114
if (ifm->ifa_index)
5075-
dev = dev_get_by_index(net, ifm->ifa_index);
5115+
dev = dev_get_by_index(tgt_net, ifm->ifa_index);
50765116

5077-
ifa = ipv6_get_ifaddr(net, addr, dev, 1);
5117+
ifa = ipv6_get_ifaddr(tgt_net, addr, dev, 1);
50785118
if (!ifa) {
50795119
err = -EADDRNOTAVAIL;
50805120
goto errout;
@@ -5087,19 +5127,22 @@ static int inet6_rtm_getaddr(struct sk_buff *in_skb, struct nlmsghdr *nlh,
50875127
}
50885128

50895129
err = inet6_fill_ifaddr(skb, ifa, NETLINK_CB(in_skb).portid,
5090-
nlh->nlmsg_seq, RTM_NEWADDR, 0);
5130+
nlh->nlmsg_seq, RTM_NEWADDR, 0, netnsid);
50915131
if (err < 0) {
50925132
/* -EMSGSIZE implies BUG in inet6_ifaddr_msgsize() */
50935133
WARN_ON(err == -EMSGSIZE);
50945134
kfree_skb(skb);
50955135
goto errout_ifa;
50965136
}
5097-
err = rtnl_unicast(skb, net, NETLINK_CB(in_skb).portid);
5137+
err = rtnl_unicast(skb, tgt_net, NETLINK_CB(in_skb).portid);
50985138
errout_ifa:
50995139
in6_ifa_put(ifa);
51005140
errout:
51015141
if (dev)
51025142
dev_put(dev);
5143+
if (netnsid >= 0)
5144+
put_net(tgt_net);
5145+
51035146
return err;
51045147
}
51055148

@@ -5113,7 +5156,7 @@ static void inet6_ifa_notify(int event, struct inet6_ifaddr *ifa)
51135156
if (!skb)
51145157
goto errout;
51155158

5116-
err = inet6_fill_ifaddr(skb, ifa, 0, 0, event, 0);
5159+
err = inet6_fill_ifaddr(skb, ifa, 0, 0, event, 0, -1);
51175160
if (err < 0) {
51185161
/* -EMSGSIZE implies BUG in inet6_ifaddr_msgsize() */
51195162
WARN_ON(err == -EMSGSIZE);

0 commit comments

Comments
 (0)