summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorbluhm <bluhm@openbsd.org>2010-11-16 19:39:17 +0000
committerbluhm <bluhm@openbsd.org>2010-11-16 19:39:17 +0000
commitbd3cc611e9adaf3f78c95b926324307d46eb4f93 (patch)
treee8e761d659e4cce88956fbe255df623653f70568
parentattach FeiXun products. (diff)
downloadwireguard-openbsd-bd3cc611e9adaf3f78c95b926324307d46eb4f93.tar.xz
wireguard-openbsd-bd3cc611e9adaf3f78c95b926324307d46eb4f93.zip
If the interface address referenced by a cloning route did not point
to an interface any more, the kernel crashed with a null pointer dereference. This situation could be created by a strange sequence of route and ifconfig commands. Now when a cloning route references a stale interface address and rtrequest1(RTM_RESOLVE) has to create a cloned route, it does a lookup for a valid interface address with the same ip address. The new interface address and its interface are used for the new cloned route and they replace the old ones at the cloning route. ok claudio@, henning@
-rw-r--r--sys/net/route.c42
1 files changed, 37 insertions, 5 deletions
diff --git a/sys/net/route.c b/sys/net/route.c
index e2e53bd2e45..4fab3e1cccb 100644
--- a/sys/net/route.c
+++ b/sys/net/route.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: route.c,v 1.127 2010/08/25 14:07:24 claudio Exp $ */
+/* $OpenBSD: route.c,v 1.128 2010/11/16 19:39:17 bluhm Exp $ */
/* $NetBSD: route.c,v 1.14 1996/02/13 22:00:46 christos Exp $ */
/*
@@ -792,7 +792,20 @@ rtrequest1(int req, struct rt_addrinfo *info, u_int8_t prio,
senderr(EINVAL);
if ((rt->rt_flags & RTF_CLONING) == 0)
senderr(EINVAL);
- ifa = rt->rt_ifa;
+ if (rt->rt_ifa->ifa_ifp) {
+ info->rti_ifa = rt->rt_ifa;
+ } else {
+ /*
+ * The interface address at the cloning route
+ * is not longer referenced by an interface.
+ * Try to find a similar active address and use
+ * it for the cloned route. The cloning route
+ * will get the new address and interface later.
+ */
+ info->rti_ifa = NULL;
+ info->rti_info[RTAX_IFA] = rt->rt_ifa->ifa_addr;
+ }
+ info->rti_ifp = rt->rt_ifp;
info->rti_flags = rt->rt_flags & ~(RTF_CLONING | RTF_STATIC);
info->rti_flags |= RTF_CLONED;
info->rti_info[RTAX_GATEWAY] = rt->rt_gateway;
@@ -800,13 +813,12 @@ rtrequest1(int req, struct rt_addrinfo *info, u_int8_t prio,
info->rti_flags |= RTF_HOST;
info->rti_info[RTAX_LABEL] =
rtlabel_id2sa(rt->rt_labelid, &sa_rl2);
- goto makeroute;
+ /* FALLTHROUGH */
case RTM_ADD:
- if (info->rti_ifa == 0 && (error = rt_getifa(info, tableid)))
+ if (info->rti_ifa == NULL && (error = rt_getifa(info, tableid)))
senderr(error);
ifa = info->rti_ifa;
-makeroute:
rt = pool_get(&rtentry_pool, PR_NOWAIT | PR_ZERO);
if (rt == NULL)
senderr(ENOBUFS);
@@ -899,6 +911,26 @@ makeroute:
rt->rt_ifp = ifa->ifa_ifp;
if (req == RTM_RESOLVE) {
/*
+ * If the ifa of the cloning route was stale, a
+ * successful lookup for an ifa with the same address
+ * has been made. Use this ifa also for the cloning
+ * route.
+ */
+ if ((*ret_nrt)->rt_ifa->ifa_ifp == NULL) {
+ printf("rtrequest1 RTM_RESOLVE: wrong ifa (%p) "
+ "was (%p)\n", ifa, (*ret_nrt)->rt_ifa);
+ if ((*ret_nrt)->rt_ifa->ifa_rtrequest)
+ (*ret_nrt)->rt_ifa->ifa_rtrequest(
+ RTM_DELETE, *ret_nrt, NULL);
+ IFAFREE((*ret_nrt)->rt_ifa);
+ (*ret_nrt)->rt_ifa = ifa;
+ (*ret_nrt)->rt_ifp = ifa->ifa_ifp;
+ ifa->ifa_refcnt++;
+ if (ifa->ifa_rtrequest)
+ ifa->ifa_rtrequest(RTM_ADD, *ret_nrt,
+ NULL);
+ }
+ /*
* Copy both metrics and a back pointer to the cloned
* route's parent.
*/