[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>
This commit is contained in:
committed by
David S. Miller
parent
be403ea185
commit
d889ce3b29
@@ -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)
|
|||||||
|
|
||||||
#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 @@ nla_put_failure:
|
|||||||
|
|
||||||
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)
|
|||||||
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;
|
||||||
|
|
||||||
|
dev = __dev_get_by_index(iif);
|
||||||
|
if (dev == NULL) {
|
||||||
err = -ENODEV;
|
err = -ENODEV;
|
||||||
if (!dev)
|
goto errout_free;
|
||||||
goto out_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;
|
rt = (struct rtable*) skb->dst;
|
||||||
if (!err && rt->u.dst.error)
|
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 = {
|
||||||
|
.nl_u = {
|
||||||
|
.ip4_u = {
|
||||||
|
.daddr = dst,
|
||||||
.saddr = src,
|
.saddr = src,
|
||||||
.tos = rtm->rtm_tos } } };
|
.tos = rtm->rtm_tos,
|
||||||
int oif = 0;
|
},
|
||||||
if (rta[RTA_OIF - 1])
|
},
|
||||||
memcpy(&oif, RTA_DATA(rta[RTA_OIF - 1]), sizeof(int));
|
.oif = tb[RTA_OIF] ? nla_get_u32(tb[RTA_OIF]) : 0,
|
||||||
fl.oif = oif;
|
};
|
||||||
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)
|
||||||
|
Reference in New Issue
Block a user