Merge branch 'route-dump-filter-fixes'
David Ahern says: ==================== net: Fixups for recent dump filtering changes Li RongQing noted that tgt_net is leaked in ipv4 due to the recent change to handle address dumps for a specific device. The report also applies to ipv6 and other error paths. Patches 1 and 2 fix those leaks. Patch 3 stops route dumps from erroring out when dumping across address families and a table id is given. This is needed in preparation for patch 4. Patch 4 updates the rtnl_dump_all to handle a failure in one of the dumpit functions. At the moment, if an address dump returns an error the dump all loop breaks but the error is dropped. The result can be no data is returned and no error either leaving the user wondering about the addresses. Patches were tested with a modified iproute2 to add invalid data to the dump request causing each specific failure path to be hit in addition to positive testing that it works as it should when given valid data. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
559bf69e3c
|
@ -226,6 +226,7 @@ struct fib_dump_filter {
|
||||||
u32 table_id;
|
u32 table_id;
|
||||||
/* filter_set is an optimization that an entry is set */
|
/* filter_set is an optimization that an entry is set */
|
||||||
bool filter_set;
|
bool filter_set;
|
||||||
|
bool dump_all_families;
|
||||||
unsigned char protocol;
|
unsigned char protocol;
|
||||||
unsigned char rt_type;
|
unsigned char rt_type;
|
||||||
unsigned int flags;
|
unsigned int flags;
|
||||||
|
|
|
@ -3333,6 +3333,7 @@ static int rtnl_dump_all(struct sk_buff *skb, struct netlink_callback *cb)
|
||||||
int idx;
|
int idx;
|
||||||
int s_idx = cb->family;
|
int s_idx = cb->family;
|
||||||
int type = cb->nlh->nlmsg_type - RTM_BASE;
|
int type = cb->nlh->nlmsg_type - RTM_BASE;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
if (s_idx == 0)
|
if (s_idx == 0)
|
||||||
s_idx = 1;
|
s_idx = 1;
|
||||||
|
@ -3365,12 +3366,13 @@ static int rtnl_dump_all(struct sk_buff *skb, struct netlink_callback *cb)
|
||||||
cb->prev_seq = 0;
|
cb->prev_seq = 0;
|
||||||
cb->seq = 0;
|
cb->seq = 0;
|
||||||
}
|
}
|
||||||
if (dumpit(skb, cb))
|
ret = dumpit(skb, cb);
|
||||||
|
if (ret < 0)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
cb->family = idx;
|
cb->family = idx;
|
||||||
|
|
||||||
return skb->len;
|
return skb->len ? : ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct sk_buff *rtmsg_ifinfo_build_skb(int type, struct net_device *dev,
|
struct sk_buff *rtmsg_ifinfo_build_skb(int type, struct net_device *dev,
|
||||||
|
|
|
@ -1761,7 +1761,7 @@ static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb)
|
||||||
struct net_device *dev;
|
struct net_device *dev;
|
||||||
struct in_device *in_dev;
|
struct in_device *in_dev;
|
||||||
struct hlist_head *head;
|
struct hlist_head *head;
|
||||||
int err;
|
int err = 0;
|
||||||
|
|
||||||
s_h = cb->args[0];
|
s_h = cb->args[0];
|
||||||
s_idx = idx = cb->args[1];
|
s_idx = idx = cb->args[1];
|
||||||
|
@ -1771,12 +1771,15 @@ static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb)
|
||||||
err = inet_valid_dump_ifaddr_req(nlh, &fillargs, &tgt_net,
|
err = inet_valid_dump_ifaddr_req(nlh, &fillargs, &tgt_net,
|
||||||
skb->sk, cb);
|
skb->sk, cb);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
goto put_tgt_net;
|
||||||
|
|
||||||
|
err = 0;
|
||||||
if (fillargs.ifindex) {
|
if (fillargs.ifindex) {
|
||||||
dev = __dev_get_by_index(tgt_net, fillargs.ifindex);
|
dev = __dev_get_by_index(tgt_net, fillargs.ifindex);
|
||||||
if (!dev)
|
if (!dev) {
|
||||||
return -ENODEV;
|
err = -ENODEV;
|
||||||
|
goto put_tgt_net;
|
||||||
|
}
|
||||||
|
|
||||||
in_dev = __in_dev_get_rtnl(dev);
|
in_dev = __in_dev_get_rtnl(dev);
|
||||||
if (in_dev) {
|
if (in_dev) {
|
||||||
|
@ -1821,7 +1824,7 @@ put_tgt_net:
|
||||||
if (fillargs.netnsid >= 0)
|
if (fillargs.netnsid >= 0)
|
||||||
put_net(tgt_net);
|
put_net(tgt_net);
|
||||||
|
|
||||||
return skb->len;
|
return err < 0 ? err : skb->len;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rtmsg_ifa(int event, struct in_ifaddr *ifa, struct nlmsghdr *nlh,
|
static void rtmsg_ifa(int event, struct in_ifaddr *ifa, struct nlmsghdr *nlh,
|
||||||
|
|
|
@ -829,6 +829,7 @@ int ip_valid_fib_dump_req(struct net *net, const struct nlmsghdr *nlh,
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
filter->dump_all_families = (rtm->rtm_family == AF_UNSPEC);
|
||||||
filter->flags = rtm->rtm_flags;
|
filter->flags = rtm->rtm_flags;
|
||||||
filter->protocol = rtm->rtm_protocol;
|
filter->protocol = rtm->rtm_protocol;
|
||||||
filter->rt_type = rtm->rtm_type;
|
filter->rt_type = rtm->rtm_type;
|
||||||
|
@ -899,6 +900,9 @@ static int inet_dump_fib(struct sk_buff *skb, struct netlink_callback *cb)
|
||||||
if (filter.table_id) {
|
if (filter.table_id) {
|
||||||
tb = fib_get_table(net, filter.table_id);
|
tb = fib_get_table(net, filter.table_id);
|
||||||
if (!tb) {
|
if (!tb) {
|
||||||
|
if (filter.dump_all_families)
|
||||||
|
return skb->len;
|
||||||
|
|
||||||
NL_SET_ERR_MSG(cb->extack, "ipv4: FIB table does not exist");
|
NL_SET_ERR_MSG(cb->extack, "ipv4: FIB table does not exist");
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2542,6 +2542,9 @@ static int ipmr_rtm_dumproute(struct sk_buff *skb, struct netlink_callback *cb)
|
||||||
|
|
||||||
mrt = ipmr_get_table(sock_net(skb->sk), filter.table_id);
|
mrt = ipmr_get_table(sock_net(skb->sk), filter.table_id);
|
||||||
if (!mrt) {
|
if (!mrt) {
|
||||||
|
if (filter.dump_all_families)
|
||||||
|
return skb->len;
|
||||||
|
|
||||||
NL_SET_ERR_MSG(cb->extack, "ipv4: MR table does not exist");
|
NL_SET_ERR_MSG(cb->extack, "ipv4: MR table does not exist");
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
}
|
}
|
||||||
|
|
|
@ -5089,23 +5089,25 @@ static int inet6_dump_addr(struct sk_buff *skb, struct netlink_callback *cb,
|
||||||
struct net_device *dev;
|
struct net_device *dev;
|
||||||
struct inet6_dev *idev;
|
struct inet6_dev *idev;
|
||||||
struct hlist_head *head;
|
struct hlist_head *head;
|
||||||
|
int err = 0;
|
||||||
|
|
||||||
s_h = cb->args[0];
|
s_h = cb->args[0];
|
||||||
s_idx = idx = cb->args[1];
|
s_idx = idx = cb->args[1];
|
||||||
s_ip_idx = cb->args[2];
|
s_ip_idx = cb->args[2];
|
||||||
|
|
||||||
if (cb->strict_check) {
|
if (cb->strict_check) {
|
||||||
int err;
|
|
||||||
|
|
||||||
err = inet6_valid_dump_ifaddr_req(nlh, &fillargs, &tgt_net,
|
err = inet6_valid_dump_ifaddr_req(nlh, &fillargs, &tgt_net,
|
||||||
skb->sk, cb);
|
skb->sk, cb);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
goto put_tgt_net;
|
||||||
|
|
||||||
|
err = 0;
|
||||||
if (fillargs.ifindex) {
|
if (fillargs.ifindex) {
|
||||||
dev = __dev_get_by_index(tgt_net, fillargs.ifindex);
|
dev = __dev_get_by_index(tgt_net, fillargs.ifindex);
|
||||||
if (!dev)
|
if (!dev) {
|
||||||
return -ENODEV;
|
err = -ENODEV;
|
||||||
|
goto put_tgt_net;
|
||||||
|
}
|
||||||
idev = __in6_dev_get(dev);
|
idev = __in6_dev_get(dev);
|
||||||
if (idev) {
|
if (idev) {
|
||||||
err = in6_dump_addrs(idev, skb, cb, s_ip_idx,
|
err = in6_dump_addrs(idev, skb, cb, s_ip_idx,
|
||||||
|
@ -5144,7 +5146,7 @@ put_tgt_net:
|
||||||
if (fillargs.netnsid >= 0)
|
if (fillargs.netnsid >= 0)
|
||||||
put_net(tgt_net);
|
put_net(tgt_net);
|
||||||
|
|
||||||
return skb->len;
|
return err < 0 ? err : skb->len;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int inet6_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb)
|
static int inet6_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb)
|
||||||
|
|
|
@ -620,6 +620,9 @@ static int inet6_dump_fib(struct sk_buff *skb, struct netlink_callback *cb)
|
||||||
if (arg.filter.table_id) {
|
if (arg.filter.table_id) {
|
||||||
tb = fib6_get_table(net, arg.filter.table_id);
|
tb = fib6_get_table(net, arg.filter.table_id);
|
||||||
if (!tb) {
|
if (!tb) {
|
||||||
|
if (arg.filter.dump_all_families)
|
||||||
|
return skb->len;
|
||||||
|
|
||||||
NL_SET_ERR_MSG_MOD(cb->extack, "FIB table does not exist");
|
NL_SET_ERR_MSG_MOD(cb->extack, "FIB table does not exist");
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2473,6 +2473,9 @@ static int ip6mr_rtm_dumproute(struct sk_buff *skb, struct netlink_callback *cb)
|
||||||
|
|
||||||
mrt = ip6mr_get_table(sock_net(skb->sk), filter.table_id);
|
mrt = ip6mr_get_table(sock_net(skb->sk), filter.table_id);
|
||||||
if (!mrt) {
|
if (!mrt) {
|
||||||
|
if (filter.dump_all_families)
|
||||||
|
return skb->len;
|
||||||
|
|
||||||
NL_SET_ERR_MSG_MOD(cb->extack, "MR table does not exist");
|
NL_SET_ERR_MSG_MOD(cb->extack, "MR table does not exist");
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue