Commit e8ba330a authored by David Ahern's avatar David Ahern Committed by David S. Miller

rtnetlink: Update fib dumps for strict data checking

Add helper to check netlink message for route dumps. If the strict flag
is set the dump request is expected to have an rtmsg struct as the header.
All elements of the struct are expected to be 0 with the exception of
rtm_flags (which is used by both ipv4 and ipv6 dumps) and no attributes
can be appended. rtm_flags can only have RTM_F_CLONED and RTM_F_PREFIX
set.

Update inet_dump_fib, inet6_dump_fib, mpls_dump_routes, ipmr_rtm_dumproute,
and ip6mr_rtm_dumproute to call this helper if strict data checking is
enabled.
Signed-off-by: default avatarDavid Ahern <dsahern@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 14fc5bb2
...@@ -452,4 +452,6 @@ static inline void fib_proc_exit(struct net *net) ...@@ -452,4 +452,6 @@ static inline void fib_proc_exit(struct net *net)
u32 ip_mtu_from_fib_result(struct fib_result *res, __be32 daddr); u32 ip_mtu_from_fib_result(struct fib_result *res, __be32 daddr);
int ip_valid_fib_dump_req(const struct nlmsghdr *nlh,
struct netlink_ext_ack *extack);
#endif /* _NET_FIB_H */ #endif /* _NET_FIB_H */
...@@ -802,8 +802,40 @@ static int inet_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh, ...@@ -802,8 +802,40 @@ static int inet_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh,
return err; return err;
} }
int ip_valid_fib_dump_req(const struct nlmsghdr *nlh,
struct netlink_ext_ack *extack)
{
struct rtmsg *rtm;
if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*rtm))) {
NL_SET_ERR_MSG(extack, "Invalid header for FIB dump request");
return -EINVAL;
}
rtm = nlmsg_data(nlh);
if (rtm->rtm_dst_len || rtm->rtm_src_len || rtm->rtm_tos ||
rtm->rtm_table || rtm->rtm_protocol || rtm->rtm_scope ||
rtm->rtm_type) {
NL_SET_ERR_MSG(extack, "Invalid values in header for FIB dump request");
return -EINVAL;
}
if (rtm->rtm_flags & ~(RTM_F_CLONED | RTM_F_PREFIX)) {
NL_SET_ERR_MSG(extack, "Invalid flags for FIB dump request");
return -EINVAL;
}
if (nlmsg_attrlen(nlh, sizeof(*rtm))) {
NL_SET_ERR_MSG(extack, "Invalid data after header in FIB dump request");
return -EINVAL;
}
return 0;
}
EXPORT_SYMBOL_GPL(ip_valid_fib_dump_req);
static int inet_dump_fib(struct sk_buff *skb, struct netlink_callback *cb) static int inet_dump_fib(struct sk_buff *skb, struct netlink_callback *cb)
{ {
const struct nlmsghdr *nlh = cb->nlh;
struct net *net = sock_net(skb->sk); struct net *net = sock_net(skb->sk);
unsigned int h, s_h; unsigned int h, s_h;
unsigned int e = 0, s_e; unsigned int e = 0, s_e;
...@@ -811,8 +843,14 @@ static int inet_dump_fib(struct sk_buff *skb, struct netlink_callback *cb) ...@@ -811,8 +843,14 @@ static int inet_dump_fib(struct sk_buff *skb, struct netlink_callback *cb)
struct hlist_head *head; struct hlist_head *head;
int dumped = 0, err; int dumped = 0, err;
if (nlmsg_len(cb->nlh) >= sizeof(struct rtmsg) && if (cb->strict_check) {
((struct rtmsg *) nlmsg_data(cb->nlh))->rtm_flags & RTM_F_CLONED) err = ip_valid_fib_dump_req(nlh, cb->extack);
if (err < 0)
return err;
}
if (nlmsg_len(nlh) >= sizeof(struct rtmsg) &&
((struct rtmsg *)nlmsg_data(nlh))->rtm_flags & RTM_F_CLONED)
return skb->len; return skb->len;
s_h = cb->args[0]; s_h = cb->args[0];
......
...@@ -2527,6 +2527,13 @@ static int ipmr_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh, ...@@ -2527,6 +2527,13 @@ static int ipmr_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh,
static int ipmr_rtm_dumproute(struct sk_buff *skb, struct netlink_callback *cb) static int ipmr_rtm_dumproute(struct sk_buff *skb, struct netlink_callback *cb)
{ {
if (cb->strict_check) {
int err = ip_valid_fib_dump_req(cb->nlh, cb->extack);
if (err < 0)
return err;
}
return mr_rtm_dumproute(skb, cb, ipmr_mr_table_iter, return mr_rtm_dumproute(skb, cb, ipmr_mr_table_iter,
_ipmr_fill_mroute, &mfc_unres_lock); _ipmr_fill_mroute, &mfc_unres_lock);
} }
......
...@@ -564,6 +564,7 @@ static int fib6_dump_table(struct fib6_table *table, struct sk_buff *skb, ...@@ -564,6 +564,7 @@ static int fib6_dump_table(struct fib6_table *table, struct sk_buff *skb,
static int inet6_dump_fib(struct sk_buff *skb, struct netlink_callback *cb) static int inet6_dump_fib(struct sk_buff *skb, struct netlink_callback *cb)
{ {
const struct nlmsghdr *nlh = cb->nlh;
struct net *net = sock_net(skb->sk); struct net *net = sock_net(skb->sk);
unsigned int h, s_h; unsigned int h, s_h;
unsigned int e = 0, s_e; unsigned int e = 0, s_e;
...@@ -573,6 +574,13 @@ static int inet6_dump_fib(struct sk_buff *skb, struct netlink_callback *cb) ...@@ -573,6 +574,13 @@ static int inet6_dump_fib(struct sk_buff *skb, struct netlink_callback *cb)
struct hlist_head *head; struct hlist_head *head;
int res = 0; int res = 0;
if (cb->strict_check) {
int err = ip_valid_fib_dump_req(nlh, cb->extack);
if (err < 0)
return err;
}
s_h = cb->args[0]; s_h = cb->args[0];
s_e = cb->args[1]; s_e = cb->args[1];
......
...@@ -2457,6 +2457,15 @@ static void mrt6msg_netlink_event(struct mr_table *mrt, struct sk_buff *pkt) ...@@ -2457,6 +2457,15 @@ static void mrt6msg_netlink_event(struct mr_table *mrt, struct sk_buff *pkt)
static int ip6mr_rtm_dumproute(struct sk_buff *skb, struct netlink_callback *cb) static int ip6mr_rtm_dumproute(struct sk_buff *skb, struct netlink_callback *cb)
{ {
const struct nlmsghdr *nlh = cb->nlh;
if (cb->strict_check) {
int err = ip_valid_fib_dump_req(nlh, cb->extack);
if (err < 0)
return err;
}
return mr_rtm_dumproute(skb, cb, ip6mr_mr_table_iter, return mr_rtm_dumproute(skb, cb, ip6mr_mr_table_iter,
_ip6mr_fill_mroute, &mfc_unres_lock); _ip6mr_fill_mroute, &mfc_unres_lock);
} }
...@@ -2017,6 +2017,7 @@ static int mpls_dump_route(struct sk_buff *skb, u32 portid, u32 seq, int event, ...@@ -2017,6 +2017,7 @@ static int mpls_dump_route(struct sk_buff *skb, u32 portid, u32 seq, int event,
static int mpls_dump_routes(struct sk_buff *skb, struct netlink_callback *cb) static int mpls_dump_routes(struct sk_buff *skb, struct netlink_callback *cb)
{ {
const struct nlmsghdr *nlh = cb->nlh;
struct net *net = sock_net(skb->sk); struct net *net = sock_net(skb->sk);
struct mpls_route __rcu **platform_label; struct mpls_route __rcu **platform_label;
size_t platform_labels; size_t platform_labels;
...@@ -2024,6 +2025,13 @@ static int mpls_dump_routes(struct sk_buff *skb, struct netlink_callback *cb) ...@@ -2024,6 +2025,13 @@ static int mpls_dump_routes(struct sk_buff *skb, struct netlink_callback *cb)
ASSERT_RTNL(); ASSERT_RTNL();
if (cb->strict_check) {
int err = ip_valid_fib_dump_req(nlh, cb->extack);
if (err < 0)
return err;
}
index = cb->args[0]; index = cb->args[0];
if (index < MPLS_LABEL_FIRST_UNRESERVED) if (index < MPLS_LABEL_FIRST_UNRESERVED)
index = MPLS_LABEL_FIRST_UNRESERVED; index = MPLS_LABEL_FIRST_UNRESERVED;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment