Skip to content

Commit d380714

Browse files
braunerdavem330
authored andcommitted
ipv4: enable IFA_TARGET_NETNSID for RTM_GETADDR
- Backwards Compatibility: If userspace wants to determine whether ipv4 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 ipv4 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 9f3c057 commit d380714

File tree

1 file changed

+30
-8
lines changed

1 file changed

+30
-8
lines changed

net/ipv4/devinet.c

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ static const struct nla_policy ifa_ipv4_policy[IFA_MAX+1] = {
100100
[IFA_CACHEINFO] = { .len = sizeof(struct ifa_cacheinfo) },
101101
[IFA_FLAGS] = { .type = NLA_U32 },
102102
[IFA_RT_PRIORITY] = { .type = NLA_U32 },
103+
[IFA_TARGET_NETNSID] = { .type = NLA_S32 },
103104
};
104105

105106
#define IN4_ADDR_HSIZE_SHIFT 8
@@ -1584,7 +1585,8 @@ static int put_cacheinfo(struct sk_buff *skb, unsigned long cstamp,
15841585
}
15851586

15861587
static int inet_fill_ifaddr(struct sk_buff *skb, struct in_ifaddr *ifa,
1587-
u32 portid, u32 seq, int event, unsigned int flags)
1588+
u32 portid, u32 seq, int event, unsigned int flags,
1589+
int netnsid)
15881590
{
15891591
struct ifaddrmsg *ifm;
15901592
struct nlmsghdr *nlh;
@@ -1601,6 +1603,9 @@ static int inet_fill_ifaddr(struct sk_buff *skb, struct in_ifaddr *ifa,
16011603
ifm->ifa_scope = ifa->ifa_scope;
16021604
ifm->ifa_index = ifa->ifa_dev->dev->ifindex;
16031605

1606+
if (netnsid >= 0 && nla_put_s32(skb, IFA_TARGET_NETNSID, netnsid))
1607+
goto nla_put_failure;
1608+
16041609
if (!(ifm->ifa_flags & IFA_F_PERMANENT)) {
16051610
preferred = ifa->ifa_preferred_lft;
16061611
valid = ifa->ifa_valid_lft;
@@ -1648,6 +1653,9 @@ static int inet_fill_ifaddr(struct sk_buff *skb, struct in_ifaddr *ifa,
16481653
static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb)
16491654
{
16501655
struct net *net = sock_net(skb->sk);
1656+
struct nlattr *tb[IFA_MAX+1];
1657+
struct net *tgt_net = net;
1658+
int netnsid = -1;
16511659
int h, s_h;
16521660
int idx, s_idx;
16531661
int ip_idx, s_ip_idx;
@@ -1660,12 +1668,23 @@ static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb)
16601668
s_idx = idx = cb->args[1];
16611669
s_ip_idx = ip_idx = cb->args[2];
16621670

1671+
if (nlmsg_parse(cb->nlh, sizeof(struct ifaddrmsg), tb, IFA_MAX,
1672+
ifa_ipv4_policy, NULL) >= 0) {
1673+
if (tb[IFA_TARGET_NETNSID]) {
1674+
netnsid = nla_get_s32(tb[IFA_TARGET_NETNSID]);
1675+
1676+
tgt_net = rtnl_get_net_ns_capable(skb->sk, netnsid);
1677+
if (IS_ERR(tgt_net))
1678+
return PTR_ERR(tgt_net);
1679+
}
1680+
}
1681+
16631682
for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) {
16641683
idx = 0;
1665-
head = &net->dev_index_head[h];
1684+
head = &tgt_net->dev_index_head[h];
16661685
rcu_read_lock();
1667-
cb->seq = atomic_read(&net->ipv4.dev_addr_genid) ^
1668-
net->dev_base_seq;
1686+
cb->seq = atomic_read(&tgt_net->ipv4.dev_addr_genid) ^
1687+
tgt_net->dev_base_seq;
16691688
hlist_for_each_entry_rcu(dev, head, index_hlist) {
16701689
if (idx < s_idx)
16711690
goto cont;
@@ -1680,9 +1699,10 @@ static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb)
16801699
if (ip_idx < s_ip_idx)
16811700
continue;
16821701
if (inet_fill_ifaddr(skb, ifa,
1683-
NETLINK_CB(cb->skb).portid,
1684-
cb->nlh->nlmsg_seq,
1685-
RTM_NEWADDR, NLM_F_MULTI) < 0) {
1702+
NETLINK_CB(cb->skb).portid,
1703+
cb->nlh->nlmsg_seq,
1704+
RTM_NEWADDR, NLM_F_MULTI,
1705+
netnsid) < 0) {
16861706
rcu_read_unlock();
16871707
goto done;
16881708
}
@@ -1698,6 +1718,8 @@ static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb)
16981718
cb->args[0] = h;
16991719
cb->args[1] = idx;
17001720
cb->args[2] = ip_idx;
1721+
if (netnsid >= 0)
1722+
put_net(tgt_net);
17011723

17021724
return skb->len;
17031725
}
@@ -1715,7 +1737,7 @@ static void rtmsg_ifa(int event, struct in_ifaddr *ifa, struct nlmsghdr *nlh,
17151737
if (!skb)
17161738
goto errout;
17171739

1718-
err = inet_fill_ifaddr(skb, ifa, portid, seq, event, 0);
1740+
err = inet_fill_ifaddr(skb, ifa, portid, seq, event, 0, -1);
17191741
if (err < 0) {
17201742
/* -EMSGSIZE implies BUG in inet_nlmsg_size() */
17211743
WARN_ON(err == -EMSGSIZE);

0 commit comments

Comments
 (0)