diff options
author | Thomas Graf <tgraf@suug.ch> | 2006-08-17 21:15:44 -0400 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2006-09-22 17:55:06 -0400 |
commit | d889ce3b29e55b91257964b4c9aac70b91fedd91 (patch) | |
tree | 6d9250959b3cf33ceae6fcd90f34a12315bddb1c | |
parent | be403ea1856f1428b5912b42184acbba808c41d6 (diff) |
[IPv4]: Convert route get to new netlink api
Fixes various unvalidated netlink attributes causing memory
corruptions when left empty by userspace applications.
Signed-off-by: Thomas Graf <tgraf@suug.ch>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | include/net/ip_fib.h | 1 | ||||
-rw-r--r-- | net/ipv4/fib_frontend.c | 2 | ||||
-rw-r--r-- | net/ipv4/route.c | 84 |
3 files changed, 47 insertions, 40 deletions
diff --git a/include/net/ip_fib.h b/include/net/ip_fib.h index 42ed96fab3f5..fcc159a4ac17 100644 --- a/include/net/ip_fib.h +++ b/include/net/ip_fib.h | |||
@@ -216,6 +216,7 @@ extern void fib_select_default(const struct flowi *flp, struct fib_result *res); | |||
216 | #endif /* CONFIG_IP_MULTIPLE_TABLES */ | 216 | #endif /* CONFIG_IP_MULTIPLE_TABLES */ |
217 | 217 | ||
218 | /* Exported by fib_frontend.c */ | 218 | /* Exported by fib_frontend.c */ |
219 | extern struct nla_policy rtm_ipv4_policy[]; | ||
219 | extern void ip_fib_init(void); | 220 | extern void ip_fib_init(void); |
220 | extern int inet_rtm_delroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg); | 221 | extern int inet_rtm_delroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg); |
221 | extern int inet_rtm_newroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg); | 222 | extern int inet_rtm_newroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg); |
diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c index d537c933abe3..d0abeab16e66 100644 --- a/net/ipv4/fib_frontend.c +++ b/net/ipv4/fib_frontend.c | |||
@@ -453,7 +453,7 @@ int ip_rt_ioctl(unsigned int cmd, void *arg) | |||
453 | 453 | ||
454 | #endif | 454 | #endif |
455 | 455 | ||
456 | static struct nla_policy rtm_ipv4_policy[RTA_MAX+1] __read_mostly = { | 456 | struct nla_policy rtm_ipv4_policy[RTA_MAX+1] __read_mostly = { |
457 | [RTA_DST] = { .type = NLA_U32 }, | 457 | [RTA_DST] = { .type = NLA_U32 }, |
458 | [RTA_SRC] = { .type = NLA_U32 }, | 458 | [RTA_SRC] = { .type = NLA_U32 }, |
459 | [RTA_IIF] = { .type = NLA_U32 }, | 459 | [RTA_IIF] = { .type = NLA_U32 }, |
diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 31b67059ac29..a4d4cb85a16c 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c | |||
@@ -2737,18 +2737,24 @@ nla_put_failure: | |||
2737 | 2737 | ||
2738 | int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void *arg) | 2738 | int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void *arg) |
2739 | { | 2739 | { |
2740 | struct rtattr **rta = arg; | 2740 | struct rtmsg *rtm; |
2741 | struct rtmsg *rtm = NLMSG_DATA(nlh); | 2741 | struct nlattr *tb[RTA_MAX+1]; |
2742 | struct rtable *rt = NULL; | 2742 | struct rtable *rt = NULL; |
2743 | u32 dst = 0; | 2743 | u32 dst, src, iif; |
2744 | u32 src = 0; | 2744 | int err; |
2745 | int iif = 0; | ||
2746 | int err = -ENOBUFS; | ||
2747 | struct sk_buff *skb; | 2745 | struct sk_buff *skb; |
2748 | 2746 | ||
2747 | err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_ipv4_policy); | ||
2748 | if (err < 0) | ||
2749 | goto errout; | ||
2750 | |||
2751 | rtm = nlmsg_data(nlh); | ||
2752 | |||
2749 | skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); | 2753 | skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); |
2750 | if (!skb) | 2754 | if (skb == NULL) { |
2751 | goto out; | 2755 | err = -ENOBUFS; |
2756 | goto errout; | ||
2757 | } | ||
2752 | 2758 | ||
2753 | /* Reserve room for dummy headers, this skb can pass | 2759 | /* Reserve room for dummy headers, this skb can pass |
2754 | through good chunk of routing engine. | 2760 | through good chunk of routing engine. |
@@ -2759,61 +2765,61 @@ int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void *arg) | |||
2759 | skb->nh.iph->protocol = IPPROTO_ICMP; | 2765 | skb->nh.iph->protocol = IPPROTO_ICMP; |
2760 | skb_reserve(skb, MAX_HEADER + sizeof(struct iphdr)); | 2766 | skb_reserve(skb, MAX_HEADER + sizeof(struct iphdr)); |
2761 | 2767 | ||
2762 | if (rta[RTA_SRC - 1]) | 2768 | src = tb[RTA_SRC] ? nla_get_u32(tb[RTA_SRC]) : 0; |
2763 | memcpy(&src, RTA_DATA(rta[RTA_SRC - 1]), 4); | 2769 | dst = tb[RTA_DST] ? nla_get_u32(tb[RTA_DST]) : 0; |
2764 | if (rta[RTA_DST - 1]) | 2770 | iif = tb[RTA_IIF] ? nla_get_u32(tb[RTA_IIF]) : 0; |
2765 | memcpy(&dst, RTA_DATA(rta[RTA_DST - 1]), 4); | ||
2766 | if (rta[RTA_IIF - 1]) | ||
2767 | memcpy(&iif, RTA_DATA(rta[RTA_IIF - 1]), sizeof(int)); | ||
2768 | 2771 | ||
2769 | if (iif) { | 2772 | if (iif) { |
2770 | struct net_device *dev = __dev_get_by_index(iif); | 2773 | struct net_device *dev; |
2771 | err = -ENODEV; | 2774 | |
2772 | if (!dev) | 2775 | dev = __dev_get_by_index(iif); |
2773 | goto out_free; | 2776 | if (dev == NULL) { |
2777 | err = -ENODEV; | ||
2778 | goto errout_free; | ||
2779 | } | ||
2780 | |||
2774 | skb->protocol = htons(ETH_P_IP); | 2781 | skb->protocol = htons(ETH_P_IP); |
2775 | skb->dev = dev; | 2782 | skb->dev = dev; |
2776 | local_bh_disable(); | 2783 | local_bh_disable(); |
2777 | err = ip_route_input(skb, dst, src, rtm->rtm_tos, dev); | 2784 | err = ip_route_input(skb, dst, src, rtm->rtm_tos, dev); |
2778 | local_bh_enable(); | 2785 | local_bh_enable(); |
2779 | rt = (struct rtable*)skb->dst; | 2786 | |
2780 | if (!err && rt->u.dst.error) | 2787 | rt = (struct rtable*) skb->dst; |
2788 | if (err == 0 && rt->u.dst.error) | ||
2781 | err = -rt->u.dst.error; | 2789 | err = -rt->u.dst.error; |
2782 | } else { | 2790 | } else { |
2783 | struct flowi fl = { .nl_u = { .ip4_u = { .daddr = dst, | 2791 | struct flowi fl = { |
2784 | .saddr = src, | 2792 | .nl_u = { |
2785 | .tos = rtm->rtm_tos } } }; | 2793 | .ip4_u = { |
2786 | int oif = 0; | 2794 | .daddr = dst, |
2787 | if (rta[RTA_OIF - 1]) | 2795 | .saddr = src, |
2788 | memcpy(&oif, RTA_DATA(rta[RTA_OIF - 1]), sizeof(int)); | 2796 | .tos = rtm->rtm_tos, |
2789 | fl.oif = oif; | 2797 | }, |
2798 | }, | ||
2799 | .oif = tb[RTA_OIF] ? nla_get_u32(tb[RTA_OIF]) : 0, | ||
2800 | }; | ||
2790 | err = ip_route_output_key(&rt, &fl); | 2801 | err = ip_route_output_key(&rt, &fl); |
2791 | } | 2802 | } |
2803 | |||
2792 | if (err) | 2804 | if (err) |
2793 | goto out_free; | 2805 | goto errout_free; |
2794 | 2806 | ||
2795 | skb->dst = &rt->u.dst; | 2807 | skb->dst = &rt->u.dst; |
2796 | if (rtm->rtm_flags & RTM_F_NOTIFY) | 2808 | if (rtm->rtm_flags & RTM_F_NOTIFY) |
2797 | rt->rt_flags |= RTCF_NOTIFY; | 2809 | rt->rt_flags |= RTCF_NOTIFY; |
2798 | 2810 | ||
2799 | NETLINK_CB(skb).dst_pid = NETLINK_CB(in_skb).pid; | ||
2800 | |||
2801 | err = rt_fill_info(skb, NETLINK_CB(in_skb).pid, nlh->nlmsg_seq, | 2811 | err = rt_fill_info(skb, NETLINK_CB(in_skb).pid, nlh->nlmsg_seq, |
2802 | RTM_NEWROUTE, 0, 0); | 2812 | RTM_NEWROUTE, 0, 0); |
2803 | if (!err) | 2813 | if (err <= 0) |
2804 | goto out_free; | 2814 | goto errout_free; |
2805 | if (err < 0) { | ||
2806 | err = -EMSGSIZE; | ||
2807 | goto out_free; | ||
2808 | } | ||
2809 | 2815 | ||
2810 | err = rtnl_unicast(skb, NETLINK_CB(in_skb).pid); | 2816 | err = rtnl_unicast(skb, NETLINK_CB(in_skb).pid); |
2811 | out: | 2817 | errout: |
2812 | return err; | 2818 | return err; |
2813 | 2819 | ||
2814 | out_free: | 2820 | errout_free: |
2815 | kfree_skb(skb); | 2821 | kfree_skb(skb); |
2816 | goto out; | 2822 | goto errout; |
2817 | } | 2823 | } |
2818 | 2824 | ||
2819 | int ip_rt_dump(struct sk_buff *skb, struct netlink_callback *cb) | 2825 | int ip_rt_dump(struct sk_buff *skb, struct netlink_callback *cb) |