diff options
author | Thomas Graf <tgraf@suug.ch> | 2006-08-22 03:01:47 -0400 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2006-09-22 17:55:14 -0400 |
commit | ab364a6f96bad9625bdb97b5688c76c44eb1e96e (patch) | |
tree | 6a85db5eb05c524401855c77c8e489272869c7b6 /net | |
parent | 2d7202bfdd28687073f5efef8d2f51bbab0af867 (diff) |
[IPv6] route: Convert GETROUTE to use 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>
Diffstat (limited to 'net')
-rw-r--r-- | net/ipv6/route.c | 80 |
1 files changed, 44 insertions, 36 deletions
diff --git a/net/ipv6/route.c b/net/ipv6/route.c index f0a66de84331..5d6e9083ca2c 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c | |||
@@ -1833,6 +1833,7 @@ void rt6_mtu_change(struct net_device *dev, unsigned mtu) | |||
1833 | static struct nla_policy rtm_ipv6_policy[RTA_MAX+1] __read_mostly = { | 1833 | static struct nla_policy rtm_ipv6_policy[RTA_MAX+1] __read_mostly = { |
1834 | [RTA_GATEWAY] = { .minlen = sizeof(struct in6_addr) }, | 1834 | [RTA_GATEWAY] = { .minlen = sizeof(struct in6_addr) }, |
1835 | [RTA_OIF] = { .type = NLA_U32 }, | 1835 | [RTA_OIF] = { .type = NLA_U32 }, |
1836 | [RTA_IIF] = { .type = NLA_U32 }, | ||
1836 | [RTA_PRIORITY] = { .type = NLA_U32 }, | 1837 | [RTA_PRIORITY] = { .type = NLA_U32 }, |
1837 | [RTA_METRICS] = { .type = NLA_NESTED }, | 1838 | [RTA_METRICS] = { .type = NLA_NESTED }, |
1838 | }; | 1839 | }; |
@@ -2048,68 +2049,75 @@ int rt6_dump_route(struct rt6_info *rt, void *p_arg) | |||
2048 | 2049 | ||
2049 | int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void *arg) | 2050 | int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void *arg) |
2050 | { | 2051 | { |
2051 | struct rtattr **rta = arg; | 2052 | struct nlattr *tb[RTA_MAX+1]; |
2052 | int iif = 0; | 2053 | struct rt6_info *rt; |
2053 | int err = -ENOBUFS; | ||
2054 | struct sk_buff *skb; | 2054 | struct sk_buff *skb; |
2055 | struct rtmsg *rtm; | ||
2055 | struct flowi fl; | 2056 | struct flowi fl; |
2056 | struct rt6_info *rt; | 2057 | int err, iif = 0; |
2057 | |||
2058 | skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); | ||
2059 | if (skb == NULL) | ||
2060 | goto out; | ||
2061 | 2058 | ||
2062 | /* Reserve room for dummy headers, this skb can pass | 2059 | err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_ipv6_policy); |
2063 | through good chunk of routing engine. | 2060 | if (err < 0) |
2064 | */ | 2061 | goto errout; |
2065 | skb->mac.raw = skb->data; | ||
2066 | skb_reserve(skb, MAX_HEADER + sizeof(struct ipv6hdr)); | ||
2067 | 2062 | ||
2063 | err = -EINVAL; | ||
2068 | memset(&fl, 0, sizeof(fl)); | 2064 | memset(&fl, 0, sizeof(fl)); |
2069 | if (rta[RTA_SRC-1]) | ||
2070 | ipv6_addr_copy(&fl.fl6_src, | ||
2071 | (struct in6_addr*)RTA_DATA(rta[RTA_SRC-1])); | ||
2072 | if (rta[RTA_DST-1]) | ||
2073 | ipv6_addr_copy(&fl.fl6_dst, | ||
2074 | (struct in6_addr*)RTA_DATA(rta[RTA_DST-1])); | ||
2075 | 2065 | ||
2076 | if (rta[RTA_IIF-1]) | 2066 | if (tb[RTA_SRC]) { |
2077 | memcpy(&iif, RTA_DATA(rta[RTA_IIF-1]), sizeof(int)); | 2067 | if (nla_len(tb[RTA_SRC]) < sizeof(struct in6_addr)) |
2068 | goto errout; | ||
2069 | |||
2070 | ipv6_addr_copy(&fl.fl6_src, nla_data(tb[RTA_SRC])); | ||
2071 | } | ||
2072 | |||
2073 | if (tb[RTA_DST]) { | ||
2074 | if (nla_len(tb[RTA_DST]) < sizeof(struct in6_addr)) | ||
2075 | goto errout; | ||
2076 | |||
2077 | ipv6_addr_copy(&fl.fl6_dst, nla_data(tb[RTA_DST])); | ||
2078 | } | ||
2079 | |||
2080 | if (tb[RTA_IIF]) | ||
2081 | iif = nla_get_u32(tb[RTA_IIF]); | ||
2082 | |||
2083 | if (tb[RTA_OIF]) | ||
2084 | fl.oif = nla_get_u32(tb[RTA_OIF]); | ||
2078 | 2085 | ||
2079 | if (iif) { | 2086 | if (iif) { |
2080 | struct net_device *dev; | 2087 | struct net_device *dev; |
2081 | dev = __dev_get_by_index(iif); | 2088 | dev = __dev_get_by_index(iif); |
2082 | if (!dev) { | 2089 | if (!dev) { |
2083 | err = -ENODEV; | 2090 | err = -ENODEV; |
2084 | goto out_free; | 2091 | goto errout; |
2085 | } | 2092 | } |
2086 | } | 2093 | } |
2087 | 2094 | ||
2088 | fl.oif = 0; | 2095 | skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); |
2089 | if (rta[RTA_OIF-1]) | 2096 | if (skb == NULL) { |
2090 | memcpy(&fl.oif, RTA_DATA(rta[RTA_OIF-1]), sizeof(int)); | 2097 | err = -ENOBUFS; |
2098 | goto errout; | ||
2099 | } | ||
2091 | 2100 | ||
2092 | rt = (struct rt6_info*)ip6_route_output(NULL, &fl); | 2101 | /* Reserve room for dummy headers, this skb can pass |
2102 | through good chunk of routing engine. | ||
2103 | */ | ||
2104 | skb->mac.raw = skb->data; | ||
2105 | skb_reserve(skb, MAX_HEADER + sizeof(struct ipv6hdr)); | ||
2093 | 2106 | ||
2107 | rt = (struct rt6_info*) ip6_route_output(NULL, &fl); | ||
2094 | skb->dst = &rt->u.dst; | 2108 | skb->dst = &rt->u.dst; |
2095 | 2109 | ||
2096 | NETLINK_CB(skb).dst_pid = NETLINK_CB(in_skb).pid; | 2110 | err = rt6_fill_node(skb, rt, &fl.fl6_dst, &fl.fl6_src, iif, |
2097 | err = rt6_fill_node(skb, rt, | ||
2098 | &fl.fl6_dst, &fl.fl6_src, | ||
2099 | iif, | ||
2100 | RTM_NEWROUTE, NETLINK_CB(in_skb).pid, | 2111 | RTM_NEWROUTE, NETLINK_CB(in_skb).pid, |
2101 | nlh->nlmsg_seq, 0, 0); | 2112 | nlh->nlmsg_seq, 0, 0); |
2102 | if (err < 0) { | 2113 | if (err < 0) { |
2103 | err = -EMSGSIZE; | 2114 | kfree_skb(skb); |
2104 | goto out_free; | 2115 | goto errout; |
2105 | } | 2116 | } |
2106 | 2117 | ||
2107 | err = rtnl_unicast(skb, NETLINK_CB(in_skb).pid); | 2118 | err = rtnl_unicast(skb, NETLINK_CB(in_skb).pid); |
2108 | out: | 2119 | errout: |
2109 | return err; | 2120 | return err; |
2110 | out_free: | ||
2111 | kfree_skb(skb); | ||
2112 | goto out; | ||
2113 | } | 2121 | } |
2114 | 2122 | ||
2115 | void inet6_rt_notify(int event, struct rt6_info *rt, struct nl_info *info) | 2123 | void inet6_rt_notify(int event, struct rt6_info *rt, struct nl_info *info) |