rtnetlink: Update fib dumps for strict data checking
authorDavid Ahern <dsahern@gmail.com>
Mon, 8 Oct 2018 03:16:35 +0000 (20:16 -0700)
committerDavid S. Miller <davem@davemloft.net>
Mon, 8 Oct 2018 17:39:05 +0000 (10:39 -0700)
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: David Ahern <dsahern@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/net/ip_fib.h
net/ipv4/fib_frontend.c
net/ipv4/ipmr.c
net/ipv6/ip6_fib.c
net/ipv6/ip6mr.c
net/mpls/af_mpls.c

index f7c109e372987c06f379c673a2e99635e2da477b..9846b79c9ee194e9e4242f5fbc56728c49eccfd5 100644 (file)
@@ -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);
 
+int ip_valid_fib_dump_req(const struct nlmsghdr *nlh,
+                         struct netlink_ext_ack *extack);
 #endif  /* _NET_FIB_H */
index 30e2bcc3ef2a293568076228fecf3cf07ba01f20..038f511c73fa176ebe075ebfa8175aeac5dba285 100644 (file)
@@ -802,8 +802,40 @@ errout:
        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)
 {
+       const struct nlmsghdr *nlh = cb->nlh;
        struct net *net = sock_net(skb->sk);
        unsigned int h, s_h;
        unsigned int e = 0, s_e;
@@ -811,8 +843,14 @@ static int inet_dump_fib(struct sk_buff *skb, struct netlink_callback *cb)
        struct hlist_head *head;
        int dumped = 0, err;
 
-       if (nlmsg_len(cb->nlh) >= sizeof(struct rtmsg) &&
-           ((struct rtmsg *) nlmsg_data(cb->nlh))->rtm_flags & RTM_F_CLONED)
+       if (cb->strict_check) {
+               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;
 
        s_h = cb->args[0];
index e7322e407bb4f4f33d5d821f4c0e2024cea9e629..91b0d5671649c30b95fbb02a1b0a20636435a263 100644 (file)
@@ -2527,6 +2527,13 @@ errout_free:
 
 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,
                                _ipmr_fill_mroute, &mfc_unres_lock);
 }
index cf709eadc932b7eeb1450cb8c1ba3c65e0848954..e14d244c551f3670f412ebf180e3bd5dddc9eabe 100644 (file)
@@ -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)
 {
+       const struct nlmsghdr *nlh = cb->nlh;
        struct net *net = sock_net(skb->sk);
        unsigned int h, s_h;
        unsigned int e = 0, s_e;
@@ -573,6 +574,13 @@ static int inet6_dump_fib(struct sk_buff *skb, struct netlink_callback *cb)
        struct hlist_head *head;
        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_e = cb->args[1];
 
index 6f07b838042500832b718433c5091ca4cdc5cd0c..d7563ef76518482dfac68386b6946e9677f1708e 100644 (file)
@@ -2457,6 +2457,15 @@ errout:
 
 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,
                                _ip6mr_fill_mroute, &mfc_unres_lock);
 }
index 55a30ee3d82033e7c2360891de56735213cb53c5..0458c8aa5c11a7eb76dc955cd6ed02a5c1ca68df 100644 (file)
@@ -2017,6 +2017,7 @@ nla_put_failure:
 
 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 mpls_route __rcu **platform_label;
        size_t platform_labels;
@@ -2024,6 +2025,13 @@ static int mpls_dump_routes(struct sk_buff *skb, struct netlink_callback *cb)
 
        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];
        if (index < MPLS_LABEL_FIRST_UNRESERVED)
                index = MPLS_LABEL_FIRST_UNRESERVED;