Commit d889ce3b authored by Thomas Graf's avatar Thomas Graf Committed by David S. Miller

[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: default avatarThomas Graf <tgraf@suug.ch>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent be403ea1
...@@ -216,6 +216,7 @@ extern void fib_select_default(const struct flowi *flp, struct fib_result *res); ...@@ -216,6 +216,7 @@ extern void fib_select_default(const struct flowi *flp, struct fib_result *res);
#endif /* CONFIG_IP_MULTIPLE_TABLES */ #endif /* CONFIG_IP_MULTIPLE_TABLES */
/* Exported by fib_frontend.c */ /* Exported by fib_frontend.c */
extern struct nla_policy rtm_ipv4_policy[];
extern void ip_fib_init(void); extern void ip_fib_init(void);
extern int inet_rtm_delroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg); extern int inet_rtm_delroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg);
extern int inet_rtm_newroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg); extern int inet_rtm_newroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg);
......
...@@ -453,7 +453,7 @@ int ip_rt_ioctl(unsigned int cmd, void *arg) ...@@ -453,7 +453,7 @@ int ip_rt_ioctl(unsigned int cmd, void *arg)
#endif #endif
static struct nla_policy rtm_ipv4_policy[RTA_MAX+1] __read_mostly = { struct nla_policy rtm_ipv4_policy[RTA_MAX+1] __read_mostly = {
[RTA_DST] = { .type = NLA_U32 }, [RTA_DST] = { .type = NLA_U32 },
[RTA_SRC] = { .type = NLA_U32 }, [RTA_SRC] = { .type = NLA_U32 },
[RTA_IIF] = { .type = NLA_U32 }, [RTA_IIF] = { .type = NLA_U32 },
......
...@@ -2737,18 +2737,24 @@ static int rt_fill_info(struct sk_buff *skb, u32 pid, u32 seq, int event, ...@@ -2737,18 +2737,24 @@ static int rt_fill_info(struct sk_buff *skb, u32 pid, u32 seq, int event,
int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void *arg) int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void *arg)
{ {
struct rtattr **rta = arg; struct rtmsg *rtm;
struct rtmsg *rtm = NLMSG_DATA(nlh); struct nlattr *tb[RTA_MAX+1];
struct rtable *rt = NULL; struct rtable *rt = NULL;
u32 dst = 0; u32 dst, src, iif;
u32 src = 0; int err;
int iif = 0;
int err = -ENOBUFS;
struct sk_buff *skb; struct sk_buff *skb;
err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_ipv4_policy);
if (err < 0)
goto errout;
rtm = nlmsg_data(nlh);
skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
if (!skb) if (skb == NULL) {
goto out; err = -ENOBUFS;
goto errout;
}
/* Reserve room for dummy headers, this skb can pass /* Reserve room for dummy headers, this skb can pass
through good chunk of routing engine. 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,61 +2765,61 @@ int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void *arg)
skb->nh.iph->protocol = IPPROTO_ICMP; skb->nh.iph->protocol = IPPROTO_ICMP;
skb_reserve(skb, MAX_HEADER + sizeof(struct iphdr)); skb_reserve(skb, MAX_HEADER + sizeof(struct iphdr));
if (rta[RTA_SRC - 1]) src = tb[RTA_SRC] ? nla_get_u32(tb[RTA_SRC]) : 0;
memcpy(&src, RTA_DATA(rta[RTA_SRC - 1]), 4); dst = tb[RTA_DST] ? nla_get_u32(tb[RTA_DST]) : 0;
if (rta[RTA_DST - 1]) iif = tb[RTA_IIF] ? nla_get_u32(tb[RTA_IIF]) : 0;
memcpy(&dst, RTA_DATA(rta[RTA_DST - 1]), 4);
if (rta[RTA_IIF - 1])
memcpy(&iif, RTA_DATA(rta[RTA_IIF - 1]), sizeof(int));
if (iif) { if (iif) {
struct net_device *dev = __dev_get_by_index(iif); struct net_device *dev;
err = -ENODEV;
if (!dev) dev = __dev_get_by_index(iif);
goto out_free; if (dev == NULL) {
err = -ENODEV;
goto errout_free;
}
skb->protocol = htons(ETH_P_IP); skb->protocol = htons(ETH_P_IP);
skb->dev = dev; skb->dev = dev;
local_bh_disable(); local_bh_disable();
err = ip_route_input(skb, dst, src, rtm->rtm_tos, dev); err = ip_route_input(skb, dst, src, rtm->rtm_tos, dev);
local_bh_enable(); local_bh_enable();
rt = (struct rtable*)skb->dst;
if (!err && rt->u.dst.error) rt = (struct rtable*) skb->dst;
if (err == 0 && rt->u.dst.error)
err = -rt->u.dst.error; err = -rt->u.dst.error;
} else { } else {
struct flowi fl = { .nl_u = { .ip4_u = { .daddr = dst, struct flowi fl = {
.saddr = src, .nl_u = {
.tos = rtm->rtm_tos } } }; .ip4_u = {
int oif = 0; .daddr = dst,
if (rta[RTA_OIF - 1]) .saddr = src,
memcpy(&oif, RTA_DATA(rta[RTA_OIF - 1]), sizeof(int)); .tos = rtm->rtm_tos,
fl.oif = oif; },
},
.oif = tb[RTA_OIF] ? nla_get_u32(tb[RTA_OIF]) : 0,
};
err = ip_route_output_key(&rt, &fl); err = ip_route_output_key(&rt, &fl);
} }
if (err) if (err)
goto out_free; goto errout_free;
skb->dst = &rt->u.dst; skb->dst = &rt->u.dst;
if (rtm->rtm_flags & RTM_F_NOTIFY) if (rtm->rtm_flags & RTM_F_NOTIFY)
rt->rt_flags |= RTCF_NOTIFY; rt->rt_flags |= RTCF_NOTIFY;
NETLINK_CB(skb).dst_pid = NETLINK_CB(in_skb).pid;
err = rt_fill_info(skb, NETLINK_CB(in_skb).pid, nlh->nlmsg_seq, err = rt_fill_info(skb, NETLINK_CB(in_skb).pid, nlh->nlmsg_seq,
RTM_NEWROUTE, 0, 0); RTM_NEWROUTE, 0, 0);
if (!err) if (err <= 0)
goto out_free; goto errout_free;
if (err < 0) {
err = -EMSGSIZE;
goto out_free;
}
err = rtnl_unicast(skb, NETLINK_CB(in_skb).pid); err = rtnl_unicast(skb, NETLINK_CB(in_skb).pid);
out: errout:
return err; return err;
out_free: errout_free:
kfree_skb(skb); kfree_skb(skb);
goto out; goto errout;
} }
int ip_rt_dump(struct sk_buff *skb, struct netlink_callback *cb) int ip_rt_dump(struct sk_buff *skb, struct netlink_callback *cb)
......
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